1use crate::traits::{Builder, Entity, Geometry, GmshExport, GmshImport, Grid, Point};
4use itertools::izip;
5use ndelement::types::ReferenceCellType;
6use num::Zero;
7use num::traits::FromBytes;
8use std::collections::HashMap;
9use std::fs::File;
10use std::io::{BufRead, BufReader, Read};
11use std::str::FromStr;
12
13fn get_permutation_to_gmsh(cell_type: ReferenceCellType, degree: usize) -> Vec<usize> {
14 match cell_type {
15 ReferenceCellType::Triangle => match degree {
16 1 => vec![0, 1, 2],
17 2 => vec![0, 1, 2, 5, 3, 4],
18 3 => vec![0, 1, 2, 7, 8, 3, 4, 6, 5, 9],
19 4 => vec![0, 1, 2, 9, 10, 11, 3, 4, 5, 8, 7, 6, 12, 13, 14],
20 5 => vec![
21 0, 1, 2, 11, 12, 13, 14, 3, 4, 5, 6, 10, 9, 8, 7, 15, 16, 17, 18, 19, 20,
22 ],
23 _ => {
24 panic!("Unsupported degree");
25 }
26 },
27 ReferenceCellType::Quadrilateral => match degree {
28 1 => vec![0, 1, 3, 2],
29 2 => vec![0, 1, 3, 2, 4, 6, 7, 5, 8],
30 _ => {
31 panic!("Unsupported degree");
32 }
33 },
34 ReferenceCellType::Tetrahedron => match degree {
35 1 => vec![0, 1, 2, 3],
36 _ => {
37 panic!("Unsupported degree");
38 }
39 },
40 ReferenceCellType::Hexahedron => match degree {
41 1 => vec![0, 1, 3, 2, 4, 5, 7, 6],
42 _ => {
43 panic!("Unsupported degree");
44 }
45 },
46 _ => {
47 panic!("Unsupported cell type.");
48 }
49 }
50}
51
52fn get_gmsh_cell(cell_type: ReferenceCellType, degree: usize) -> usize {
53 match cell_type {
54 ReferenceCellType::Triangle => match degree {
55 1 => 2,
56 2 => 9,
57 3 => 21,
58 4 => 23,
59 5 => 25,
60 _ => {
61 panic!("Unsupported degree");
62 }
63 },
64 ReferenceCellType::Quadrilateral => match degree {
65 1 => 3,
66 2 => 10,
67 _ => {
68 panic!("Unsupported degree");
69 }
70 },
71 ReferenceCellType::Tetrahedron => match degree {
72 1 => 4,
73 _ => {
74 panic!("Unsupported degree");
75 }
76 },
77 ReferenceCellType::Hexahedron => match degree {
78 1 => 5,
79 _ => {
80 panic!("Unsupported degree");
81 }
82 },
83 _ => {
84 panic!("Unsupported cell type.");
85 }
86 }
87}
88
89fn interpret_gmsh_cell(gmsh_cell: usize) -> (ReferenceCellType, usize) {
90 match gmsh_cell {
91 2 => (ReferenceCellType::Triangle, 1),
92 9 => (ReferenceCellType::Triangle, 2),
93 21 => (ReferenceCellType::Triangle, 3),
94 23 => (ReferenceCellType::Triangle, 4),
95 25 => (ReferenceCellType::Triangle, 5),
96 3 => (ReferenceCellType::Quadrilateral, 1),
97 10 => (ReferenceCellType::Quadrilateral, 2),
98 4 => (ReferenceCellType::Tetrahedron, 1),
99 5 => (ReferenceCellType::Hexahedron, 1),
100 _ => {
101 panic!("Unsupported cell type.");
102 }
103 }
104}
105
106fn parse<T: FromBytes>(data: &[u8], gmsh_data_size: usize, is_le: bool) -> T
108where
109 <T as FromBytes>::Bytes: Sized,
110{
111 let mut buf: T::Bytes = unsafe { std::mem::zeroed() };
112 let target_data_size = std::mem::size_of::<T::Bytes>();
113 let buf_bytes: &mut [u8] = unsafe {
114 std::slice::from_raw_parts_mut((&mut buf as *mut _) as *mut u8, target_data_size)
115 };
116
117 if is_le {
118 buf_bytes[..gmsh_data_size].copy_from_slice(data);
119 T::from_le_bytes(&buf)
120 } else {
121 buf_bytes[target_data_size - gmsh_data_size..].copy_from_slice(data);
122 T::from_be_bytes(&buf)
123 }
124}
125
126impl<G: Grid<EntityDescriptor = ReferenceCellType>> GmshExport for G {
127 fn to_gmsh_string(&self) -> String {
128 let tdim = self.topology_dim();
129 let gdim = self.geometry_dim();
130
131 let mut points = HashMap::new();
132 for cell_type in self.cell_types() {
133 for cell in self.entity_iter(*cell_type) {
134 for point in cell.geometry().points() {
135 let mut p = vec![G::T::zero(); gdim];
136 point.coords(&mut p);
137 points.insert(point.index(), p);
138 }
139 }
140 }
141 let mut points = points.iter().collect::<Vec<_>>();
142 points.sort_by(|i, j| i.0.cmp(j.0));
143 let node_count = points.len();
144
145 let mut gmsh_s = String::from("");
146 gmsh_s.push_str("$MeshFormat\n");
147 gmsh_s.push_str("4.1 0 8\n");
148 gmsh_s.push_str("$EndMeshFormat\n");
149 gmsh_s.push_str("$Nodes\n");
150 gmsh_s.push_str(&format!("1 {node_count} 1 {node_count}\n"));
151 gmsh_s.push_str(&format!("{tdim} 1 0 {node_count}\n"));
152 for (i, _) in &points {
153 gmsh_s.push_str(&format!("{}\n", *i + 1));
154 }
155 for (_, coords) in &points {
156 for n in 0..3 {
157 if n != 0 {
158 gmsh_s.push(' ');
159 }
160 gmsh_s.push_str(&format!(
161 "{}",
162 if let Some(c) = coords.get(n) {
163 *c
164 } else {
165 G::T::zero()
166 }
167 ));
168 }
169 gmsh_s.push('\n');
170 }
171 gmsh_s.push_str("$EndNodes\n");
172 gmsh_s.push_str("$Elements\n");
173
174 let cell_count = self
175 .entity_types(tdim)
176 .iter()
177 .map(|t| self.entity_count(*t))
178 .sum::<usize>();
179
180 let mut elements = vec![];
181 let mut cells_by_element = vec![];
182 for t in self.cell_types() {
183 for (index, cell) in self.entity_iter(*t).enumerate() {
184 let element = (cell.entity_type(), cell.geometry().degree());
185 if !elements.contains(&element) {
186 elements.push(element);
187 cells_by_element.push(vec![]);
188 }
189 cells_by_element[elements.iter().position(|i| *i == element).unwrap()].push(index);
190 }
191 }
192
193 gmsh_s.push_str(&format!("{} {cell_count} 1 {cell_count}\n", elements.len()));
194
195 let mut next_index = 1;
196 for ((cell_type, degree), cells) in izip!(elements, cells_by_element) {
197 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
198
199 gmsh_s.push_str(&format!(
200 "{tdim} 1 {} {}\n",
201 get_gmsh_cell(cell_type, degree),
202 cells.len()
203 ));
204
205 for index in cells.iter() {
206 gmsh_s.push_str(&format!("{}", {
207 let idx = next_index;
208 next_index += 1;
209 idx
210 },));
211 let entity = self.entity(cell_type, *index).unwrap();
212 let point_indices = entity
213 .geometry()
214 .points()
215 .map(|i| i.index())
216 .collect::<Vec<_>>();
217 for j in &gmsh_perm {
218 gmsh_s.push_str(&format!(" {}", point_indices[*j] + 1));
219 }
220 gmsh_s.push('\n');
221 }
222 }
223
224 gmsh_s.push_str("$EndElements\n");
225
226 gmsh_s
227 }
228}
229
230fn gmsh_section(s: &str, section: &str) -> String {
232 let a = s.split(&format!("${section}\n")).collect::<Vec<_>>();
233 if a.len() <= 1 {
234 panic!("Section not found: {section}");
235 }
236 String::from(a[1].split(&format!("\n$End{section}")).collect::<Vec<_>>()[0])
237}
238
239impl<T, B> GmshImport for B
240where
241 T: FromStr + FromBytes + std::fmt::Debug,
242 <T as FromBytes>::Bytes: Sized,
243 B: Builder<T = T, EntityDescriptor = ReferenceCellType>,
244{
245 fn import_from_gmsh_v1(&mut self, s: String) {
246 let nodes = gmsh_section(&s, "Nodes");
248 let mut nodes = nodes.lines();
249
250 let Some(num_nodes) = nodes.next() else {
251 panic!("Could not read num nodes");
252 };
253 let num_nodes = num_nodes
254 .parse::<usize>()
255 .expect("Could not parse num nodes");
256
257 for _ in 0..num_nodes {
258 let Some(line) = nodes.next() else {
259 panic!("Unable to read node line");
260 };
261 let line = line.split(" ").collect::<Vec<&str>>();
262
263 let (tag, coords) = line.split_at(1);
264 let tag = tag[0].parse::<usize>().expect("Could not parse node tag");
265 let coords = coords
266 .iter()
267 .map(|c| {
268 if let Ok(d) = T::from_str(c) {
269 d
270 } else {
271 panic!("Could not parse coords")
272 }
273 })
274 .collect::<Vec<_>>();
275
276 self.add_point(tag, &coords[..self.gdim()]);
277 }
278
279 let elements = gmsh_section(&s, "Elements");
281 let mut elements = elements.lines();
282
283 let Some(num_elements) = elements.next() else {
284 panic!("Could not read num nodes");
285 };
286 let num_elements = num_elements
287 .parse::<usize>()
288 .expect("Could not parse num nodes");
289
290 for _ in 0..num_elements {
291 let Some(line) = elements.next() else {
292 panic!("Unable to read element line");
293 };
294 let line = line.split(" ").collect::<Vec<&str>>();
295
296 let (a, node_tags) = line.split_at(5);
297 let [tag, element_type, ..] = a
298 .iter()
299 .map(|i| {
300 i.parse::<usize>()
301 .expect("Could not parse element tag and type")
302 })
303 .collect::<Vec<_>>()[..]
304 else {
305 panic!("Unrecognised format");
306 };
307
308 let node_tags = node_tags
309 .iter()
310 .map(|i| {
311 i.parse::<usize>()
312 .expect("Could not parse nodes for element")
313 })
314 .collect::<Vec<_>>();
315 let (cell_type, degree) = interpret_gmsh_cell(element_type);
316 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
317
318 let mut cell = vec![0; node_tags.len()];
319 for (i, j) in gmsh_perm.iter().enumerate() {
320 cell[*j] = node_tags[i];
321 }
322
323 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
324 }
325 }
326
327 fn import_from_gmsh_string_v2(&mut self, s: String) {
328 let nodes = gmsh_section(&s, "Nodes");
330 let mut nodes = nodes.lines();
331
332 let Some(num_nodes) = nodes.next() else {
333 panic!("Could not read num nodes");
334 };
335 let num_nodes = num_nodes
336 .parse::<usize>()
337 .expect("Could not parse num nodes");
338
339 for _ in 0..num_nodes {
340 let Some(line) = nodes.next() else {
341 panic!("Unable to read node line");
342 };
343 let line = line.split(" ").collect::<Vec<&str>>();
344
345 let (tag, coords) = line.split_at(1);
346 let tag = tag[0].parse::<usize>().expect("Could not parse node tag");
347 let coords = coords
348 .iter()
349 .map(|c| {
350 if let Ok(d) = T::from_str(c) {
351 d
352 } else {
353 panic!("Could not parse coords")
354 }
355 })
356 .collect::<Vec<_>>();
357
358 self.add_point(tag, &coords[..self.gdim()]);
359 }
360
361 let elements = gmsh_section(&s, "Elements");
363 let mut elements = elements.lines();
364
365 let Some(num_elements) = elements.next() else {
366 panic!("Could not read num nodes");
367 };
368 let num_elements = num_elements
369 .parse::<usize>()
370 .expect("Could not parse num nodes");
371
372 for _ in 0..num_elements {
373 let Some(line) = elements.next() else {
374 panic!("Unable to read element line");
375 };
376 let line = line.split(" ").collect::<Vec<&str>>();
377
378 let (a, rem_line) = line.split_at(3);
379 let [tag, element_type, num_tags] = a
380 .iter()
381 .map(|i| {
382 i.parse::<usize>()
383 .expect("Could not parse element tag and type")
384 })
385 .collect::<Vec<_>>()[..]
386 else {
387 panic!("Unrecognised format");
388 };
389
390 let (_, node_tags) = rem_line.split_at(num_tags);
391 let node_tags = node_tags
392 .iter()
393 .map(|i| {
394 i.parse::<usize>()
395 .expect("Could not parse nodes for element")
396 })
397 .collect::<Vec<_>>();
398 let (cell_type, degree) = interpret_gmsh_cell(element_type);
399 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
400
401 let mut cell = vec![0; node_tags.len()];
402 for (i, j) in gmsh_perm.iter().enumerate() {
403 cell[*j] = node_tags[i];
404 }
405
406 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
407 }
408 }
409
410 fn import_from_gmsh_binary_v2(
411 &mut self,
412 mut reader: BufReader<File>,
413 data_size: usize,
414 is_le: bool,
415 ) {
416 let mut line = String::new();
417 let mut buf = Vec::new();
418
419 macro_rules! read_exact {
420 ($size: expr, $msg: expr) => {{
421 buf.resize($size, 0);
422 reader.read_exact(&mut buf).expect($msg);
423 }};
424 }
425
426 const GMSH_INT_SIZE: usize = 4;
427
428 loop {
429 let Ok(num_bytes) = reader.read_line(&mut line) else {
430 continue;
431 };
432
433 if num_bytes == 0 {
435 break;
436 }
437
438 match line.trim() {
439 "$Nodes" => {
441 line.clear();
442 let Ok(_) = reader.read_line(&mut line) else {
443 panic!("Unable to read num nodes");
444 };
445 let num_nodes = line
446 .trim()
447 .parse::<usize>()
448 .expect("Could not parse num nodes");
449
450 for _ in 0..num_nodes {
451 read_exact!(GMSH_INT_SIZE, "Unable to read node tag");
452 let tag = parse::<usize>(&buf, GMSH_INT_SIZE, is_le);
453
454 read_exact!(3 * data_size, "Unable to read node coords");
455 let coords = buf
456 .chunks(data_size)
457 .map(|i| parse::<T>(i, data_size, is_le))
458 .collect::<Vec<_>>();
459
460 self.add_point(tag, &coords[..self.gdim()]);
461 }
462
463 line.clear();
464 }
465 "$Elements" => {
467 line.clear();
468 let Ok(_) = reader.read_line(&mut line) else {
469 panic!("Unable to read num elements")
470 };
471 let num_elements = line
472 .trim()
473 .parse::<usize>()
474 .expect("Could not parse num elements");
475
476 for _ in 0..num_elements {
477 read_exact!(3 * GMSH_INT_SIZE, "Unable to element tag and type");
478 let [elm_type, _num_elm_follow, num_tags] = buf
479 .chunks(GMSH_INT_SIZE)
480 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
481 .collect::<Vec<_>>()[..]
482 else {
483 panic!("Could not parse element tag and type")
484 };
485
486 read_exact!(GMSH_INT_SIZE, "Unable to read num tags");
487 let tag = parse::<usize>(&buf, 4, is_le);
488
489 read_exact!(num_tags * GMSH_INT_SIZE, "Unable to read element tags");
491
492 let (cell_type, degree) = interpret_gmsh_cell(elm_type);
493 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
494
495 read_exact!(
496 gmsh_perm.len() * GMSH_INT_SIZE,
497 "Unable to read element node tags"
498 );
499 let node_tags = buf
500 .chunks(GMSH_INT_SIZE)
501 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
502 .collect::<Vec<_>>();
503
504 let mut cell = vec![0; node_tags.len()];
505 for (i, j) in gmsh_perm.iter().enumerate() {
506 cell[*j] = node_tags[i];
507 }
508
509 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
510 }
511 line.clear();
512 }
513 _ => {
514 line.clear();
515 }
516 }
517 }
518 }
519
520 fn import_from_gmsh_string_v4(&mut self, s: String) {
521 let nodes = gmsh_section(&s, "Nodes");
523 let nodes = nodes.lines().collect::<Vec<_>>();
524
525 let [num_entity_blocks, _num_nodes, _min_node_tag, _max_node_tag] = nodes[0]
526 .trim()
527 .split(" ")
528 .map(|i| i.parse::<usize>().unwrap())
529 .collect::<Vec<_>>()[..]
530 else {
531 panic!("Unrecognised gmsh format for node blocks");
532 };
533
534 let mut line_n = 1;
535 for _ in 0..num_entity_blocks {
536 let [_entity_dim, _entity_tag, parametric, num_nodes_in_block] = nodes[line_n]
537 .trim()
538 .split(" ")
539 .map(|i| i.parse::<usize>().unwrap())
540 .collect::<Vec<_>>()[..]
541 else {
542 panic!("Unrecognised gmsh format for nodes");
543 };
544 if parametric == 1 {
545 unimplemented!("Parametric nodes currently not supported")
546 }
547 line_n += 1;
548 let tags = &nodes[line_n..line_n + num_nodes_in_block];
549 let coords = &nodes[line_n + num_nodes_in_block..line_n + 2 * num_nodes_in_block];
550 for (t, c) in izip!(tags, coords) {
551 let pt = c
552 .trim()
553 .split(" ")
554 .map(|i| {
555 if let Ok(j) = T::from_str(i) {
556 j
557 } else {
558 panic!("Could not parse coordinate");
559 }
560 })
561 .collect::<Vec<_>>();
562 self.add_point(t.parse::<usize>().unwrap(), &pt[..self.gdim()]);
563 }
564 line_n += num_nodes_in_block * 2;
565 }
566
567 let elements = gmsh_section(&s, "Elements");
569 let elements = elements.lines().collect::<Vec<_>>();
570
571 let [
572 num_entity_blocks,
573 _num_elements,
574 _min_element_tag,
575 _max_element_tag,
576 ] = elements[0]
577 .trim()
578 .split(" ")
579 .map(|i| i.parse::<usize>().unwrap())
580 .collect::<Vec<_>>()[..]
581 else {
582 panic!("Unrecognised gmsh format");
583 };
584
585 let mut line_n = 1;
586 for _ in 0..num_entity_blocks {
587 let [
588 _entity_dim,
589 _entity_tag,
590 element_type,
591 num_elements_in_block,
592 ] = elements[line_n]
593 .trim()
594 .split(" ")
595 .map(|i| i.parse::<usize>().unwrap())
596 .collect::<Vec<_>>()[..]
597 else {
598 panic!("Unrecognised gmsh format");
599 };
600 let (cell_type, degree) = interpret_gmsh_cell(element_type);
601 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
602
603 line_n += 1;
604 for line in &elements[line_n..line_n + num_elements_in_block] {
605 let line = line
606 .trim()
607 .split(" ")
608 .map(|i| i.parse::<usize>().unwrap())
609 .collect::<Vec<_>>();
610 let mut cell = vec![0; line.len() - 1];
611 for (i, j) in gmsh_perm.iter().enumerate() {
612 cell[*j] = line[i + 1];
613 }
614 self.add_cell_from_nodes_and_type(line[0], &cell, cell_type, degree);
615 }
616
617 line_n += num_elements_in_block;
618 }
619 }
620
621 fn import_from_gmsh_binary_v4(
622 &mut self,
623 mut reader: BufReader<File>,
624 data_size: usize,
625 is_le: bool,
626 ) {
627 let mut line = String::new();
628 let mut buf = Vec::new();
629
630 macro_rules! read_exact {
631 ($size: expr, $msg: expr) => {{
632 buf.resize($size, 0);
633 reader.read_exact(&mut buf).expect($msg);
634 }};
635 }
636
637 const GMSH_INT_SIZE: usize = 4;
638
639 loop {
640 let Ok(num_bytes) = reader.read_line(&mut line) else {
641 continue;
642 };
643
644 if num_bytes == 0 {
646 break;
647 }
648
649 match line.trim() {
650 "$Nodes" => {
652 read_exact!(4 * data_size, "Unable to read node section info");
653 let [num_entity_blocks, _num_nodes, _min_node_tag, _max_node_tag] = buf
654 .chunks(data_size)
655 .map(|i| parse::<usize>(i, data_size, is_le))
656 .collect::<Vec<_>>()[..]
657 else {
658 panic!("Could not parse node section info")
659 };
660
661 for _ in 0..num_entity_blocks {
662 read_exact!(3 * GMSH_INT_SIZE, "Unable to read node entity block info");
663 let [_entity_dim, _entity_tag, parametric] = buf
664 .chunks(GMSH_INT_SIZE)
665 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
666 .collect::<Vec<_>>()[..]
667 else {
668 panic!("Could not parse node entity block info")
669 };
670
671 if parametric == 1 {
672 unimplemented!("Parametric nodes currently not supported")
673 }
674
675 read_exact!(data_size, "Unable to read num nodes in block");
676 let num_nodes_in_block = parse::<usize>(&buf, data_size, is_le);
677
678 read_exact!(num_nodes_in_block * data_size, "Unable to read node tags");
679 let tags = buf
680 .chunks(data_size)
681 .map(|i| parse::<usize>(i, data_size, is_le))
682 .collect::<Vec<_>>();
683
684 read_exact!(
685 3 * num_nodes_in_block * data_size,
686 "Unable to read node coords"
687 );
688 let coords = buf
689 .chunks(3 * data_size)
690 .map(|i| {
691 i.chunks(data_size)
692 .map(|j| parse::<T>(j, data_size, is_le))
693 .collect::<Vec<_>>()
694 })
695 .collect::<Vec<_>>();
696
697 for (t, c) in izip!(tags, coords) {
698 self.add_point(t, &c[..self.gdim()]);
699 }
700 }
701
702 line.clear();
703 }
704 "$Elements" => {
706 read_exact!(4 * data_size, "Unable to read element section info");
707 let [
708 num_entity_blocks,
709 _num_elements,
710 _min_element_tag,
711 _max_element_tag,
712 ] = buf
713 .chunks(data_size)
714 .map(|i| parse::<usize>(i, data_size, is_le))
715 .collect::<Vec<_>>()[..]
716 else {
717 panic!("Could not parse element section info")
718 };
719
720 for _ in 0..num_entity_blocks {
721 read_exact!(
722 3 * GMSH_INT_SIZE,
723 "Unable to read element entity block info"
724 );
725 let [_entity_dim, _entity_tag, element_type] = buf
726 .chunks(GMSH_INT_SIZE)
727 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
728 .collect::<Vec<_>>()[..]
729 else {
730 panic!("Could not parse element entity block info")
731 };
732
733 read_exact!(data_size, "Unable to read num elements in block");
734 let num_elements_in_block = parse::<usize>(&buf, data_size, is_le);
735
736 let (cell_type, degree) = interpret_gmsh_cell(element_type);
737 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
738
739 for _ in 0..num_elements_in_block {
740 read_exact!(data_size, "Unable to read element tag");
741 let tag = parse::<usize>(&buf, data_size, is_le);
742
743 read_exact!(data_size * gmsh_perm.len(), "Unable to read node tags");
744 let node_tags = buf
745 .chunks(data_size)
746 .map(|i| parse::<usize>(i, data_size, is_le))
747 .collect::<Vec<_>>();
748
749 let mut cell = vec![0; node_tags.len()];
750 for (i, j) in gmsh_perm.iter().enumerate() {
751 cell[*j] = node_tags[i];
752 }
753
754 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
755 }
756 }
757 line.clear();
758 }
759 _ => {
760 line.clear();
761 }
762 }
763 }
764 }
765}
766
767#[cfg(test)]
768mod test {
769 use super::*;
770 use crate::{
771 MixedGridBuilder, SingleElementGridBuilder,
772 shapes::regular_sphere,
773 traits::{Builder, Topology},
774 };
775 use approx::*;
776
777 #[test]
778 fn test_regular_sphere_gmsh_io() {
779 let g = regular_sphere::<f64>(2);
780 g.export_as_gmsh("_test_io_sphere.msh");
781 }
782
783 #[test]
784 fn test_export_quads() {
785 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
786 b.add_point(0, &[0.0, 0.0, 0.0]);
787 b.add_point(1, &[1.0, 0.0, 0.0]);
788 b.add_point(2, &[0.0, 1.0, 0.0]);
789 b.add_point(3, &[1.0, 1.0, 0.0]);
790 b.add_point(4, &[0.0, 0.0, 1.0]);
791 b.add_point(5, &[1.0, 0.0, 1.0]);
792 b.add_point(6, &[0.0, 1.0, 1.0]);
793 b.add_point(7, &[1.0, 1.0, 1.0]);
794 b.add_cell(0, &[0, 2, 1, 3]);
795 b.add_cell(1, &[0, 1, 4, 5]);
796 b.add_cell(2, &[0, 4, 2, 6]);
797 b.add_cell(3, &[1, 3, 5, 7]);
798 b.add_cell(4, &[2, 6, 3, 7]);
799 b.add_cell(5, &[4, 5, 6, 7]);
800 let g = b.create_grid();
801 g.export_as_gmsh("_test_io_cube.msh");
802 }
803
804 #[test]
805 fn test_export_tetrahedra() {
806 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
807 b.add_point(0, &[0.0, 0.0, 0.0]);
808 b.add_point(1, &[1.0, 0.0, 0.0]);
809 b.add_point(2, &[0.0, 1.0, 0.0]);
810 b.add_point(3, &[1.0, 1.0, 0.0]);
811 b.add_point(4, &[0.0, 0.0, 1.0]);
812 b.add_point(5, &[1.0, 0.0, 1.0]);
813 b.add_point(6, &[0.0, 1.0, 1.0]);
814 b.add_point(7, &[1.0, 1.0, 1.0]);
815 b.add_cell(0, &[0, 1, 5, 7]);
816 b.add_cell(1, &[0, 2, 6, 7]);
817 b.add_cell(2, &[0, 4, 5, 7]);
818 b.add_cell(3, &[0, 1, 3, 7]);
819 b.add_cell(4, &[0, 2, 3, 7]);
820 b.add_cell(5, &[0, 4, 6, 7]);
821 let g = b.create_grid();
822 g.export_as_gmsh("_test_io_tetrahedra.msh");
823 }
824
825 #[test]
826 fn test_hexahedra() {
827 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Hexahedron, 1));
828 b.add_point(0, &[0.0, 0.0, 0.0]);
829 b.add_point(1, &[1.0, 0.0, 0.0]);
830 b.add_point(2, &[0.0, 1.0, 0.0]);
831 b.add_point(3, &[1.0, 1.0, 0.0]);
832 b.add_point(4, &[0.0, 0.0, 1.0]);
833 b.add_point(5, &[1.0, 0.0, 1.0]);
834 b.add_point(6, &[0.0, 1.0, 1.0]);
835 b.add_point(7, &[1.0, 1.0, 1.0]);
836 b.add_point(8, &[0.0, 0.0, 2.0]);
837 b.add_point(9, &[1.0, 0.0, 2.0]);
838 b.add_point(10, &[0.0, 1.0, 2.0]);
839 b.add_point(11, &[1.0, 1.0, 1.5]);
840 b.add_cell(1, &[0, 1, 2, 3, 4, 5, 6, 7]);
841 b.add_cell(2, &[4, 5, 6, 7, 8, 9, 10, 11]);
842 let g = b.create_grid();
843 g.export_as_gmsh("_test_io_hexahedra.msh");
844
845 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Hexahedron, 1));
846 b.import_from_gmsh("_test_io_hexahedra.msh");
847 let g2 = b.create_grid();
848
849 let mut p1 = [0.0; 3];
850 let mut p2 = [0.0; 3];
851 for (v1, v2) in izip!(
852 g.entity_iter(ReferenceCellType::Point),
853 g2.entity_iter(ReferenceCellType::Point)
854 ) {
855 for (pt1, pt2) in izip!(v1.geometry().points(), v2.geometry().points()) {
856 pt1.coords(&mut p1);
857 pt2.coords(&mut p2);
858 for (c1, c2) in izip!(&p1, &p2) {
859 assert_relative_eq!(c1, c2, epsilon = 1e-10);
860 }
861 }
862 }
863 for (h1, h2) in izip!(
864 g.entity_iter(ReferenceCellType::Hexahedron),
865 g2.entity_iter(ReferenceCellType::Hexahedron)
866 ) {
867 for (v1, v2) in izip!(
868 h1.topology().sub_entity_iter(ReferenceCellType::Point),
869 h2.topology().sub_entity_iter(ReferenceCellType::Point)
870 ) {
871 assert_eq!(v1, v2);
872 }
873 }
874 }
875
876 #[test]
877 fn test_high_order_triangles() {
878 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 5));
879 b.add_point(0, &[0.0, 0.0, 0.0]);
880 b.add_point(1, &[5.0, 0.0, 0.2]);
881 b.add_point(2, &[0.0, 5.0, 0.4]);
882 b.add_point(3, &[4.0, 1.0, -0.1]);
883 b.add_point(4, &[3.0, 2.0, 0.2]);
884 b.add_point(5, &[2.0, 3.0, -0.3]);
885 b.add_point(6, &[1.0, 4.0, -0.5]);
886 b.add_point(7, &[0.0, 1.0, 0.6]);
887 b.add_point(8, &[0.0, 2.0, 0.2]);
888 b.add_point(9, &[0.0, 3.0, 0.1]);
889 b.add_point(10, &[0.0, 4.0, -0.2]);
890 b.add_point(11, &[1.0, 0.0, -0.3]);
891 b.add_point(12, &[2.0, 0.0, -0.4]);
892 b.add_point(13, &[3.0, 0.0, -0.5]);
893 b.add_point(14, &[4.0, 0.0, -0.2]);
894 b.add_point(15, &[1.0, 1.0, 0.1]);
895 b.add_point(16, &[2.0, 1.0, 0.1]);
896 b.add_point(17, &[3.0, 1.0, 0.1]);
897 b.add_point(18, &[2.0, 1.0, 0.2]);
898 b.add_point(19, &[2.0, 2.0, 0.1]);
899 b.add_point(20, &[3.0, 1.0, 0.1]);
900 b.add_cell(
901 1,
902 &[
903 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
904 ],
905 );
906 let g = b.create_grid();
907 g.export_as_gmsh("_test_io_high_order_triangle.msh");
908
909 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 5));
910 b.import_from_gmsh("_test_io_high_order_triangle.msh");
911 let g2 = b.create_grid();
912
913 let mut p1 = [0.0; 3];
914 let mut p2 = [0.0; 3];
915 for (v1, v2) in izip!(
916 g.entity_iter(ReferenceCellType::Point),
917 g2.entity_iter(ReferenceCellType::Point)
918 ) {
919 v1.geometry().points().next().unwrap().coords(&mut p1);
920 v2.geometry().points().next().unwrap().coords(&mut p2);
921 }
922 for (v1, v2) in izip!(
923 g.entity_iter(ReferenceCellType::Point),
924 g2.entity_iter(ReferenceCellType::Point)
925 ) {
926 v1.geometry().points().next().unwrap().coords(&mut p1);
927 v2.geometry().points().next().unwrap().coords(&mut p2);
928 for (c1, c2) in izip!(&p1, &p2) {
929 assert_relative_eq!(c1, c2, epsilon = 1e-10);
930 }
931 }
932 for (h1, h2) in izip!(
933 g.entity_iter(ReferenceCellType::Triangle),
934 g2.entity_iter(ReferenceCellType::Triangle)
935 ) {
936 for (v1, v2) in izip!(
937 h1.topology().sub_entity_iter(ReferenceCellType::Point),
938 h2.topology().sub_entity_iter(ReferenceCellType::Point)
939 ) {
940 assert_eq!(v1, v2);
941 }
942 }
943 }
944
945 #[test]
946 fn test_export_mixed() {
947 let mut b = MixedGridBuilder::<f64>::new(2);
948 b.add_point(0, &[0.0, 0.0]);
949 b.add_point(1, &[1.0, 0.0]);
950 b.add_point(2, &[0.0, 1.0]);
951 b.add_point(3, &[1.0, 1.0]);
952 b.add_point(4, &[2.0, 0.5]);
953 b.add_point(5, &[1.6, 0.9]);
954 b.add_point(6, &[1.0, 0.5]);
955 b.add_point(7, &[1.6, 0.1]);
956
957 b.add_cell(0, (ReferenceCellType::Quadrilateral, 1, &[0, 1, 2, 3]));
958 b.add_cell(1, (ReferenceCellType::Triangle, 2, &[1, 4, 3, 5, 6, 7]));
959 let g = b.create_grid();
960 g.export_as_gmsh("_test_io_mixed.msh");
961
962 let mut b = MixedGridBuilder::<f64>::new(2);
963 b.import_from_gmsh("_test_io_mixed.msh");
964 let _g = b.create_grid();
965 }
966
967 #[test]
968 fn test_import_mixed() {
969 let mut b = MixedGridBuilder::<f64>::new(2);
970 b.import_from_gmsh("meshes/mixed.msh");
971 let _g = b.create_grid();
972 }
973 #[test]
974 fn test_import_mixed_triangle() {
975 let mut b = MixedGridBuilder::<f64>::new(3);
976 b.import_from_gmsh("meshes/sphere_triangle.msh");
977 let _g = b.create_grid();
978 }
979
980 #[test]
981 fn test_import_triangle() {
982 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
983 b.import_from_gmsh("meshes/sphere_triangle.msh");
984 let _g = b.create_grid();
985 }
986
987 #[test]
988 fn test_import_quadrilateral() {
989 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
990 b.import_from_gmsh("meshes/cube_quadrilateral.msh");
991 let _g = b.create_grid();
992 }
993
994 #[test]
995 fn test_import_tetrahedron() {
996 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
997 b.import_from_gmsh("meshes/cube_tetrahedron.msh");
998 let _g = b.create_grid();
999 }
1000
1001 #[test]
1002 #[should_panic]
1003 fn test_import_wrong_cell() {
1004 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1005 b.import_from_gmsh("meshes/cube_tetrahedron.msh");
1006 let _g = b.create_grid();
1007 }
1008
1009 #[test]
1010 #[should_panic]
1011 fn test_import_wrong_degree() {
1012 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 2));
1013 b.import_from_gmsh("meshes/sphere_triangle.msh");
1014 let _g = b.create_grid();
1015 }
1016
1017 #[test]
1018 fn test_import_triangle_bin() {
1019 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
1020 b.import_from_gmsh("meshes/sphere_triangle_bin.msh");
1021 let _g = b.create_grid();
1022 }
1023
1024 #[test]
1025 fn test_import_quadrilateral_bin() {
1026 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1027 b.import_from_gmsh("meshes/cube_quadrilateral_bin.msh");
1028 let _g = b.create_grid();
1029 }
1030
1031 #[test]
1032 fn test_import_tetrahedron_bin() {
1033 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
1034 b.import_from_gmsh("meshes/cube_tetrahedron_bin.msh");
1035 let _g = b.create_grid();
1036 }
1037
1038 #[test]
1039 #[should_panic]
1040 fn test_import_wrong_cell_bin() {
1041 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1042 b.import_from_gmsh("meshes/cube_tetrahedron_bin.msh");
1043 let _g = b.create_grid();
1044 }
1045
1046 #[test]
1047 #[should_panic]
1048 fn test_import_wrong_degree_bin() {
1049 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 2));
1050 b.import_from_gmsh("meshes/sphere_triangle_bin.msh");
1051 let _g = b.create_grid();
1052 }
1053}