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 println!("{coords:?}");
277 self.add_point(tag, &coords[..self.gdim()]);
278 println!("ADDED");
279 }
280
281 let elements = gmsh_section(&s, "Elements");
283 let mut elements = elements.lines();
284
285 let Some(num_elements) = elements.next() else {
286 panic!("Could not read num nodes");
287 };
288 let num_elements = num_elements
289 .parse::<usize>()
290 .expect("Could not parse num nodes");
291
292 for _ in 0..num_elements {
293 let Some(line) = elements.next() else {
294 panic!("Unable to read element line");
295 };
296 let line = line.split(" ").collect::<Vec<&str>>();
297
298 let (a, node_tags) = line.split_at(5);
299 let [tag, element_type, ..] = a
300 .iter()
301 .map(|i| {
302 i.parse::<usize>()
303 .expect("Could not parse element tag and type")
304 })
305 .collect::<Vec<_>>()[..]
306 else {
307 panic!("Unrecognised format");
308 };
309
310 let node_tags = node_tags
311 .iter()
312 .map(|i| {
313 i.parse::<usize>()
314 .expect("Could not parse nodes for element")
315 })
316 .collect::<Vec<_>>();
317 let (cell_type, degree) = interpret_gmsh_cell(element_type);
318 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
319
320 let mut cell = vec![0; node_tags.len()];
321 for (i, j) in gmsh_perm.iter().enumerate() {
322 cell[*j] = node_tags[i];
323 }
324
325 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
326 }
327 }
328
329 fn import_from_gmsh_string_v2(&mut self, s: String) {
330 let nodes = gmsh_section(&s, "Nodes");
332 let mut nodes = nodes.lines();
333
334 let Some(num_nodes) = nodes.next() else {
335 panic!("Could not read num nodes");
336 };
337 let num_nodes = num_nodes
338 .parse::<usize>()
339 .expect("Could not parse num nodes");
340
341 for _ in 0..num_nodes {
342 let Some(line) = nodes.next() else {
343 panic!("Unable to read node line");
344 };
345 let line = line.split(" ").collect::<Vec<&str>>();
346
347 let (tag, coords) = line.split_at(1);
348 let tag = tag[0].parse::<usize>().expect("Could not parse node tag");
349 let coords = coords
350 .iter()
351 .map(|c| {
352 if let Ok(d) = T::from_str(c) {
353 d
354 } else {
355 panic!("Could not parse coords")
356 }
357 })
358 .collect::<Vec<_>>();
359
360 self.add_point(tag, &coords[..self.gdim()]);
361 }
362
363 let elements = gmsh_section(&s, "Elements");
365 let mut elements = elements.lines();
366
367 let Some(num_elements) = elements.next() else {
368 panic!("Could not read num nodes");
369 };
370 let num_elements = num_elements
371 .parse::<usize>()
372 .expect("Could not parse num nodes");
373
374 for _ in 0..num_elements {
375 let Some(line) = elements.next() else {
376 panic!("Unable to read element line");
377 };
378 let line = line.split(" ").collect::<Vec<&str>>();
379
380 let (a, rem_line) = line.split_at(3);
381 let [tag, element_type, num_tags] = a
382 .iter()
383 .map(|i| {
384 i.parse::<usize>()
385 .expect("Could not parse element tag and type")
386 })
387 .collect::<Vec<_>>()[..]
388 else {
389 panic!("Unrecognised format");
390 };
391
392 let (_, node_tags) = rem_line.split_at(num_tags);
393 let node_tags = node_tags
394 .iter()
395 .map(|i| {
396 i.parse::<usize>()
397 .expect("Could not parse nodes for element")
398 })
399 .collect::<Vec<_>>();
400 let (cell_type, degree) = interpret_gmsh_cell(element_type);
401 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
402
403 let mut cell = vec![0; node_tags.len()];
404 for (i, j) in gmsh_perm.iter().enumerate() {
405 cell[*j] = node_tags[i];
406 }
407
408 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
409 }
410 }
411
412 fn import_from_gmsh_binary_v2(
413 &mut self,
414 mut reader: BufReader<File>,
415 data_size: usize,
416 is_le: bool,
417 ) {
418 let mut line = String::new();
419 let mut buf = Vec::new();
420
421 macro_rules! read_exact {
422 ($size: expr, $msg: expr) => {{
423 buf.resize($size, 0);
424 reader.read_exact(&mut buf).expect($msg);
425 }};
426 }
427
428 const GMSH_INT_SIZE: usize = 4;
429
430 loop {
431 let Ok(num_bytes) = reader.read_line(&mut line) else {
432 continue;
433 };
434
435 if num_bytes == 0 {
437 break;
438 }
439
440 match line.trim() {
441 "$Nodes" => {
443 line.clear();
444 let Ok(_) = reader.read_line(&mut line) else {
445 panic!("Unable to read num nodes");
446 };
447 let num_nodes = line
448 .trim()
449 .parse::<usize>()
450 .expect("Could not parse num nodes");
451
452 for _ in 0..num_nodes {
453 read_exact!(GMSH_INT_SIZE, "Unable to read node tag");
454 let tag = parse::<usize>(&buf, GMSH_INT_SIZE, is_le);
455
456 read_exact!(3 * data_size, "Unable to read node coords");
457 let coords = buf
458 .chunks(data_size)
459 .map(|i| parse::<T>(i, data_size, is_le))
460 .collect::<Vec<_>>();
461
462 self.add_point(tag, &coords[..self.gdim()]);
463 }
464
465 line.clear();
466 }
467 "$Elements" => {
469 line.clear();
470 let Ok(_) = reader.read_line(&mut line) else {
471 panic!("Unable to read num elements")
472 };
473 let num_elements = line
474 .trim()
475 .parse::<usize>()
476 .expect("Could not parse num elements");
477
478 for _ in 0..num_elements {
479 read_exact!(3 * GMSH_INT_SIZE, "Unable to element tag and type");
480 let [elm_type, _num_elm_follow, num_tags] = buf
481 .chunks(GMSH_INT_SIZE)
482 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
483 .collect::<Vec<_>>()[..]
484 else {
485 panic!("Could not parse element tag and type")
486 };
487
488 read_exact!(GMSH_INT_SIZE, "Unable to read num tags");
489 let tag = parse::<usize>(&buf, 4, is_le);
490
491 read_exact!(num_tags * GMSH_INT_SIZE, "Unable to read element tags");
493
494 let (cell_type, degree) = interpret_gmsh_cell(elm_type);
495 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
496
497 read_exact!(
498 gmsh_perm.len() * GMSH_INT_SIZE,
499 "Unable to read element node tags"
500 );
501 let node_tags = buf
502 .chunks(GMSH_INT_SIZE)
503 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
504 .collect::<Vec<_>>();
505
506 let mut cell = vec![0; node_tags.len()];
507 for (i, j) in gmsh_perm.iter().enumerate() {
508 cell[*j] = node_tags[i];
509 }
510
511 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
512 }
513 line.clear();
514 }
515 _ => {
516 line.clear();
517 }
518 }
519 }
520 }
521
522 fn import_from_gmsh_string_v4(&mut self, s: String) {
523 let nodes = gmsh_section(&s, "Nodes");
525 let nodes = nodes.lines().collect::<Vec<_>>();
526
527 let [num_entity_blocks, _num_nodes, _min_node_tag, _max_node_tag] = nodes[0]
528 .trim()
529 .split(" ")
530 .map(|i| i.parse::<usize>().unwrap())
531 .collect::<Vec<_>>()[..]
532 else {
533 panic!("Unrecognised gmsh format for node blocks");
534 };
535
536 let mut line_n = 1;
537 for _ in 0..num_entity_blocks {
538 let [_entity_dim, _entity_tag, parametric, num_nodes_in_block] = nodes[line_n]
539 .trim()
540 .split(" ")
541 .map(|i| i.parse::<usize>().unwrap())
542 .collect::<Vec<_>>()[..]
543 else {
544 panic!("Unrecognised gmsh format for nodes");
545 };
546 if parametric == 1 {
547 unimplemented!("Parametric nodes currently not supported")
548 }
549 line_n += 1;
550 let tags = &nodes[line_n..line_n + num_nodes_in_block];
551 let coords = &nodes[line_n + num_nodes_in_block..line_n + 2 * num_nodes_in_block];
552 for (t, c) in izip!(tags, coords) {
553 let pt = c
554 .trim()
555 .split(" ")
556 .map(|i| {
557 if let Ok(j) = T::from_str(i) {
558 j
559 } else {
560 panic!("Could not parse coordinate");
561 }
562 })
563 .collect::<Vec<_>>();
564 self.add_point(t.parse::<usize>().unwrap(), &pt[..self.gdim()]);
565 }
566 line_n += num_nodes_in_block * 2;
567 }
568
569 let elements = gmsh_section(&s, "Elements");
571 let elements = elements.lines().collect::<Vec<_>>();
572
573 let [
574 num_entity_blocks,
575 _num_elements,
576 _min_element_tag,
577 _max_element_tag,
578 ] = elements[0]
579 .trim()
580 .split(" ")
581 .map(|i| i.parse::<usize>().unwrap())
582 .collect::<Vec<_>>()[..]
583 else {
584 panic!("Unrecognised gmsh format");
585 };
586
587 let mut line_n = 1;
588 for _ in 0..num_entity_blocks {
589 let [
590 _entity_dim,
591 _entity_tag,
592 element_type,
593 num_elements_in_block,
594 ] = elements[line_n]
595 .trim()
596 .split(" ")
597 .map(|i| i.parse::<usize>().unwrap())
598 .collect::<Vec<_>>()[..]
599 else {
600 panic!("Unrecognised gmsh format");
601 };
602 let (cell_type, degree) = interpret_gmsh_cell(element_type);
603 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
604
605 line_n += 1;
606 for line in &elements[line_n..line_n + num_elements_in_block] {
607 let line = line
608 .trim()
609 .split(" ")
610 .map(|i| i.parse::<usize>().unwrap())
611 .collect::<Vec<_>>();
612 let mut cell = vec![0; line.len() - 1];
613 for (i, j) in gmsh_perm.iter().enumerate() {
614 cell[*j] = line[i + 1];
615 }
616 self.add_cell_from_nodes_and_type(line[0], &cell, cell_type, degree);
617 }
618
619 line_n += num_elements_in_block;
620 }
621 }
622
623 fn import_from_gmsh_binary_v4(
624 &mut self,
625 mut reader: BufReader<File>,
626 data_size: usize,
627 is_le: bool,
628 ) {
629 let mut line = String::new();
630 let mut buf = Vec::new();
631
632 macro_rules! read_exact {
633 ($size: expr, $msg: expr) => {{
634 buf.resize($size, 0);
635 reader.read_exact(&mut buf).expect($msg);
636 }};
637 }
638
639 const GMSH_INT_SIZE: usize = 4;
640
641 loop {
642 let Ok(num_bytes) = reader.read_line(&mut line) else {
643 continue;
644 };
645
646 if num_bytes == 0 {
648 break;
649 }
650
651 match line.trim() {
652 "$Nodes" => {
654 read_exact!(4 * data_size, "Unable to read node section info");
655 let [num_entity_blocks, _num_nodes, _min_node_tag, _max_node_tag] = buf
656 .chunks(data_size)
657 .map(|i| parse::<usize>(i, data_size, is_le))
658 .collect::<Vec<_>>()[..]
659 else {
660 panic!("Could not parse node section info")
661 };
662
663 for _ in 0..num_entity_blocks {
664 read_exact!(3 * GMSH_INT_SIZE, "Unable to read node entity block info");
665 let [_entity_dim, _entity_tag, parametric] = buf
666 .chunks(GMSH_INT_SIZE)
667 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
668 .collect::<Vec<_>>()[..]
669 else {
670 panic!("Could not parse node entity block info")
671 };
672
673 if parametric == 1 {
674 unimplemented!("Parametric nodes currently not supported")
675 }
676
677 read_exact!(data_size, "Unable to read num nodes in block");
678 let num_nodes_in_block = parse::<usize>(&buf, data_size, is_le);
679
680 read_exact!(num_nodes_in_block * data_size, "Unable to read node tags");
681 let tags = buf
682 .chunks(data_size)
683 .map(|i| parse::<usize>(i, data_size, is_le))
684 .collect::<Vec<_>>();
685
686 read_exact!(
687 3 * num_nodes_in_block * data_size,
688 "Unable to read node coords"
689 );
690 let coords = buf
691 .chunks(3 * data_size)
692 .map(|i| {
693 i.chunks(data_size)
694 .map(|j| parse::<T>(j, data_size, is_le))
695 .collect::<Vec<_>>()
696 })
697 .collect::<Vec<_>>();
698
699 for (t, c) in izip!(tags, coords) {
700 self.add_point(t, &c[..self.gdim()]);
701 }
702 }
703
704 line.clear();
705 }
706 "$Elements" => {
708 read_exact!(4 * data_size, "Unable to read element section info");
709 let [
710 num_entity_blocks,
711 _num_elements,
712 _min_element_tag,
713 _max_element_tag,
714 ] = buf
715 .chunks(data_size)
716 .map(|i| parse::<usize>(i, data_size, is_le))
717 .collect::<Vec<_>>()[..]
718 else {
719 panic!("Could not parse element section info")
720 };
721
722 for _ in 0..num_entity_blocks {
723 read_exact!(
724 3 * GMSH_INT_SIZE,
725 "Unable to read element entity block info"
726 );
727 let [_entity_dim, _entity_tag, element_type] = buf
728 .chunks(GMSH_INT_SIZE)
729 .map(|i| parse::<usize>(i, GMSH_INT_SIZE, is_le))
730 .collect::<Vec<_>>()[..]
731 else {
732 panic!("Could not parse element entity block info")
733 };
734
735 read_exact!(data_size, "Unable to read num elements in block");
736 let num_elements_in_block = parse::<usize>(&buf, data_size, is_le);
737
738 let (cell_type, degree) = interpret_gmsh_cell(element_type);
739 let gmsh_perm = get_permutation_to_gmsh(cell_type, degree);
740
741 for _ in 0..num_elements_in_block {
742 read_exact!(data_size, "Unable to read element tag");
743 let tag = parse::<usize>(&buf, data_size, is_le);
744
745 read_exact!(data_size * gmsh_perm.len(), "Unable to read node tags");
746 let node_tags = buf
747 .chunks(data_size)
748 .map(|i| parse::<usize>(i, data_size, is_le))
749 .collect::<Vec<_>>();
750
751 let mut cell = vec![0; node_tags.len()];
752 for (i, j) in gmsh_perm.iter().enumerate() {
753 cell[*j] = node_tags[i];
754 }
755
756 self.add_cell_from_nodes_and_type(tag, &cell, cell_type, degree);
757 }
758 }
759 line.clear();
760 }
761 _ => {
762 line.clear();
763 }
764 }
765 }
766 }
767}
768
769#[cfg(test)]
770mod test {
771 use super::*;
772 use crate::{
773 MixedGridBuilder, SingleElementGridBuilder,
774 shapes::regular_sphere,
775 traits::{Builder, Topology},
776 };
777 use approx::*;
778
779 #[test]
780 fn test_regular_sphere_gmsh_io() {
781 let g = regular_sphere::<f64>(2);
782 g.export_as_gmsh("_test_io_sphere.msh");
783 }
784
785 #[test]
786 fn test_export_quads() {
787 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
788 b.add_point(0, &[0.0, 0.0, 0.0]);
789 b.add_point(1, &[1.0, 0.0, 0.0]);
790 b.add_point(2, &[0.0, 1.0, 0.0]);
791 b.add_point(3, &[1.0, 1.0, 0.0]);
792 b.add_point(4, &[0.0, 0.0, 1.0]);
793 b.add_point(5, &[1.0, 0.0, 1.0]);
794 b.add_point(6, &[0.0, 1.0, 1.0]);
795 b.add_point(7, &[1.0, 1.0, 1.0]);
796 b.add_cell(0, &[0, 2, 1, 3]);
797 b.add_cell(1, &[0, 1, 4, 5]);
798 b.add_cell(2, &[0, 4, 2, 6]);
799 b.add_cell(3, &[1, 3, 5, 7]);
800 b.add_cell(4, &[2, 6, 3, 7]);
801 b.add_cell(5, &[4, 5, 6, 7]);
802 let g = b.create_grid();
803 g.export_as_gmsh("_test_io_cube.msh");
804 }
805
806 #[test]
807 fn test_export_tetrahedra() {
808 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
809 b.add_point(0, &[0.0, 0.0, 0.0]);
810 b.add_point(1, &[1.0, 0.0, 0.0]);
811 b.add_point(2, &[0.0, 1.0, 0.0]);
812 b.add_point(3, &[1.0, 1.0, 0.0]);
813 b.add_point(4, &[0.0, 0.0, 1.0]);
814 b.add_point(5, &[1.0, 0.0, 1.0]);
815 b.add_point(6, &[0.0, 1.0, 1.0]);
816 b.add_point(7, &[1.0, 1.0, 1.0]);
817 b.add_cell(0, &[0, 1, 5, 7]);
818 b.add_cell(1, &[0, 2, 6, 7]);
819 b.add_cell(2, &[0, 4, 5, 7]);
820 b.add_cell(3, &[0, 1, 3, 7]);
821 b.add_cell(4, &[0, 2, 3, 7]);
822 b.add_cell(5, &[0, 4, 6, 7]);
823 let g = b.create_grid();
824 g.export_as_gmsh("_test_io_tetrahedra.msh");
825 }
826
827 #[test]
828 fn test_hexahedra() {
829 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Hexahedron, 1));
830 b.add_point(0, &[0.0, 0.0, 0.0]);
831 b.add_point(1, &[1.0, 0.0, 0.0]);
832 b.add_point(2, &[0.0, 1.0, 0.0]);
833 b.add_point(3, &[1.0, 1.0, 0.0]);
834 b.add_point(4, &[0.0, 0.0, 1.0]);
835 b.add_point(5, &[1.0, 0.0, 1.0]);
836 b.add_point(6, &[0.0, 1.0, 1.0]);
837 b.add_point(7, &[1.0, 1.0, 1.0]);
838 b.add_point(8, &[0.0, 0.0, 2.0]);
839 b.add_point(9, &[1.0, 0.0, 2.0]);
840 b.add_point(10, &[0.0, 1.0, 2.0]);
841 b.add_point(11, &[1.0, 1.0, 1.5]);
842 b.add_cell(1, &[0, 1, 2, 3, 4, 5, 6, 7]);
843 b.add_cell(2, &[4, 5, 6, 7, 8, 9, 10, 11]);
844 let g = b.create_grid();
845 g.export_as_gmsh("_test_io_hexahedra.msh");
846
847 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Hexahedron, 1));
848 b.import_from_gmsh("_test_io_hexahedra.msh");
849 let g2 = b.create_grid();
850
851 let mut p1 = [0.0; 3];
852 let mut p2 = [0.0; 3];
853 for (v1, v2) in izip!(
854 g.entity_iter(ReferenceCellType::Point),
855 g2.entity_iter(ReferenceCellType::Point)
856 ) {
857 for (pt1, pt2) in izip!(v1.geometry().points(), v2.geometry().points()) {
858 pt1.coords(&mut p1);
859 pt2.coords(&mut p2);
860 for (c1, c2) in izip!(&p1, &p2) {
861 assert_relative_eq!(c1, c2, epsilon = 1e-10);
862 }
863 }
864 }
865 for (h1, h2) in izip!(
866 g.entity_iter(ReferenceCellType::Hexahedron),
867 g2.entity_iter(ReferenceCellType::Hexahedron)
868 ) {
869 for (v1, v2) in izip!(
870 h1.topology().sub_entity_iter(ReferenceCellType::Point),
871 h2.topology().sub_entity_iter(ReferenceCellType::Point)
872 ) {
873 assert_eq!(v1, v2);
874 }
875 }
876 }
877
878 #[test]
879 fn test_high_order_triangles() {
880 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 5));
881 b.add_point(0, &[0.0, 0.0, 0.0]);
882 b.add_point(1, &[5.0, 0.0, 0.2]);
883 b.add_point(2, &[0.0, 5.0, 0.4]);
884 b.add_point(3, &[4.0, 1.0, -0.1]);
885 b.add_point(4, &[3.0, 2.0, 0.2]);
886 b.add_point(5, &[2.0, 3.0, -0.3]);
887 b.add_point(6, &[1.0, 4.0, -0.5]);
888 b.add_point(7, &[0.0, 1.0, 0.6]);
889 b.add_point(8, &[0.0, 2.0, 0.2]);
890 b.add_point(9, &[0.0, 3.0, 0.1]);
891 b.add_point(10, &[0.0, 4.0, -0.2]);
892 b.add_point(11, &[1.0, 0.0, -0.3]);
893 b.add_point(12, &[2.0, 0.0, -0.4]);
894 b.add_point(13, &[3.0, 0.0, -0.5]);
895 b.add_point(14, &[4.0, 0.0, -0.2]);
896 b.add_point(15, &[1.0, 1.0, 0.1]);
897 b.add_point(16, &[2.0, 1.0, 0.1]);
898 b.add_point(17, &[3.0, 1.0, 0.1]);
899 b.add_point(18, &[2.0, 1.0, 0.2]);
900 b.add_point(19, &[2.0, 2.0, 0.1]);
901 b.add_point(20, &[3.0, 1.0, 0.1]);
902 b.add_cell(
903 1,
904 &[
905 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
906 ],
907 );
908 let g = b.create_grid();
909 g.export_as_gmsh("_test_io_high_order_triangle.msh");
910
911 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 5));
912 b.import_from_gmsh("_test_io_high_order_triangle.msh");
913 let g2 = b.create_grid();
914
915 let mut p1 = [0.0; 3];
916 let mut p2 = [0.0; 3];
917 for (v1, v2) in izip!(
918 g.entity_iter(ReferenceCellType::Point),
919 g2.entity_iter(ReferenceCellType::Point)
920 ) {
921 v1.geometry().points().next().unwrap().coords(&mut p1);
922 v2.geometry().points().next().unwrap().coords(&mut p2);
923 }
924 for (v1, v2) in izip!(
925 g.entity_iter(ReferenceCellType::Point),
926 g2.entity_iter(ReferenceCellType::Point)
927 ) {
928 v1.geometry().points().next().unwrap().coords(&mut p1);
929 v2.geometry().points().next().unwrap().coords(&mut p2);
930 for (c1, c2) in izip!(&p1, &p2) {
931 assert_relative_eq!(c1, c2, epsilon = 1e-10);
932 }
933 }
934 for (h1, h2) in izip!(
935 g.entity_iter(ReferenceCellType::Triangle),
936 g2.entity_iter(ReferenceCellType::Triangle)
937 ) {
938 for (v1, v2) in izip!(
939 h1.topology().sub_entity_iter(ReferenceCellType::Point),
940 h2.topology().sub_entity_iter(ReferenceCellType::Point)
941 ) {
942 assert_eq!(v1, v2);
943 }
944 }
945 }
946
947 #[test]
948 fn test_export_mixed() {
949 let mut b = MixedGridBuilder::<f64>::new(2);
950 b.add_point(0, &[0.0, 0.0]);
951 b.add_point(1, &[1.0, 0.0]);
952 b.add_point(2, &[0.0, 1.0]);
953 b.add_point(3, &[1.0, 1.0]);
954 b.add_point(4, &[2.0, 0.5]);
955 b.add_point(5, &[1.6, 0.9]);
956 b.add_point(6, &[1.0, 0.5]);
957 b.add_point(7, &[1.6, 0.1]);
958
959 b.add_cell(0, (ReferenceCellType::Quadrilateral, 1, &[0, 1, 2, 3]));
960 b.add_cell(1, (ReferenceCellType::Triangle, 2, &[1, 4, 3, 5, 6, 7]));
961 let g = b.create_grid();
962 g.export_as_gmsh("_test_io_mixed.msh");
963
964 let mut b = MixedGridBuilder::<f64>::new(2);
965 b.import_from_gmsh("_test_io_mixed.msh");
966 let _g = b.create_grid();
967 }
968
969 #[test]
970 fn test_import_mixed() {
971 let mut b = MixedGridBuilder::<f64>::new(2);
972 b.import_from_gmsh("meshes/mixed.msh");
973 let _g = b.create_grid();
974 }
975 #[test]
976 fn test_import_mixed_triangle() {
977 let mut b = MixedGridBuilder::<f64>::new(3);
978 b.import_from_gmsh("meshes/sphere_triangle.msh");
979 let _g = b.create_grid();
980 }
981
982 #[test]
983 fn test_import_triangle() {
984 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
985 b.import_from_gmsh("meshes/sphere_triangle.msh");
986 let _g = b.create_grid();
987 }
988
989 #[test]
990 fn test_import_quadrilateral() {
991 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
992 b.import_from_gmsh("meshes/cube_quadrilateral.msh");
993 let _g = b.create_grid();
994 }
995
996 #[test]
997 fn test_import_tetrahedron() {
998 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
999 b.import_from_gmsh("meshes/cube_tetrahedron.msh");
1000 let _g = b.create_grid();
1001 }
1002
1003 #[test]
1004 #[should_panic]
1005 fn test_import_wrong_cell() {
1006 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1007 b.import_from_gmsh("meshes/cube_tetrahedron.msh");
1008 let _g = b.create_grid();
1009 }
1010
1011 #[test]
1012 #[should_panic]
1013 fn test_import_wrong_degree() {
1014 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 2));
1015 b.import_from_gmsh("meshes/sphere_triangle.msh");
1016 let _g = b.create_grid();
1017 }
1018
1019 #[test]
1020 fn test_import_triangle_bin() {
1021 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
1022 b.import_from_gmsh("meshes/sphere_triangle_bin.msh");
1023 let _g = b.create_grid();
1024 }
1025
1026 #[test]
1027 fn test_import_quadrilateral_bin() {
1028 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1029 b.import_from_gmsh("meshes/cube_quadrilateral_bin.msh");
1030 let _g = b.create_grid();
1031 }
1032
1033 #[test]
1034 fn test_import_tetrahedron_bin() {
1035 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Tetrahedron, 1));
1036 b.import_from_gmsh("meshes/cube_tetrahedron_bin.msh");
1037 let _g = b.create_grid();
1038 }
1039
1040 #[test]
1041 #[should_panic]
1042 fn test_import_wrong_cell_bin() {
1043 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Quadrilateral, 1));
1044 b.import_from_gmsh("meshes/cube_tetrahedron_bin.msh");
1045 let _g = b.create_grid();
1046 }
1047
1048 #[test]
1049 #[should_panic]
1050 fn test_import_wrong_degree_bin() {
1051 let mut b = SingleElementGridBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 2));
1052 b.import_from_gmsh("meshes/sphere_triangle_bin.msh");
1053 let _g = b.create_grid();
1054 }
1055}