32 template<
typename C>
static bool check_voxel(
const C& c) {
34 unsigned N = c[0].size();
35 if (c.size() != (1U << N))
return false;
36 const base_node P0 = c[0];
37 h[0] = c[1][0] - P0[0];
38 h[1] = c[2][0] - P0[0];
39 if (c.size() != 4) h[2] = c[4][0] - P0[0];
40 for (
unsigned i=1; i < c.size(); ++i) {
41 const base_node d = c[i] - P0;
42 for (
unsigned j=0; j < N; ++j)
43 if (gmm::abs(d[j]) > 1e-7*h[j] && gmm::abs(d[j] - h[j]) > 1e-7*h[j])
50 std::string base64_encode(
const std::vector<unsigned char>& src)
52 const std::string table(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
54 for (
size_type i = 0; i < src.size(); ++i) {
57 dst.push_back(table[(src[i] & 0xFC) >> 2]);
58 if (i + 1 == src.size()) {
59 dst.push_back(table[(src[i] & 0x03) << 4]);
65 dst.push_back(table[((src[i - 1] & 0x03) << 4) | ((src[i + 0] & 0xF0) >> 4)]);
66 if (i + 1 == src.size()) {
67 dst.push_back(table[(src[i] & 0x0F) << 2]);
72 dst.push_back(table[((src[i - 1] & 0x0F) << 2) | ((src[i + 0] & 0xC0) >> 6)]);
73 dst.push_back(table[src[i] & 0x3F]);
84 struct gf2vtk_dof_mapping :
public std::vector<std::vector<unsigned> > {};
85 struct gf2vtk_vtk_type :
public std::vector<int> {};
87 typedef enum { VTK_VERTEX = 1,
97 VTK_QUADRATIC_EDGE = 21,
98 VTK_QUADRATIC_TRIANGLE = 22,
99 VTK_QUADRATIC_QUAD = 23,
100 VTK_QUADRATIC_TETRA = 24,
101 VTK_QUADRATIC_HEXAHEDRON = 25,
102 VTK_QUADRATIC_WEDGE = 26,
103 VTK_QUADRATIC_PYRAMID = 27,
104 VTK_BIQUADRATIC_QUAD = 28,
105 VTK_TRIQUADRATIC_HEXAHEDRON = 29,
106 VTK_BIQUADRATIC_QUADRATIC_WEDGE = 32 } vtk_cell_type;
108 typedef enum { NO_VTK_MAPPING,
116 N8_TO_VTK_HEXAHEDRON,
119 N3_TO_VTK_QUADRATIC_EDGE,
120 N6_TO_VTK_QUADRATIC_TRIANGLE,
121 N8_TO_VTK_QUADRATIC_QUAD,
122 N10_TO_VTK_QUADRATIC_TETRA,
123 N20_TO_VTK_QUADRATIC_HEXAHEDRON,
124 N15_TO_VTK_QUADRATIC_WEDGE,
125 N13_TO_VTK_QUADRATIC_PYRAMID,
126 N14_TO_VTK_QUADRATIC_PYRAMID,
127 N9_TO_VTK_BIQUADRATIC_QUAD,
128 N27_TO_VTK_TRIQUADRATIC_HEXAHEDRON,
129 N18_TO_VTK_BIQUADRATIC_QUADRATIC_WEDGE } vtk_mapping_type;
141 vtktypes[N1_TO_VTK_VERTEX] = VTK_VERTEX;
142 vtkmaps [N1_TO_VTK_VERTEX] = {0};
143 vtktypes[N2_TO_VTK_LINE] = VTK_LINE;
144 vtkmaps [N2_TO_VTK_LINE] = {0, 1};
145 vtktypes[N3_TO_VTK_TRIANGLE] = VTK_TRIANGLE;
146 vtkmaps [N3_TO_VTK_TRIANGLE] = {0, 1, 2};
147 vtktypes[N4_TO_VTK_PIXEL] = VTK_PIXEL;
148 vtkmaps [N4_TO_VTK_PIXEL] = {0, 1, 2, 3};
149 vtktypes[N4_TO_VTK_QUAD] = VTK_QUAD;
150 vtkmaps [N4_TO_VTK_QUAD] = {0, 1, 3, 2};
151 vtktypes[N4_TO_VTK_TETRA] = VTK_TETRA;
152 vtkmaps [N4_TO_VTK_TETRA] = {0, 1, 2, 3};
153 vtktypes[N8_TO_VTK_VOXEL] = VTK_VOXEL;
154 vtkmaps [N8_TO_VTK_VOXEL] = {0, 1, 2, 3, 4, 5, 6, 7};
155 vtktypes[N8_TO_VTK_HEXAHEDRON] = VTK_HEXAHEDRON;
156 vtkmaps [N8_TO_VTK_HEXAHEDRON] = {0, 1, 3, 2, 4, 5, 7, 6};
157 vtktypes[N6_TO_VTK_WEDGE] = VTK_WEDGE;
158 vtkmaps [N6_TO_VTK_WEDGE] = {0, 1, 2, 3, 4, 5};
159 vtktypes[N5_TO_VTK_PYRAMID] = VTK_PYRAMID;
160 vtkmaps [N5_TO_VTK_PYRAMID] = {0, 1, 3, 2, 4};
161 vtktypes[N3_TO_VTK_QUADRATIC_EDGE] = VTK_QUADRATIC_EDGE;
162 vtkmaps [N3_TO_VTK_QUADRATIC_EDGE] = {0, 2, 1};
163 vtktypes[N6_TO_VTK_QUADRATIC_TRIANGLE] = VTK_QUADRATIC_TRIANGLE;
164 vtkmaps [N6_TO_VTK_QUADRATIC_TRIANGLE] = {0, 2, 5, 1, 4, 3};
165 vtktypes[N8_TO_VTK_QUADRATIC_QUAD] = VTK_QUADRATIC_QUAD;
166 vtkmaps [N8_TO_VTK_QUADRATIC_QUAD] = {0, 2, 7, 5, 1, 4, 6, 3};
167 vtktypes[N10_TO_VTK_QUADRATIC_TETRA] = VTK_QUADRATIC_TETRA;
168 vtkmaps [N10_TO_VTK_QUADRATIC_TETRA] = {0, 2, 5, 9, 1, 4, 3, 6, 7, 8};
169 vtktypes[N20_TO_VTK_QUADRATIC_HEXAHEDRON] = VTK_QUADRATIC_HEXAHEDRON;
170 vtkmaps [N20_TO_VTK_QUADRATIC_HEXAHEDRON] = {0, 2, 7, 5, 12, 14, 19, 17, 1, 4, 6, 3, 13, 16, 18, 15, 8, 9, 11, 10};
171 vtktypes[N15_TO_VTK_QUADRATIC_WEDGE] = VTK_QUADRATIC_WEDGE;
172 vtkmaps [N15_TO_VTK_QUADRATIC_WEDGE] = {0, 2, 5, 9, 11, 14, 1, 4, 3, 10, 13, 12, 6, 7, 8};
174 vtktypes[N13_TO_VTK_QUADRATIC_PYRAMID] = VTK_QUADRATIC_PYRAMID;
175 vtkmaps [N13_TO_VTK_QUADRATIC_PYRAMID] = {0, 2, 7, 5, 12, 1, 4, 6, 3, 8, 9, 11, 10};
176 vtktypes[N14_TO_VTK_QUADRATIC_PYRAMID] = VTK_QUADRATIC_PYRAMID;
177 vtkmaps [N14_TO_VTK_QUADRATIC_PYRAMID] = {0, 2, 8, 6, 13, 1, 5, 7, 3, 9, 10, 12, 11};
178 vtktypes[N9_TO_VTK_BIQUADRATIC_QUAD] = VTK_BIQUADRATIC_QUAD;
179 vtkmaps [N9_TO_VTK_BIQUADRATIC_QUAD] = {0, 2, 8, 6, 1, 5, 7, 3, 4};
180 vtktypes[N27_TO_VTK_TRIQUADRATIC_HEXAHEDRON] = VTK_TRIQUADRATIC_HEXAHEDRON;
181 vtkmaps [N27_TO_VTK_TRIQUADRATIC_HEXAHEDRON] = {0, 2, 8, 6, 18, 20, 26, 24, 1, 5, 7, 3, 19, 23, 25, 21, 9, 11, 17, 15, 12, 14, 10, 16, 4, 22};
182 vtktypes[N18_TO_VTK_BIQUADRATIC_QUADRATIC_WEDGE] = VTK_BIQUADRATIC_QUADRATIC_WEDGE;
183 vtkmaps [N18_TO_VTK_BIQUADRATIC_QUADRATIC_WEDGE] = {0, 2, 5, 12, 14, 17, 1, 4, 3, 13, 16, 15, 6, 8, 11, 7, 10, 9};
186 static const std::vector<unsigned> &
187 select_vtk_dof_mapping(
unsigned t) {
189 if (vtkmaps.size() == 0) init_gf2vtk();
193 int select_vtk_type(
unsigned t) {
195 if (vtktypes.size() == 0) init_gf2vtk();
200 vtk_export::vtk_export(std::ostream &os_,
bool ascii_,
bool vtk_)
201 : os(os_), ascii(ascii_), vtk(vtk_) { init(); }
203 vtk_export::vtk_export(
const std::string& fname,
bool ascii_,
bool vtk_)
204 : os(real_os), ascii(ascii_), vtk(vtk_),
205 real_os(fname.c_str(), !ascii ? std::ios_base::binary | std::ios_base::out
206 : std::ios_base::out) {
207 GMM_ASSERT1(real_os,
"impossible to write to file '" << fname <<
"'");
211 vtk_export::~vtk_export(){
213 if (state == IN_CELL_DATA) os <<
"</CellData>\n";
214 if (state == IN_POINT_DATA) os <<
"</PointData>\n";
216 os <<
"</UnstructuredGrid>\n";
217 os <<
"</VTKFile>\n";
221 void vtk_export::init() {
222 strcpy(header,
"Exported by GetFEM");
223 psl = 0; dim_ = dim_type(-1);
224 static int test_endian = 0x01234567;
225 reverse_endian = (*((
char*)&test_endian) == 0x67);
230 void vtk_export::switch_to_cell_data() {
231 if (state != IN_CELL_DATA) {
234 if (psl)
for (
auto i : {0,1,2,3}) nb_cells += psl->nb_simplexes(i);
235 else nb_cells = pmf->convex_index().card();
237 os <<
"CELL_DATA " << nb_cells <<
"\n";
240 if (state == IN_POINT_DATA) os <<
"</PointData>\n";
241 os <<
"<CellData>\n";
243 state = IN_CELL_DATA;
247 void vtk_export::switch_to_point_data() {
248 if (state != IN_POINT_DATA) {
251 os <<
"POINT_DATA " << (psl ? psl->nb_points()
252 : pmf_dof_used.card()) <<
"\n";
255 if (state == IN_CELL_DATA) os <<
"</CellData>\n";
256 os <<
"<PointData>\n";
258 state = IN_POINT_DATA;
263 void vtk_export::exporting(
const stored_mesh_slice& sl) {
264 psl = &sl; dim_ = dim_type(sl.dim());
265 GMM_ASSERT1(psl->dim() <= 3,
"attempt to export a " <<
int(dim_)
266 <<
"D slice (not supported)");
269 void vtk_export::exporting(
const mesh& m) {
271 GMM_ASSERT1(dim_ <= 3,
"attempt to export a " <<
int(dim_)
272 <<
"D mesh (not supported)");
273 pmf = std::make_unique<mesh_fem>(
const_cast<mesh&
>(m), dim_type(1));
274 for (dal::bv_visitor cv(m.
convex_index()); !cv.finished(); ++cv) {
277 pmf->set_finite_element(cv, pf);
282 void vtk_export::exporting(
const mesh_fem& mf) {
284 GMM_ASSERT1(dim_ <= 3,
"attempt to export a " <<
int(dim_)
285 <<
"D mesh_fem (not supported)");
286 if (&mf != pmf.get())
287 pmf = std::make_unique<mesh_fem>(mf.
linked_mesh());
290 for (dal::bv_visitor cv(mf.
convex_index()); !cv.finished(); ++cv) {
297 pf ==
fem_descriptor(
"FEM_PYRAMID_Q2_INCOMPLETE_DISCONTINUOUS") ||
300 pmf->set_finite_element(cv, pf);
302 bool discontinuous =
false;
303 for (
unsigned i=0; i < pf->nb_dof(cv); ++i) {
305 if (!
dof_linkable(pf->dof_types()[i])) { discontinuous =
true;
break; }
312 if ((pf != classical_pf1 && pf->estimated_degree() > 1) ||
313 pgt->structure() != pgt->basic_structure())
316 pmf->set_finite_element(cv, discontinuous ?
323 const mesh &m = pmf->linked_mesh();
324 pmf_mapping_type.resize(pmf->convex_index().last_true() + 1,
unsigned(-1));
325 pmf_dof_used.sup(0, pmf->nb_basic_dof());
326 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
327 vtk_mapping_type t = NO_VTK_MAPPING;
328 size_type nbd = pmf->fem_of_element(cv)->nb_dof(cv);
329 switch (pmf->fem_of_element(cv)->dim()) {
330 case 0: t = N1_TO_VTK_VERTEX;
break;
332 if (nbd == 2) t = N2_TO_VTK_LINE;
333 else if (nbd == 3) t = N3_TO_VTK_QUADRATIC_EDGE;
336 if (nbd == 3) t = N3_TO_VTK_TRIANGLE;
338 t = check_voxel(m.points_of_convex(cv)) ? N4_TO_VTK_PIXEL
340 else if (nbd == 6) t = N6_TO_VTK_QUADRATIC_TRIANGLE;
341 else if (nbd == 8) t = N8_TO_VTK_QUADRATIC_QUAD;
342 else if (nbd == 9) t = N9_TO_VTK_BIQUADRATIC_QUAD;
345 if (nbd == 4) t = N4_TO_VTK_TETRA;
346 else if (nbd == 10) t = N10_TO_VTK_QUADRATIC_TETRA;
348 t = check_voxel(m.points_of_convex(cv)) ? N8_TO_VTK_VOXEL
349 : N8_TO_VTK_HEXAHEDRON;
350 else if (nbd == 20) t = N20_TO_VTK_QUADRATIC_HEXAHEDRON;
351 else if (nbd == 27) t = N27_TO_VTK_TRIQUADRATIC_HEXAHEDRON;
352 else if (nbd == 5) t = N5_TO_VTK_PYRAMID;
353 else if (nbd == 13) t = N13_TO_VTK_QUADRATIC_PYRAMID;
354 else if (nbd == 14) t = N14_TO_VTK_QUADRATIC_PYRAMID;
355 else if (nbd == 6) t = N6_TO_VTK_WEDGE;
356 else if (nbd == 15) t = N15_TO_VTK_QUADRATIC_WEDGE;
357 else if (nbd == 18) t = N18_TO_VTK_BIQUADRATIC_QUADRATIC_WEDGE;
360 GMM_ASSERT1(t != -1,
"semi internal error. Could not map " <<
362 <<
" to a VTK cell type");
363 pmf_mapping_type[cv] = t;
365 const std::vector<unsigned> &dmap = select_vtk_dof_mapping(t);
367 GMM_ASSERT1(dmap.size() <= pmf->nb_basic_dof_of_element(cv),
368 "inconsistency in vtk_dof_mapping");
369 for (
unsigned i=0; i < dmap.size(); ++i)
370 pmf_dof_used.add(pmf->ind_basic_dof_of_element(cv)[dmap[i]]);
377 const stored_mesh_slice& vtk_export::get_exported_slice()
const {
378 GMM_ASSERT1(psl,
"no slice!");
382 const mesh_fem& vtk_export::get_exported_mesh_fem()
const {
383 GMM_ASSERT1(pmf.get(),
"no mesh_fem!");
387 void vtk_export::set_header(
const std::string& s)
389 strncpy(header, s.c_str(), 256);
393 void vtk_export::check_header() {
394 if (state >= HEADER_WRITTEN)
return;
396 os <<
"# vtk DataFile Version 2.0\n";
397 os << header <<
"\n";
398 os << (ascii ?
"ASCII\n" :
"BINARY\n");
400 os <<
"<?xml version=\"1.0\"?>\n";
401 os <<
"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" ";
402 os <<
"byte_order=\"" << (reverse_endian ?
"LittleEndian" :
"BigEndian") <<
"\">\n";
403 os <<
"<!--" << header <<
"-->\n";
404 os <<
"<UnstructuredGrid>\n";
406 state = HEADER_WRITTEN;
409 void vtk_export::write_separ()
410 {
if (ascii) os <<
"\n"; }
412 void vtk_export::clear_vals()
413 {
if (!vtk && !ascii) vals.clear(); }
415 void vtk_export::write_vals() {
416 if (!vtk && !ascii) {
417 os << base64_encode(vals);
422 void vtk_export::write_mesh() {
423 if (psl) write_mesh_structure_from_slice();
424 else write_mesh_structure_from_mesh_fem();
428 void vtk_export::write_mesh_structure_from_slice() {
430 static int vtk_simplex_code[4] = { VTK_VERTEX, VTK_LINE, VTK_TRIANGLE, VTK_TETRA };
431 if (state >= STRUCTURE_WRITTEN)
return;
435 for (
size_type ic=0; ic < psl->nb_convex(); ++ic) {
436 for (
const slice_simplex &s : psl->simplexes(ic))
437 cells_cnt += s.dim() + 2;
438 splx_cnt += psl->simplexes(ic).size();
442 os <<
"DATASET UNSTRUCTURED_GRID\n";
443 os <<
"POINTS " << psl->nb_points() <<
" float\n";
445 os <<
"<Piece NumberOfPoints=\"" << psl->nb_points();
446 os <<
"\" NumberOfCells=\"" << splx_cnt <<
"\">\n";
448 os <<
"<DataArray type=\"Float32\" Name=\"Points\" ";
449 os <<
"NumberOfComponents=\"3\" ";
450 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
451 if (!ascii) write_val(
int(
sizeof(
float)*psl->nb_points()*3));
458 for (
size_type ic=0; ic < psl->nb_convex(); ++ic) {
459 for (
size_type i=0; i < psl->nodes(ic).size(); ++i)
460 write_vec(psl->nodes(ic)[i].pt.begin(),psl->nodes(ic)[i].pt.size());
465 os << (ascii ?
"" :
"\n") <<
"</DataArray>\n";
472 write_separ(); os <<
"CELLS " << splx_cnt <<
" " << cells_cnt <<
"\n";
475 os <<
"<DataArray type=\"Int32\" Name=\"connectivity\" ";
476 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
479 for (
size_type ic=0; ic < psl->nb_convex(); ++ic) {
480 for (
const slice_simplex &s : psl->simplexes(ic))
481 size +=
int((s.dim()+1)*
sizeof(int));
486 for (
size_type ic=0; ic < psl->nb_convex(); ++ic) {
487 for (
const slice_simplex &s : psl->simplexes(ic)) {
489 write_val(
int(s.dim()+1));
491 write_val(
int(s.inodes[j] + nodes_cnt));
494 nodes_cnt += psl->nodes(ic).size();
496 assert(nodes_cnt == psl->nb_points());
499 write_separ(); os <<
"CELL_TYPES " << splx_cnt <<
"\n";
501 os << (ascii ?
"" :
"\n") <<
"</DataArray>\n";
502 os <<
"<DataArray type=\"Int32\" Name=\"offsets\" ";
503 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
506 for (
size_type ic=0; ic < psl->nb_convex(); ++ic)
507 size +=
int(psl->simplexes(ic).size()*
sizeof(int));
512 for (
size_type ic=0; ic < psl->nb_convex(); ++ic) {
513 for (
const slice_simplex &s : psl->simplexes(ic))
515 write_val(
int(vtk_simplex_code[s.dim()]));
517 cnt += int(s.dim()+1);
521 splx_cnt -= psl->simplexes(ic).size();
524 assert(splx_cnt == 0);
526 os << (ascii ?
"" :
"\n") <<
"</DataArray>\n";
527 os <<
"<DataArray type=\"Int32\" Name=\"types\" ";
528 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
531 for (
size_type ic=0; ic < psl->nb_convex(); ++ic)
532 size +=
int(psl->simplexes(ic).size()*
sizeof(int));
535 for (
size_type ic=0; ic < psl->nb_convex(); ++ic)
536 for (
const slice_simplex &s : psl->simplexes(ic))
537 write_val(
int(vtk_simplex_code[s.dim()]));
539 os <<
"\n" <<
"</DataArray>\n";
542 state = STRUCTURE_WRITTEN;
546 void vtk_export::write_mesh_structure_from_mesh_fem() {
547 if (state >= STRUCTURE_WRITTEN)
return;
551 os <<
"DATASET UNSTRUCTURED_GRID\n";
552 os <<
"POINTS " << pmf_dof_used.card() <<
" float\n";
554 os <<
"<Piece NumberOfPoints=\"" << pmf_dof_used.card()
555 <<
"\" NumberOfCells=\"" << pmf->convex_index().card() <<
"\">\n";
557 os <<
"<DataArray type=\"Float32\" Name=\"Points\" ";
558 os <<
"NumberOfComponents=\"3\" ";
559 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
560 if (!ascii) write_val(
int(
sizeof(
float)*pmf_dof_used.card()*3));
562 std::vector<int> dofmap(pmf->nb_dof());
564 for (dal::bv_visitor d(pmf_dof_used); !d.finished(); ++d) {
566 base_node P = pmf->point_of_basic_dof(d);
567 write_vec(P.const_begin(),P.size());
573 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv)
574 nb_cell_values += (1 + select_vtk_dof_mapping(pmf_mapping_type[cv]).size());
578 os <<
"CELLS " << pmf->convex_index().card() <<
" " << nb_cell_values <<
"\n";
580 os << (ascii ?
"" :
"\n") <<
"</DataArray>\n";
583 os <<
"<DataArray type=\"Int32\" Name=\"connectivity\" ";
584 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
587 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
588 const std::vector<unsigned> &dmap = select_vtk_dof_mapping(pmf_mapping_type[cv]);
589 size += int(
sizeof(
int)*dmap.size());
595 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
596 const std::vector<unsigned> &dmap = select_vtk_dof_mapping(pmf_mapping_type[cv]);
597 if (vtk) write_val(
int(dmap.size()));
598 for (
size_type i=0; i < dmap.size(); ++i)
599 write_val(
int(dofmap[pmf->ind_basic_dof_of_element(cv)[dmap[i]]]));
606 os <<
"CELL_TYPES " << pmf->convex_index().card() <<
"\n";
608 os << (ascii ?
"" :
"\n") <<
"</DataArray>\n";
609 os <<
"<DataArray type=\"Int32\" Name=\"offsets\" ";
610 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
612 write_val(
int(pmf->convex_index().card()*
sizeof(
int)));
614 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
615 const std::vector<unsigned> &dmap = select_vtk_dof_mapping(pmf_mapping_type[cv]);
616 cnt += int(dmap.size());
620 os <<
"\n" <<
"</DataArray>\n";
621 os <<
"<DataArray type=\"Int32\" Name=\"types\" ";
622 os << (ascii ?
"format=\"ascii\">\n" :
"format=\"binary\">\n");
624 write_val(
int(pmf->convex_index().card()*
sizeof(
int)));
626 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
627 write_val(
int(select_vtk_type(pmf_mapping_type[cv])));
628 if (vtk) write_separ();
631 if (!vtk) os <<
"\n" <<
"</DataArray>\n" <<
"</Cells>\n";
633 state = STRUCTURE_WRITTEN;
636 void vtk_export::write_mesh_quality(
const mesh &m) {
640 std::vector<scalar_type> q(mf.
nb_dof());
644 write_point_data(mf, q,
"convex_quality");
646 std::vector<scalar_type> q(pmf->convex_index().card());
647 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
650 write_cell_data(q,
"convex_quality");
659 dx_export::dx_export(std::ostream &os_,
bool ascii_)
660 : os(os_), ascii(ascii_) { init(); }
662 dx_export::dx_export(
const std::string& fname,
bool ascii_,
bool append_)
663 : os(real_os), ascii(ascii_) {
664 real_os.open(fname.c_str(),
665 std::ios_base::openmode(std::ios_base::in |
667 (append_ ? std::ios_base::ate : std::ios_base::trunc)));
668 GMM_ASSERT1(real_os.good(),
"impossible to write to dx file '"
671 if (append_) { reread_metadata(); header_written =
true; }
674 dx_export::~dx_export() {
675 std::ios::pos_type p = os.tellp();
677 os <<
"\n# --end of getfem export\nend\n";
681 void dx_export::init() {
682 strcpy(header,
"Exported by GetFEM");
683 psl = 0; dim_ = dim_type(-1); connections_dim = dim_type(-1);
684 psl_use_merged =
false;
685 header_written =
false;
688 void dx_export::write_separ()
689 {
if (ascii) os <<
"\n"; }
691 template<
typename T>
static typename std::list<T>::iterator
692 get_from_name(std::list<T> &c,
693 const std::string& name,
bool raise_error) {
694 for (
typename std::list<T>::iterator it = c.begin();
695 it != c.end(); ++it) {
696 if (it->name == name)
return it;
698 GMM_ASSERT1(!raise_error,
"object not found in dx file: " << name);
702 std::list<dx_export::dxMesh>::iterator
703 dx_export::get_mesh(
const std::string& name,
bool raise_error) {
704 return get_from_name(meshes,name,raise_error);
706 std::list<dx_export::dxObject>::iterator
707 dx_export::get_object(
const std::string& name,
bool raise_error) {
708 return get_from_name(objects,name,raise_error);
712 bool dx_export::new_mesh(std::string &name) {
713 name = default_name(name,
int(meshes.size()),
"mesh");
714 std::list<dxMesh>::iterator it = get_mesh(name,
false);
715 if (it != meshes.end()) {
716 if (&(*it) != ¤t_mesh())
717 std::swap(current_mesh(),*it);
720 meshes.push_back(dxMesh()); meshes.back().name = name;
725 void dx_export::exporting(
const stored_mesh_slice& sl,
bool merge_points,
727 if (!new_mesh(name))
return;
728 psl_use_merged = merge_points;
729 if (merge_points) sl.merge_nodes();
730 psl = &sl; dim_ = dim_type(sl.dim());
731 GMM_ASSERT1(psl->
dim() <= 3,
"4D slices and more are not supported");
732 for (dim_type d = 0; d <= psl->
dim(); ++d) {
734 if (connections_dim == dim_type(-1)) connections_dim = d;
735 else GMM_ASSERT1(
false,
"Cannot export a slice containing "
736 "simplexes of different dimensions");
739 GMM_ASSERT1(connections_dim != dim_type(-1),
"empty slice!");
743 void dx_export::exporting(
const mesh_fem& mf, std::string name) {
744 name = default_name(name,
int(meshes.size()),
"mesh");
745 if (!new_mesh(name))
return;
746 const mesh &m = mf.linked_mesh();
747 GMM_ASSERT1(mf.linked_mesh().convex_index().card() != 0,
748 "won't export an empty mesh");
751 GMM_ASSERT1(dim_ <= 3,
"4D meshes and more are not supported");
752 if (&mf != pmf.get())
753 pmf = std::make_unique<mesh_fem>(
const_cast<mesh&
>(m), dim_type(1));
755 GMM_ASSERT1(dxname_of_convex_structure
757 "DX Cannot handle " <<
760 for (dal::bv_visitor cv(mf.convex_index()); !cv.finished(); ++cv) {
764 "Cannot export this mesh to opendx, it contains "
765 "different convex types. Slice it first.");
766 pfem pf = mf.fem_of_element(cv);
767 bool discontinuous =
false;
768 for (
unsigned i=0; i < pf->nb_dof(cv); ++i) {
770 if (!
dof_linkable(pf->dof_types()[i])) { discontinuous =
true;
break; }
774 pmf->set_finite_element(cv, classical_pf1);
776 pmf_dof_used.add(0, pmf->nb_basic_dof());
777 connections_dim = dim_type(pmf->nb_basic_dof_of_element(m.convex_index().first_true()));
780 void dx_export::exporting(
const mesh& m, std::string name) {
782 GMM_ASSERT1(dim_ <= 3,
"4D meshes and more are not supported");
783 pmf = std::make_unique<mesh_fem>(
const_cast<mesh&
>(m), dim_type(1));
784 pmf->set_classical_finite_element(1);
785 exporting(*pmf, name);
788 void dx_export::write_series() {
789 for (std::list<dxSeries>::const_iterator it = series.begin();
790 it != series.end(); ++it) {
791 if (it->members.size() == 0)
continue;
793 os <<
"\nobject \"" << it->name <<
"\" class series\n";
794 for (std::list<std::string>::const_iterator ito = it->members.begin();
795 ito != it->members.end(); ++ito, ++count) {
796 os <<
" member " << count <<
" \"" << (*ito) <<
"\"\n";
801 void dx_export::serie_add_object_(
const std::string &serie_name,
802 const std::string &object_name) {
803 std::list<dxSeries>::iterator it = series.begin();
804 while (it != series.end() && it->name != serie_name) ++it;
805 if (it == series.end()) {
806 series.push_back(dxSeries()); it = series.end(); --it;
807 it->name = serie_name;
809 it->members.push_back(object_name);
813 const std::string &object_name) {
816 std::list<dxObject>::iterator ito = get_object(object_name,
false);
817 if (ito != objects.end()) {
818 std::list<dxMesh>::iterator itm = get_mesh(ito->mesh);
819 if (itm != meshes.end() && (itm->flags & dxMesh::WITH_EDGES)) {
820 serie_add_object_(serie_name +
"_edges",
821 object_name +
"_edges");
825 serie_add_object_(serie_name, object_name);
829 { strncpy(header, s.c_str(), 256); header[255] = 0; }
831 void dx_export::check_header() {
832 if (header_written)
return;
833 header_written =
true;
834 os <<
"# data file for IBM OpenDX, generated by GetFem++ v "
835 << GETFEM_VERSION <<
"\n";
836 os <<
"# " << header <<
"\n";
839 void dx_export::update_metadata(std::ios::pos_type pos_series) {
840 os.seekp(0,std::ios::end);
841 os <<
"# This file contains the following objects\n";
842 std::ios::pos_type pos_end = os.tellp();
843 for (std::list<dxSeries>::const_iterator it = series.begin();
844 it != series.end(); ++it) {
845 os <<
"#S \"" << it->name <<
"\" which contains:\n";
846 for (std::list<std::string>::const_iterator its = it->members.begin();
847 its != it->members.end(); ++its)
848 os <<
"#+ \"" << *its <<
"\"\n";
850 for (std::list<dxObject>::const_iterator it = objects.begin();
851 it != objects.end(); ++it) {
852 os <<
"#O \"" << it->name <<
"\" \"" << it->mesh <<
"\"\n";
854 for (std::list<dxMesh>::const_iterator it = meshes.begin();
855 it != meshes.end(); ++it) {
856 os <<
"#M \"" << it->name <<
"\" " << it->flags <<
"\n";
858 os <<
"#E \"THE_END\" " << std::setw(20) << pos_series << std::setw(20) << pos_end <<
"\n";
861 void dx_export::reread_metadata() {
863 real_os.seekg(0, std::ios::end);
865 unsigned long lu_end, lu_series;
867 real_os.seekg(-1, std::ios::cur);
868 c = char(real_os.peek());
869 }
while (++count < 512 && c !=
'#');
870 real_os.getline(line,
sizeof line);
871 if (sscanf(line,
"#E \"THE_END\" %lu %lu", &lu_series, &lu_end) != 2)
872 GMM_ASSERT1(
false,
"this file was not generated by getfem, "
873 "cannot append data to it!\n");
874 real_os.seekg(lu_end, std::ios::beg);
876 char name[512];
unsigned n;
878 real_os.getline(line,
sizeof line);
879 if (sscanf(line,
"#%c \"%512[^\"]\"%n", &c, name, &pos) < 1)
880 GMM_ASSERT1(
false,
"corrupted file! your .dx file is broken\n");
882 series.push_back(dxSeries()); series.back().name = name;
883 }
else if (c ==
'+') {
884 series.back().members.push_back(name);
885 }
else if (c ==
'O') {
886 objects.push_back(dxObject()); objects.back().name = name;
887 sscanf(line+pos,
" \"%512[^\"]\"", name); objects.back().mesh = name;
888 }
else if (c ==
'M') {
889 meshes.push_back(dxMesh()); meshes.back().name = name;
890 sscanf(line+pos,
"%u", &n); meshes.back().flags = n;
891 }
else if (c ==
'E') {
893 }
else GMM_ASSERT1(
false,
"corrupted file! your .dx file is broken\n");
895 real_os.seekp(lu_series, std::ios::beg);
899 const char *s_elem_type = dxname_of_convex_structure(cvs);
901 GMM_WARNING1(
"OpenDX won't handle this kind of convexes");
902 os <<
"\n attribute \"element type\" string \"" << s_elem_type <<
"\"\n"
903 <<
" attribute \"ref\" string \"positions\"\n\n";
907 const char *s_elem_type = 0;
908 switch (cvs->dim()) {
910 case 1: s_elem_type =
"lines";
break;
912 if (cvs->nb_points() == 3)
913 s_elem_type =
"triangles";
914 else if (cvs->nb_points() == 4)
915 s_elem_type =
"quads";
918 if (cvs->nb_points() == 4)
919 s_elem_type =
"tetrahedra";
920 else if (cvs->nb_points() == 8)
921 s_elem_type =
"cubes";
927 void dx_export::write_mesh() {
929 if (current_mesh().flags & dxMesh::STRUCTURE_WRITTEN)
return;
930 if (psl) write_mesh_structure_from_slice();
931 else write_mesh_structure_from_mesh_fem();
934 <<
" component \"positions\" value \""
936 <<
" component \"connections\" value \""
938 current_mesh().flags |= dxMesh::STRUCTURE_WRITTEN;
942 void dx_export::write_mesh_structure_from_slice() {
944 <<
"\" class array type float rank 1 shape "
947 if (!ascii) os <<
" " << endianness() <<
" binary";
948 os <<
" data follows\n";
949 if (psl_use_merged) {
959 write_val(
float(psl->
nodes(ic)[i].pt[k]));
965 <<
"\" class array type int rank 1 shape "
966 << int(connections_dim+1)
968 if (!ascii) os <<
" " << endianness() <<
" binary";
969 os <<
" data follows\n";
973 for (
const slice_simplex &s : psl->
simplexes(ic)) {
974 if (s.dim() == connections_dim) {
975 for (
size_type j=0; j < s.dim()+1; ++j) {
978 k = psl->merged_index(ic, s.inodes[j]);
979 else k = psl->global_index(ic, s.inodes[j]);
985 nodes_cnt += psl->
nodes(ic).size();
992 void dx_export::write_mesh_structure_from_mesh_fem() {
994 <<
"\" class array type float rank 1 shape "
995 << int(pmf->linked_mesh().dim())
996 <<
" items " << pmf->nb_dof();
997 if (!ascii) os <<
" " << endianness() <<
" binary";
998 os <<
" data follows\n";
1001 for (
size_type d = 0; d < pmf->nb_basic_dof(); ++d) {
1002 const base_node P = pmf->point_of_basic_dof(d);
1004 write_val(
float(P[k]));
1009 <<
"\" class array type int rank 1 shape "
1010 << int(connections_dim)
1011 <<
" items " << pmf->convex_index().card();
1012 if (!ascii) os <<
" " << endianness() <<
" binary";
1013 os <<
" data follows\n";
1015 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
1016 for (
size_type i=0; i < connections_dim; ++i)
1017 write_val(
int(pmf->ind_basic_dof_of_element(cv)[i]));
1020 write_convex_attributes(
basic_structure(pmf->linked_mesh().structure_of_convex(pmf->convex_index().first_true())));
1025 if (current_mesh().flags & dxMesh::WITH_EDGES)
return;
1026 if (psl) write_mesh_edges_from_slice(with_slice_edges);
1027 else write_mesh_edges_from_mesh();
1028 current_mesh().flags |= dxMesh::WITH_EDGES;
1030 <<
"\" class field\n"
1031 <<
" component \"positions\" value \""
1033 <<
" component \"connections\" value \""
1038 void dx_export::write_mesh_edges_from_slice(
bool with_slice_edges) {
1039 std::vector<size_type> edges;
1040 dal::bit_vector slice_edges;
1041 psl->
get_edges(edges, slice_edges, psl_use_merged);
1042 if (with_slice_edges) slice_edges.clear();
1045 <<
"\" class array type int rank 1 shape 2"
1046 <<
" items " << edges.size()/2 - slice_edges.card();
1047 if (!ascii) os <<
" " << endianness() <<
" binary";
1048 os <<
" data follows\n";
1049 for (
size_type i=0; i < edges.size()/2; ++i) {
1050 if (!slice_edges.is_in(i)) {
1051 write_val(
int(edges[2*i]));
1052 write_val(
int(edges[2*i+1]));
1054 if ((i+1)%10 == 0) write_separ();
1060 void dx_export::write_mesh_edges_from_mesh() {
1064 <<
"\" class array type int rank 1 shape 2"
1065 <<
" items " << ms.convex_index().card();
1066 if (!ascii) os <<
" " << endianness() <<
" binary";
1067 os <<
" data follows\n";
1068 for (dal::bv_visitor cv(ms.convex_index()); !cv.finished(); ++cv) {
1069 write_val(
int(ms.ind_points_of_convex(cv)[0]));
1070 write_val(
int(ms.ind_points_of_convex(cv)[1]));
1071 if ((cv+1)%20 == 0) write_separ();
1081 struct gf2pos_dof_mapping :
public std::vector<std::vector<unsigned> > {};
1083 static const std::vector<unsigned>& getfem_to_pos_dof_mapping(
int t) {
1085 if (dm.size() == 0) {
1087 dm[pos_export::POS_PT] = {0};
1088 dm[pos_export::POS_LN] = {0, 1};
1089 dm[pos_export::POS_TR] = {0, 1, 2};
1090 dm[pos_export::POS_QU] = {0, 1, 3, 2};
1091 dm[pos_export::POS_SI] = {0, 1, 2, 3};
1092 dm[pos_export::POS_HE] = {0, 1, 3, 2, 4, 5, 7, 6};
1093 dm[pos_export::POS_PR] = {0, 1, 2, 3, 4, 5};
1094 dm[pos_export::POS_PY] = {0, 1, 3, 2, 4};
1099 pos_export::pos_export(std::ostream& osname): os(osname) {
1103 pos_export::pos_export(
const std::string& fname)
1104 : os(real_os), real_os(fname.c_str()) {
1105 GMM_ASSERT1(real_os,
"impossible to write to pos file '" << fname <<
"'");
1109 void pos_export::init() {
1110 strcpy(header,
"Exported by GetFEM");
1115 void pos_export::set_header(
const std::string& s){
1116 strncpy(header, s.c_str(), 256);
1120 void pos_export::check_header() {
1121 if (state >= HEADER_WRITTEN)
return;
1122 os <<
"/* " << header <<
" */\n";
1123 os <<
"General.FastRedraw = 0;\n";
1124 os <<
"General.ColorScheme = 1;\n";
1125 state = HEADER_WRITTEN;
1128 void pos_export::exporting(
const mesh& m) {
1129 if (state >= STRUCTURE_WRITTEN)
return;
1130 dim = dim_type(m.dim());
1131 GMM_ASSERT1(
int(dim) <= 3,
"attempt to export a "
1132 <<
int(dim) <<
"D mesh (not supported)");
1133 pmf = std::make_unique<mesh_fem>(
const_cast<mesh&
>(m), dim_type(1));
1134 pmf->set_classical_finite_element(1);
1136 state = STRUCTURE_WRITTEN;
1139 void pos_export::exporting(
const mesh_fem& mf) {
1140 if (state >= STRUCTURE_WRITTEN)
return;
1141 dim = dim_type(mf.linked_mesh().dim());
1142 GMM_ASSERT1(
int(dim) <= 3,
"attempt to export a "
1143 <<
int(dim) <<
"D mesh_fem (not supported)");
1144 if (&mf != pmf.get())
1145 pmf = std::make_unique<mesh_fem>(mf.linked_mesh(), dim_type(1));
1148 for (dal::bv_visitor cv(mf.convex_index()); !cv.finished(); ++cv) {
1150 pfem pf = mf.fem_of_element(cv);
1152 bool discontinuous =
false;
1153 for (
unsigned i=0; i < pf->nb_dof(cv); ++i) {
1155 if (!
dof_linkable(pf->dof_types()[i])) { discontinuous =
true;
break; }
1157 pfem classical_pf1 = discontinuous ?
1159 pmf->set_finite_element(cv, classical_pf1);
1164 for (dal::bv_visitor cv(pmf->convex_index()); !cv.finished(); ++cv) {
1166 switch (pmf->fem_of_element(cv)->nb_dof(cv)){
1167 case 1: t = POS_PT;
break;
1168 case 2: t = POS_LN;
break;
1169 case 3: t = POS_TR;
break;
1171 if ( 2 == pmf->fem_of_element(cv)->dim() ) t = POS_QU;
1172 else if (3 == pmf->fem_of_element(cv)->dim()) t = POS_SI;
1174 case 6: t = POS_PR;
break;
1175 case 8: t = POS_HE;
break;
1176 case 5: t = POS_PY;
break;
1178 GMM_ASSERT1(t != -1,
"semi internal error. Could not map "
1180 <<
" to a POS primitive type");
1181 pos_cell_type.push_back(
unsigned(t));
1183 const std::vector<unsigned>& dmap = getfem_to_pos_dof_mapping(t);
1184 GMM_ASSERT1(dmap.size() <= pmf->nb_basic_dof_of_element(cv),
1185 "inconsistency in pos_dof_mapping");
1186 std::vector<unsigned> cell_dof;
1187 cell_dof.resize(dmap.size(),
unsigned(-1));
1188 for (
size_type i=0; i < dmap.size(); ++i)
1189 cell_dof[i] =
unsigned(pmf->ind_basic_dof_of_element(cv)[dmap[i]]);
1190 pos_cell_dof.push_back(cell_dof);
1192 for (
size_type i=0; i< pmf->nb_basic_dof(); ++i){
1193 std::vector<float> pt;
1194 pt.resize(dim,
float(0));
1196 pt[j] =
float(pmf->point_of_basic_dof(i)[j]);
1197 pos_pts.push_back(pt);
1199 state = STRUCTURE_WRITTEN;
1202 void pos_export::exporting(
const stored_mesh_slice& sl) {
1203 if (state >= STRUCTURE_WRITTEN)
return;
1205 dim = dim_type(sl.dim());
1206 GMM_ASSERT1(
int(dim) <= 3,
"attempt to export a "
1207 <<
int(dim) <<
"D slice (not supported)");
1210 for (
const slice_simplex &s : psl->
simplexes(ic)) {
1213 case 0: t = POS_PT;
break;
1214 case 1: t = POS_LN;
break;
1215 case 2: t = POS_TR;
break;
1216 case 3: t = POS_SI;
break;
1218 GMM_ASSERT1(t != -1,
"semi internal error.. could not map to a POS primitive type");
1219 pos_cell_type.push_back(
unsigned(t));
1221 const std::vector<unsigned>& dmap = getfem_to_pos_dof_mapping(t);
1222 GMM_ASSERT1(dmap.size() <=
size_type(t+1),
"inconsistency in pos_dof_mapping");
1224 std::vector<unsigned> cell_dof;
1225 cell_dof.resize(dmap.size(),
unsigned(-1));
1226 for (
size_type i=0; i < dmap.size(); ++i)
1227 cell_dof[i] =
unsigned(s.inodes[dmap[i]] + pcnt);
1228 pos_cell_dof.push_back(cell_dof);
1230 for (
const slice_node &n : psl->
nodes(ic)) {
1231 std::vector<float> pt;
1232 pt.resize(dim,
float(0));
1234 pt[i] =
float(n.pt[i]);
1235 pos_pts.push_back(pt);
1237 pcnt += psl->
nodes(ic).size();
1239 state = STRUCTURE_WRITTEN;
1242 void pos_export::write(
const mesh& m,
const std::string &name){
1243 if (state >= IN_CELL_DATA)
return;
1244 GMM_ASSERT1(
int(m.dim()) <= 3,
"attempt to export a "
1245 <<
int(m.dim()) <<
"D mesh (not supported)");
1246 pmf = std::make_unique<mesh_fem>(
const_cast<mesh&
>(m), dim_type(1));
1247 pmf->set_classical_finite_element(1);
1249 state = IN_CELL_DATA;
1252 void pos_export::write(
const mesh_fem& mf,
const std::string &name){
1253 if (state >= IN_CELL_DATA)
return;
1257 if (
""==name) os <<
"View \"mesh " << view <<
"\" {\n";
1258 else os <<
"View \"" << name <<
"\" {\n";
1261 std::vector<unsigned> cell_dof;
1262 std::vector<float> cell_dof_val;
1263 for (
size_type cell = 0; cell < pos_cell_type.size(); ++cell) {
1264 t = pos_cell_type[cell];
1265 cell_dof = pos_cell_dof[cell];
1266 cell_dof_val.resize(cell_dof.size(),
float(0));
1267 write_cell(t,cell_dof,cell_dof_val);
1271 os <<
"View[" << view <<
"].ShowScale = 0;\n";
1272 os <<
"View[" << view <<
"].ShowElement = 1;\n";
1273 os <<
"View[" << view <<
"].DrawScalars = 0;\n";
1274 os <<
"View[" << view <<
"].DrawVectors = 0;\n";
1275 os <<
"View[" << view++ <<
"].DrawTensors = 0;\n";
1276 state = IN_CELL_DATA;
1279 void pos_export::write(
const stored_mesh_slice& sl,
const std::string &name){
1280 if (state >= IN_CELL_DATA)
return;
1284 if (
""==name) os <<
"View \"mesh " << view <<
"\" {\n";
1285 else os <<
"View \"" << name <<
"\" {\n";
1288 std::vector<unsigned> cell_dof;
1289 std::vector<float> cell_dof_val;
1290 for (
size_type cell = 0; cell < pos_cell_type.size(); ++cell) {
1291 t = pos_cell_type[cell];
1292 cell_dof = pos_cell_dof[cell];
1293 cell_dof_val.resize(cell_dof.size(),
float(0));
1294 write_cell(t,cell_dof,cell_dof_val);
1298 os <<
"View[" << view <<
"].ShowScale = 0;\n";
1299 os <<
"View[" << view <<
"].ShowElement = 1;\n";
1300 os <<
"View[" << view <<
"].DrawScalars = 0;\n";
1301 os <<
"View[" << view <<
"].DrawVectors = 0;\n";
1302 os <<
"View[" << view++ <<
"].DrawTensors = 0;\n";
1303 state = IN_CELL_DATA;