MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
conduitdatacollection.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "../config/config.hpp"
13
14#ifdef MFEM_USE_CONDUIT
15
16#include "fem.hpp"
17#include "../general/text.hpp"
18#include <conduit_relay.hpp>
19#include <conduit_blueprint.hpp>
20
21#include <string>
22#include <sstream>
23
24using namespace conduit;
25
26namespace mfem
27{
28
29//---------------------------------------------------------------------------//
30// class ConduitDataCollection implementation
31//---------------------------------------------------------------------------//
32
33//------------------------------
34// begin public methods
35//------------------------------
36
37//---------------------------------------------------------------------------//
39 Mesh *mesh)
40 : DataCollection(coll_name, mesh),
41 relay_protocol("hdf5")
42{
43 appendRankToFileName = true; // always include rank in file names
44 cycle = 0; // always include cycle in directory names
45}
46
47#ifdef MFEM_USE_MPI
48//---------------------------------------------------------------------------//
50 const std::string& coll_name,
51 Mesh *mesh)
52 : DataCollection(coll_name, mesh),
53 relay_protocol("hdf5")
54{
55 m_comm = comm;
56 MPI_Comm_rank(comm, &myid);
57 MPI_Comm_size(comm, &num_procs);
58 appendRankToFileName = true; // always include rank in file names
59 cycle = 0; // always include cycle in directory names
60}
61#endif
62
63//---------------------------------------------------------------------------//
68
69//---------------------------------------------------------------------------//
71{
72 std::string dir_name = MeshDirectoryName();
73 int err_ = create_directory(dir_name, mesh, myid);
74 if (err_)
75 {
76 MFEM_ABORT("Error creating directory: " << dir_name);
77 }
78
79 Node n_mesh;
80 // future? If moved into Mesh class
81 // mesh->toConduitBlueprint(n_mesh);
83
84 Node verify_info;
85 if (!blueprint::mesh::verify(n_mesh,verify_info))
86 {
87 MFEM_ABORT("Conduit Mesh Blueprint Verify Failed:\n"
88 << verify_info.to_json());
89 }
90
91 // wrap all grid functions
93 for ( itr = field_map.begin(); itr != field_map.end(); itr++)
94 {
95 std::string name = itr->first;
96 GridFunction *gf = itr->second;
97 // don't save mesh nodes twice ...
98 if ( gf != mesh->GetNodes())
99 {
100 // future? If moved into GridFunction class
101 //gf->toConduitBlueprint(n_mesh["fields"][it->first]);
103 n_mesh["fields"][name]);
104 }
105 }
106
107 // wrap all quadrature functions
109 for ( qf_itr = q_field_map.begin(); qf_itr != q_field_map.end(); qf_itr++)
110 {
111 std::string name = qf_itr->first;
112 QuadratureFunction *qf = qf_itr->second;
114 n_mesh["fields"][name]);
115 }
116
117 // TODO: in parallel, we need to call ParFiniteElementSpace::ApplyDofSigns
118 // for all ParGridFunction objects before and after saving, see
119 // ParGridFunction::Save.
120
121 // save mesh data
123 n_mesh,
125
126 if (myid == 0)
127 {
128 // save root file
130 n_mesh,
132 }
133}
134
135//---------------------------------------------------------------------------//
137{
138 DeleteAll();
139 this->cycle = cycle;
140
141 // Note: We aren't currently using much info from the root file ...
142 // with cycle, we can use implicit mfem conduit file layout
143
144 Node n_root;
145 LoadRootFile(n_root);
146 relay_protocol = n_root["protocol/name"].as_string();
147
148 // for MPI case, we assume that we have # of mpi tasks
149 // == number of domains
150
151 int num_domains = n_root["number_of_trees"].to_int();
152
153 if (num_procs != num_domains)
154 {
156 MFEM_WARNING("num_procs must equal num_domains");
157 return;
158 }
159
160 // load the mesh and fields
162
163 // TODO: am I properly wielding this?
164 own_data = true;
165
166}
167
168//---------------------------------------------------------------------------//
169void
170ConduitDataCollection::SetProtocol(const std::string &protocol)
171{
172 relay_protocol = protocol;
173}
174
175// Conduit data type id for the MFEM precision
176constexpr conduit::index_t mfem_precision_conduit_id =
177#if defined(MFEM_USE_DOUBLE)
178 CONDUIT_NATIVE_DOUBLE_ID;
179#elif defined(MFEM_USE_SINGLE)
181#else
182#error Unknown MFEM precision
183#endif
184
185//------------------------------
186// begin static public methods
187//------------------------------
188
189//---------------------------------------------------------------------------//
192 const std::string &main_toplogy_name,
193 bool zero_copy)
194{
195 // n_conv holds converted data (when necessary for mfem api)
196 // if n_conv is used ( !n_conv.dtype().empty() ) we
197 // now that some data allocation was necessary, so we
198 // can't return a mesh that zero copies the conduit data
199 Node n_conv;
200
201 //
202 // we need to find the topology and its coordset.
203 //
204
205 std::string topo_name = main_toplogy_name;
206 // if topo name is not set, look for first topology
207 if (topo_name == "")
208 {
209 topo_name = n_mesh["topologies"].schema().child_name(0);
210 }
211
212 MFEM_ASSERT(n_mesh.has_path("topologies/" + topo_name),
213 "Expected topology named \"" + topo_name + "\" "
214 "(node is missing path \"topologies/" + topo_name + "\")");
215
216 // find the coord set
217 std::string coords_name =
218 n_mesh["topologies"][topo_name]["coordset"].as_string();
219
220
221 MFEM_ASSERT(n_mesh.has_path("coordsets/" + coords_name),
222 "Expected topology named \"" + coords_name + "\" "
223 "(node is missing path \"coordsets/" + coords_name + "\")");
224
225 const Node &n_coordset = n_mesh["coordsets"][coords_name];
226 const Node &n_coordset_vals = n_coordset["values"];
227
228 // get the number of dims of the coordset
229 int ndims = n_coordset_vals.number_of_children();
230
231 // get the number of points
232 int num_verts = n_coordset_vals[0].dtype().number_of_elements();
233 // get vals for points
234 const real_t *verts_ptr = NULL;
235
236 // the mfem mesh constructor needs coords with interleaved (aos) type
237 // ordering, even for 1d + 2d we always need 3 real_t (double/float) b/c it
238 // uses Array<Vertex> and Vertex is a pod of 3 real_t. we check for this
239 // case, if we don't have it we convert the data
240
241 if (ndims == 3 &&
242 n_coordset_vals[0].dtype().id() == mfem_precision_conduit_id &&
243 blueprint::mcarray::is_interleaved(n_coordset_vals) )
244 {
245 // already interleaved mcarray of 3 real_t (double/float),
246 // return ptr to beginning
247 verts_ptr = n_coordset_vals[0].value();
248 }
249 else
250 {
251 Node n_tmp;
252 // check all vals, if we don't have real_t (double/float) convert
253 // to real_t
254 NodeConstIterator itr = n_coordset_vals.children();
255 while (itr.has_next())
256 {
257 const Node &c_vals = itr.next();
258 std::string c_name = itr.name();
259
260 if ( c_vals.dtype().id() == mfem_precision_conduit_id )
261 {
262 // zero copy current coords
263 n_tmp[c_name].set_external(c_vals);
264 }
265 else
266 {
267 // convert
268 c_vals.to_data_type(mfem_precision_conduit_id, n_tmp[c_name]);
269 }
270 }
271
272 // check if we need to add extra dims to get
273 // proper interleaved array
274 if (ndims < 3)
275 {
276 // add dummy z
277 n_tmp["z"].set(DataType(mfem_precision_conduit_id, num_verts));
278 }
279
280 if (ndims < 2)
281 {
282 // add dummy y
283 n_tmp["y"].set(DataType(mfem_precision_conduit_id, num_verts));
284 }
285
286 Node &n_conv_coords_vals = n_conv["coordsets"][coords_name]["values"];
287 blueprint::mcarray::to_interleaved(n_tmp,
288 n_conv_coords_vals);
289 verts_ptr = n_conv_coords_vals[0].value();
290 }
291
292
293
294 const Node &n_mesh_topo = n_mesh["topologies"][topo_name];
295 std::string mesh_ele_shape = n_mesh_topo["elements/shape"].as_string();
296
297 mfem::Geometry::Type mesh_geo = ShapeNameToGeomType(mesh_ele_shape);
298 int num_idxs_per_ele = Geometry::NumVerts[mesh_geo];
299
300 const Node &n_mesh_conn = n_mesh_topo["elements/connectivity"];
301
302 const int *elem_indices = NULL;
303 // mfem requires ints, we could have int64s, etc convert if necessary
304 if (n_mesh_conn.dtype().is_int() &&
305 n_mesh_conn.is_compact() )
306 {
307 elem_indices = n_mesh_topo["elements/connectivity"].value();
308 }
309 else
310 {
311 Node &n_mesh_conn_conv=
312 n_conv["topologies"][topo_name]["elements/connectivity"];
313 n_mesh_conn.to_int_array(n_mesh_conn_conv);
314 elem_indices = n_mesh_conn_conv.value();
315 }
316
317 int num_mesh_ele =
318 n_mesh_topo["elements/connectivity"].dtype().number_of_elements();
319 num_mesh_ele = num_mesh_ele / num_idxs_per_ele;
320
321
322 const int *bndry_indices = NULL;
323 int num_bndry_ele = 0;
324 // init to something b/c the mesh constructor will use this for a
325 // table lookup, even if we don't have boundary info.
327
328 if ( n_mesh_topo.has_child("boundary_topology") )
329 {
330 std::string bndry_topo_name = n_mesh_topo["boundary_topology"].as_string();
331
332 // In VisIt, we encountered a case were a mesh specified a boundary
333 // topology, but the boundary topology was omitted from the blueprint
334 // index, so it's data could not be obtained.
335 //
336 // This guard prevents an error in that case, allowing the mesh to be
337 // created without boundary info
338
339 if (n_mesh["topologies"].has_child(bndry_topo_name))
340 {
341 const Node &n_bndry_topo = n_mesh["topologies"][bndry_topo_name];
342 std::string bndry_ele_shape = n_bndry_topo["elements/shape"].as_string();
343
344 bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
345 int num_idxs_per_bndry_ele = Geometry::NumVerts[mesh_geo];
346
347 const Node &n_bndry_conn = n_bndry_topo["elements/connectivity"];
348
349 // mfem requires ints, we could have int64s, etc convert if necessary
350 if ( n_bndry_conn.dtype().is_int() &&
351 n_bndry_conn.is_compact())
352 {
353 bndry_indices = n_bndry_conn.value();
354 }
355 else
356 {
357 Node &n_bndry_conn_conv =
358 n_conv["topologies"][bndry_topo_name]["elements/connectivity"];
359 n_bndry_conn.to_int_array(n_bndry_conn_conv);
360 bndry_indices = (n_bndry_conn_conv).value();
361
362 }
363
364 num_bndry_ele =
365 n_bndry_topo["elements/connectivity"].dtype().number_of_elements();
366 num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
367 }
368 }
369 else
370 {
371 // Skipping Boundary Element Data
372 }
373
374 const int *mesh_atts = NULL;
375 const int *bndry_atts = NULL;
376
377 // These variables are used in debug code below.
378 // int num_mesh_atts_entires = 0;
379 // int num_bndry_atts_entires = 0;
380
381 // the attribute fields could have several names
382 // for the element attributes check for first occurrence of field with
383 // name containing "_attribute", that doesn't contain "boundary"
384 std::string main_att_name = "";
385
386 const Node &n_fields = n_mesh["fields"];
387 NodeConstIterator itr = n_fields.children();
388
389 while ( itr.has_next() && main_att_name == "" )
390 {
391 itr.next();
392 std::string fld_name = itr.name();
393 if ( fld_name.find("boundary") == std::string::npos &&
394 fld_name.find("_attribute") != std::string::npos )
395 {
396 main_att_name = fld_name;
397 }
398 }
399
400 if ( main_att_name != "" )
401 {
402 const Node &n_mesh_atts_vals = n_fields[main_att_name]["values"];
403
404 // mfem requires ints, we could have int64s, etc convert if necessary
405 if (n_mesh_atts_vals.dtype().is_int() &&
406 n_mesh_atts_vals.is_compact() )
407 {
408 mesh_atts = n_mesh_atts_vals.value();
409 }
410 else
411 {
412 Node &n_mesh_atts_vals_conv = n_conv["fields"][main_att_name]["values"];
413 n_mesh_atts_vals.to_int_array(n_mesh_atts_vals_conv);
414 mesh_atts = n_mesh_atts_vals_conv.value();
415 }
416
417 // num_mesh_atts_entires = n_mesh_atts_vals.dtype().number_of_elements();
418 }
419 else
420 {
421 // Skipping Mesh Attribute Data
422 }
423
424 // for the boundary attributes check for first occurrence of field with
425 // name containing "_attribute", that also contains "boundary"
426 std::string bnd_att_name = "";
427 itr = n_fields.children();
428
429 while ( itr.has_next() && bnd_att_name == "" )
430 {
431 itr.next();
432 std::string fld_name = itr.name();
433 if ( fld_name.find("boundary") != std::string::npos &&
434 fld_name.find("_attribute") != std::string::npos )
435 {
436 bnd_att_name = fld_name;
437 }
438 }
439
440 if ( bnd_att_name != "" )
441 {
442 // Info: "Getting Boundary Attribute Data"
443 const Node &n_bndry_atts_vals =n_fields[bnd_att_name]["values"];
444
445 // mfem requires ints, we could have int64s, etc convert if necessary
446 if ( n_bndry_atts_vals.dtype().is_int() &&
447 n_bndry_atts_vals.is_compact())
448 {
449 bndry_atts = n_bndry_atts_vals.value();
450 }
451 else
452 {
453 Node &n_bndry_atts_vals_conv = n_conv["fields"][bnd_att_name]["values"];
454 n_bndry_atts_vals.to_int_array(n_bndry_atts_vals_conv);
455 bndry_atts = n_bndry_atts_vals_conv.value();
456 }
457
458 // num_bndry_atts_entires = n_bndry_atts_vals.dtype().number_of_elements();
459
460 }
461 else
462 {
463 // Skipping Boundary Attribute Data
464 }
465
466 // Info: "Number of Vertices: " << num_verts << endl
467 // << "Number of Mesh Elements: " << num_mesh_ele << endl
468 // << "Number of Boundary Elements: " << num_bndry_ele << endl
469 // << "Number of Mesh Attribute Entries: "
470 // << num_mesh_atts_entires << endl
471 // << "Number of Boundary Attribute Entries: "
472 // << num_bndry_atts_entires << endl);
473
474 // Construct MFEM Mesh Object with externally owned data
475 // Note: if we don't have a gf, we need to provide the proper space dim
476 // if nodes gf is attached later, it resets the space dim based
477 // on the gf's fes.
478 Mesh *mesh = new Mesh(// from coordset
479 const_cast<real_t*>(verts_ptr),
480 num_verts,
481 // from topology
482 const_cast<int*>(elem_indices),
483 mesh_geo,
484 // from mesh_attribute field
485 const_cast<int*>(mesh_atts),
486 num_mesh_ele,
487 // from boundary topology
488 const_cast<int*>(bndry_indices),
489 bndry_geo,
490 // from boundary_attribute field
491 const_cast<int*>(bndry_atts),
492 num_bndry_ele,
493 ndims, // dim
494 ndims); // space dim
495
496 // Attach Nodes Grid Function, if it exists
497 if (n_mesh_topo.has_child("grid_function"))
498 {
499 std::string nodes_gf_name = n_mesh_topo["grid_function"].as_string();
500
501 // fetch blueprint field for the nodes gf
502 const Node &n_mesh_gf = n_mesh["fields"][nodes_gf_name];
503 // create gf
505 n_mesh_gf);
506 // attach to mesh
507 mesh->NewNodes(*nodes,true);
508 }
509
510
511 if (zero_copy && !n_conv.dtype().is_empty())
512 {
513 //Info: "Cannot zero-copy since data conversions were necessary"
514 zero_copy = false;
515 }
516
517 Mesh *res = NULL;
518
519 if (zero_copy)
520 {
521 res = mesh;
522 }
523 else
524 {
525 // the mesh above contains references to external data, to get a
526 // copy independent of the conduit data, we use:
527 res = new Mesh(*mesh,true);
528 delete mesh;
529 }
530
531 return res;
532}
533
534//---------------------------------------------------------------------------//
537 const Node &n_field,
538 bool zero_copy)
539{
540 // n_conv holds converted data (when necessary for mfem api)
541 // if n_conv is used ( !n_conv.dtype().empty() ) we
542 // know that some data allocation was necessary, so we
543 // can't return a gf that zero copies the conduit data
544 Node n_conv;
545
546 const real_t *vals_ptr = NULL;
547
548 int vdim = 1;
549
551
552 if (n_field["values"].dtype().is_object())
553 {
554 vdim = n_field["values"].number_of_children();
555
556 // need to check that we have real_t (double/float) and
557 // cover supported layouts
558
559 if ( n_field["values"][0].dtype().id() == mfem_precision_conduit_id )
560 {
561 // check for contig
562 if (n_field["values"].is_contiguous())
563 {
564 // conduit mcarray contig == mfem byNODES
565 vals_ptr = n_field["values"].child(0).value();
566 }
567 // check for interleaved
568 else if (blueprint::mcarray::is_interleaved(n_field["values"]))
569 {
570 // conduit mcarray interleaved == mfem byVDIM
571 ordering = Ordering::byVDIM;
572 vals_ptr = n_field["values"].child(0).value();
573 }
574 else
575 {
576 // for mcarray generic case -- default to byNODES
577 // and provide values w/ contiguous (soa) ordering
578 blueprint::mcarray::to_contiguous(n_field["values"],
579 n_conv["values"]);
580 vals_ptr = n_conv["values"].child(0).value();
581 }
582 }
583 else // convert to real_t (double/float) and use contig
584 {
585 Node n_tmp;
586 // check all vals, if we don't have real_t (double/float) convert
587 // to real_t
588 NodeConstIterator itr = n_field["values"].children();
589 while (itr.has_next())
590 {
591 const Node &c_vals = itr.next();
592 std::string c_name = itr.name();
593
594 if ( c_vals.dtype().id() == mfem_precision_conduit_id )
595 {
596 // zero copy current coords
597 n_tmp[c_name].set_external(c_vals);
598 }
599 else
600 {
601 // convert
602 c_vals.to_data_type(mfem_precision_conduit_id, n_tmp[c_name]);
603 }
604 }
605
606 // for mcarray generic case -- default to byNODES
607 // and provide values w/ contiguous (soa) ordering
608 blueprint::mcarray::to_contiguous(n_tmp,
609 n_conv["values"]);
610 vals_ptr = n_conv["values"].child(0).value();
611 }
612 }
613 else
614 {
615 if (n_field["values"].dtype().id() == mfem_precision_conduit_id &&
616 n_field["values"].is_compact())
617 {
618 vals_ptr = n_field["values"].value();
619 }
620 else
621 {
622 n_field["values"].to_data_type(mfem_precision_conduit_id,
623 n_conv["values"]);
624 vals_ptr = n_conv["values"].value();
625 }
626 }
627
628 if (zero_copy && !n_conv.dtype().is_empty())
629 {
630 //Info: "Cannot zero-copy since data conversions were necessary"
631 zero_copy = false;
632 }
633
634 // we need basis name to create the proper mfem fec
635 std::string fec_name = n_field["basis"].as_string();
636
637 GridFunction *res = NULL;
639 fec_name.c_str());
641 fec,
642 vdim,
643 ordering);
644
645 if (zero_copy)
646 {
647 res = new GridFunction(fes,const_cast<real_t*>(vals_ptr));
648 }
649 else
650 {
651 // copy case, this constructor will alloc the space for the GF data
652 res = new GridFunction(fes);
653 // create an mfem vector that wraps the conduit data
654 Vector vals_vec(const_cast<real_t*>(vals_ptr),fes->GetVSize());
655 // copy values into the result
656 (*res) = vals_vec;
657 }
658
659 // TODO: I believe the GF already has ownership of fes, so this should be all
660 // we need to do to avoid leaking objs created here?
661 res->MakeOwner(fec);
662
663 return res;
664}
665
666//---------------------------------------------------------------------------//
669 const Node &n_field,
670 bool zero_copy)
671{
672 // n_conv holds converted data (when necessary for mfem api)
673 // if n_conv is used ( !n_conv.dtype().empty() ) we
674 // know that some data allocation was necessary, so we
675 // can't return a qf that zero copies the conduit data
676 Node n_conv;
677
678 const real_t *vals_ptr = NULL;
679 int vdim = 1;
680
681 if (n_field["values"].dtype().is_object())
682 {
683 vdim = n_field["values"].number_of_children();
684
685 // need to check that we have real_t (double/float) and
686 // cover supported layouts
687 if ( n_field["values"][0].dtype().id() == mfem_precision_conduit_id )
688 {
689 // quad funcs use what mfem calls byVDIM
690 // and what conduit calls interleaved
691 // check for interleaved
692 if (blueprint::mcarray::is_interleaved(n_field["values"]))
693 {
694 // conduit mcarray interleaved == mfem byVDIM
695 vals_ptr = n_field["values"].child(0).value();
696 }
697 else
698 {
699 // for mcarray generic case -- default to byVDIM
700 // aka interleaved
701 blueprint::mcarray::to_interleaved(n_field["values"],
702 n_conv["values"]);
703 vals_ptr = n_conv["values"].child(0).value();
704 }
705 }
706 else // convert to real_t (double/float) and use interleaved
707 {
708 Node n_tmp;
709 // check all vals, if we don't have real_t (double/float) convert
710 // to real_t
711 NodeConstIterator itr = n_field["values"].children();
712 while (itr.has_next())
713 {
714 const Node &c_vals = itr.next();
715 std::string c_name = itr.name();
716
717 if ( c_vals.dtype().id() == mfem_precision_conduit_id )
718 {
719 // zero copy current coords
720 n_tmp[c_name].set_external(c_vals);
721 }
722 else
723 {
724 // convert
725 c_vals.to_data_type(mfem_precision_conduit_id, n_tmp[c_name]);
726 }
727 }
728
729 // for mcarray generic case -- default to byVDIM
730 // aka interleaved
731 blueprint::mcarray::to_interleaved(n_tmp,
732 n_conv["values"]);
733 vals_ptr = n_conv["values"].child(0).value();
734 }
735 }
736 else // scalar case
737 {
738 if (n_field["values"].dtype().id() == mfem_precision_conduit_id &&
739 n_field["values"].is_compact())
740 {
741 vals_ptr = n_field["values"].value();
742 }
743 else
744 {
745 n_field["values"].to_data_type(mfem_precision_conduit_id,
746 n_conv["values"]);
747 vals_ptr = n_conv["values"].value();
748 }
749 }
750
751 if (zero_copy && !n_conv.dtype().is_empty())
752 {
753 //Info: "Cannot zero-copy since data conversions were necessary"
754 zero_copy = false;
755 }
756
757 // we need basis name to create the proper mfem quad space and quad func
758 // the pattern used to encode the quad space params is:
759 // QF_{ORDER}_{VDIM}
760 // ORDER is the degree of the polynomials for the quad rule
761 // VDIM is the number of components at each quad point (scalar, vector, etc)
762
763 int qf_order = 0;
764 int qf_vdim = 0;
765 std::string qf_name = n_field["basis"].as_string();
766 const char *qf_name_cstr = qf_name.c_str();
767 if (!strncmp(qf_name_cstr, "QF_", 3))
768 {
769 // parse {ORDER}
770 qf_order = atoi(qf_name_cstr + 3);
771 // find second `_`
772 const char *qf_vdim_cstr = strstr(qf_name_cstr+3,"_");
773 if (qf_vdim_cstr == NULL)
774 {
775 MFEM_ABORT("Error parsing quadrature function description string: "
776 << qf_name << std::endl
777 << "Expected: QF_{ORDER}_{VDIM}");
778 }
779 // parse {VDIM}
780 qf_vdim = atoi(qf_vdim_cstr+1);
781 }
782 else
783 {
784 MFEM_ABORT("Error parsing quadrature function description string: "
785 << qf_name << std::endl
786 << "Expected: QF_{ORDER}_{VDIM}");
787 }
788 MFEM_VERIFY(qf_vdim == vdim, "vector dimension mismatch: vdim = " << vdim
789 << ", qf_vdim = " << qf_vdim);
790
791 mfem::QuadratureSpace *quad_space = new mfem::QuadratureSpace(mesh, qf_order);
793
794 if (zero_copy)
795 {
796 res->SetSpace(quad_space, const_cast<real_t*>(vals_ptr), vdim);
797 res->SetOwnsSpace(true);
798 }
799 else
800 {
801 res->SetSpace(quad_space, vdim);
802 res->SetOwnsSpace(true);
803 // copy case, this constructor will alloc the space for the quad data
804 // create an mfem vector that wraps the conduit data
805 Vector vals_vec(const_cast<real_t*>(vals_ptr),res->Size());
806 // copy values into the result
807 (*res) = vals_vec;
808 }
809
810 return res;
811}
812
813
814
815//---------------------------------------------------------------------------//
816void
818 Node &n_mesh,
819 const std::string &coordset_name,
820 const std::string &main_topology_name,
821 const std::string &boundary_topology_name,
822 const std::string &main_adjset_name)
823{
824 int dim = mesh->SpaceDimension();
825
826 MFEM_ASSERT(dim >= 1 && dim <= 3, "invalid mesh dimension");
827
828 ////////////////////////////////////////////
829 // Setup main coordset
830 ////////////////////////////////////////////
831
832 // Assumes mfem::Vertex has the layout of a real_t (double/float) array.
833
834 // this logic assumes an mfem vertex is always 3 real_t (double/float) wide
835 int stride = sizeof(mfem::Vertex);
836 int num_vertices = mesh->GetNV();
837
838 MFEM_ASSERT( ( stride == 3 * sizeof(real_t) ),
839 "Unexpected stride for Vertex");
840
841 Node &n_mesh_coords = n_mesh["coordsets"][coordset_name];
842 n_mesh_coords["type"] = "explicit";
843
844
845 real_t *coords_ptr = mesh->GetVertex(0);
846
847 n_mesh_coords["values/x"].set_external(coords_ptr,
848 num_vertices,
849 0,
850 stride);
851
852 if (dim >= 2)
853 {
854 n_mesh_coords["values/y"].set_external(coords_ptr,
855 num_vertices,
856 sizeof(real_t),
857 stride);
858 }
859 if (dim >= 3)
860 {
861 n_mesh_coords["values/z"].set_external(coords_ptr,
862 num_vertices,
863 sizeof(real_t) * 2,
864 stride);
865 }
866
867 ////////////////////////////////////////////
868 // Setup main topo
869 ////////////////////////////////////////////
870
871 Node &n_topo = n_mesh["topologies"][main_topology_name];
872
873 n_topo["type"] = "unstructured";
874 n_topo["coordset"] = coordset_name;
875
876 Element::Type ele_type = mesh->GetElementType(0);
877
878 std::string ele_shape = ElementTypeToShapeName(ele_type);
879
880 n_topo["elements/shape"] = ele_shape;
881
882 GridFunction *gf_mesh_nodes = mesh->GetNodes();
883
884 if (gf_mesh_nodes != NULL)
885 {
886 n_topo["grid_function"] = "mesh_nodes";
887 }
888
889 // connectivity
890 // TODO: generic case, i don't think we can zero-copy (mfem allocs
891 // an array per element) so we alloc our own contig array and
892 // copy out. Some other cases (sidre) may actually have contig
893 // allocation but I am not sure how to detect this case from mfem
894 int num_ele = mesh->GetNE();
895 int geom = mesh->GetTypicalElementGeometry();
896 int idxs_per_ele = Geometry::NumVerts[geom];
897 int num_conn_idxs = num_ele * idxs_per_ele;
898
899 n_topo["elements/connectivity"].set(DataType::c_int(num_conn_idxs));
900
901 int *conn_ptr = n_topo["elements/connectivity"].value();
902
903 for (int i=0; i < num_ele; i++)
904 {
905 const Element *ele = mesh->GetElement(i);
906 const int *ele_verts = ele->GetVertices();
907
908 memcpy(conn_ptr, ele_verts, idxs_per_ele * sizeof(int));
909
910 conn_ptr += idxs_per_ele;
911 }
912
913 if (gf_mesh_nodes != NULL)
914 {
915 GridFunctionToBlueprintField(gf_mesh_nodes,
916 n_mesh["fields/mesh_nodes"],
917 main_topology_name);
918 }
919
920 ////////////////////////////////////////////
921 // Setup mesh attribute
922 ////////////////////////////////////////////
923
924 Node &n_mesh_att = n_mesh["fields/element_attribute"];
925
926 n_mesh_att["association"] = "element";
927 n_mesh_att["topology"] = main_topology_name;
928 n_mesh_att["values"].set(DataType::c_int(num_ele));
929
930 int_array att_vals = n_mesh_att["values"].value();
931 for (int i = 0; i < num_ele; i++)
932 {
933 att_vals[i] = mesh->GetAttribute(i);
934 }
935
936 ////////////////////////////////////////////
937 // Setup bndry topo "boundary"
938 ////////////////////////////////////////////
939
940 // guard vs if we have boundary elements
942 {
943 n_topo["boundary_topology"] = boundary_topology_name;
944
945 Node &n_bndry_topo = n_mesh["topologies"][boundary_topology_name];
946
947 n_bndry_topo["type"] = "unstructured";
948 n_bndry_topo["coordset"] = coordset_name;
949
950 int num_bndry_ele = mesh->GetNBE();
951
952 Element *BE0 = NULL; // representative boundary element
953 if (num_bndry_ele > 0) { BE0 = mesh->GetBdrElement(0); }
954
955 // must initialize this to something, pick POINT if no boundary elements
956 Element::Type bndry_ele_type = (BE0) ? BE0->GetType() : Element::POINT;
957 std::string bndry_ele_shape = ElementTypeToShapeName(bndry_ele_type);
958 n_bndry_topo["elements/shape"] = bndry_ele_shape;
959
960 // must initialize this to something, pick POINT if no boundary elements
961 int bndry_geom = (BE0) ? BE0->GetGeometryType() : Geometry::POINT;
962 int bndry_idxs_per_ele = Geometry::NumVerts[bndry_geom];
963 int num_bndry_conn_idxs = num_bndry_ele * bndry_idxs_per_ele;
964
965 n_bndry_topo["elements/connectivity"].set(DataType::c_int(num_bndry_conn_idxs));
966
967 int *bndry_conn_ptr = n_bndry_topo["elements/connectivity"].value();
968
969 for (int i=0; i < num_bndry_ele; i++)
970 {
971 const Element *bndry_ele = mesh->GetBdrElement(i);
972 const int *bndry_ele_verts = bndry_ele->GetVertices();
973
974 memcpy(bndry_conn_ptr, bndry_ele_verts, bndry_idxs_per_ele * sizeof(int));
975
976 bndry_conn_ptr += bndry_idxs_per_ele;
977 }
978
979 ////////////////////////////////////////////
980 // Setup bndry mesh attribute
981 ////////////////////////////////////////////
982
983 Node &n_bndry_mesh_att = n_mesh["fields/boundary_attribute"];
984
985 n_bndry_mesh_att["association"] = "element";
986 n_bndry_mesh_att["topology"] = boundary_topology_name;
987 n_bndry_mesh_att["values"].set(DataType::c_int(num_bndry_ele));
988
989 int_array bndry_att_vals = n_bndry_mesh_att["values"].value();
990 for (int i = 0; i < num_bndry_ele; i++)
991 {
992 bndry_att_vals[i] = mesh->GetBdrAttribute(i);
993 }
994 }
995
996 ////////////////////////////////////////////
997 // Setup adjsets
998 ////////////////////////////////////////////
999
1000#ifdef MFEM_USE_MPI
1001 ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
1002 if (pmesh)
1003 {
1004 ////////////////////////////////////////////
1005 // Setup main adjset
1006 ////////////////////////////////////////////
1007
1008 Node &n_adjset = n_mesh["adjsets"][main_adjset_name];
1009
1010 n_adjset["association"] = "vertex";
1011 n_adjset["topology"] = main_topology_name;
1012 n_adjset["groups"].set(DataType::object());
1013
1014 const GroupTopology &pmesh_gtopo = pmesh->gtopo;
1015 const int local_rank = pmesh->GetMyRank();
1016 const int num_groups = pmesh_gtopo.NGroups();
1017 // NOTE: skip the first group since its the local-only group
1018 for (int i = 1; i < num_groups; i++)
1019 {
1020 const int num_group_nbrs = pmesh_gtopo.GetGroupSize(i);
1021 const int *group_nbrs = pmesh_gtopo.GetGroup(i);
1022 const int num_group_verts = pmesh->GroupNVertices(i);
1023
1024 // NOTE: 'neighbor' values are local to this processor, but Blueprint
1025 // expects global domain identifiers, so we collapse this layer of
1026 // indirection
1027 Array<int> group_ranks(num_group_nbrs);
1028 std::string group_name = "group";
1029 {
1030 for (int j = 0; j < num_group_nbrs; j++)
1031 {
1032 group_ranks[j] = pmesh_gtopo.GetNeighborRank(group_nbrs[j]);
1033 }
1034 group_ranks.Sort();
1035 for (int j = 0; j < num_group_nbrs; j++)
1036 {
1037 group_name += "_" + std::to_string(group_ranks[j]);
1038 }
1039
1040 // NOTE: Blueprint only wants remote ranks in its neighbor list,
1041 // so we remove the local rank after the canonicalized Blueprint
1042 // group name is formed
1043 group_ranks.DeleteFirst(local_rank);
1044 }
1045 Node &n_group = n_adjset["groups"][group_name];
1046
1047 n_group["neighbors"].set(group_ranks.GetData(), group_ranks.Size());
1048 n_group["values"].set(DataType::c_int(num_group_verts));
1049
1050 int_array group_vals = n_group["values"].value();
1051 for (int j = 0; j < num_group_verts; j++)
1052 {
1053 group_vals[j] = pmesh->GroupVertex(i, j);
1054 }
1055 }
1056
1057 // NOTE: We don't create an adjset for face neighbor data because
1058 // these faces aren't listed in the 'boundary_topology_name' topology
1059 // (this topology only covers the faces between 'main_topology_name'
1060 // elements and void). To include a face neighbor data adjset, this
1061 // function would need to export a topology with either (1) all faces
1062 // in the mesh topology or (2) all boundary faces, including neighbors.
1063
1064 ////////////////////////////////////////////
1065 // Setup distributed state
1066 ////////////////////////////////////////////
1067
1068 Node &n_domid = n_mesh["state/domain_id"];
1069 n_domid.set(local_rank);
1070 }
1071#endif
1072}
1073
1074//---------------------------------------------------------------------------//
1075void
1077 Node &n_field,
1078 const std::string &main_topology_name)
1079{
1080 n_field["basis"] = gf->FESpace()->FEColl()->Name();
1081 n_field["topology"] = main_topology_name;
1082
1083 int vdim = gf->FESpace()->GetVDim();
1084 int ndofs = gf->FESpace()->GetNDofs();
1085
1086 if (vdim == 1) // scalar case
1087 {
1088 n_field["values"].set_external(const_cast<real_t *>(gf->HostRead()),
1089 ndofs);
1090 }
1091 else // vector case
1092 {
1093 // deal with striding of all components
1094
1095 Ordering::Type ordering = gf->FESpace()->GetOrdering();
1096
1097 int entry_stride = (ordering == Ordering::byNODES ? 1 : vdim);
1098 int vdim_stride = (ordering == Ordering::byNODES ? ndofs : 1);
1099
1100 index_t offset = 0;
1101 index_t stride = sizeof(real_t) * entry_stride;
1102
1103 for (int d = 0; d < vdim; d++)
1104 {
1105 std::ostringstream oss;
1106 oss << "v" << d;
1107 std::string comp_name = oss.str();
1108 n_field["values"][comp_name].set_external(const_cast<real_t *>(gf->HostRead()),
1109 ndofs,
1110 offset,
1111 stride);
1112 offset += sizeof(real_t) * vdim_stride;
1113 }
1114 }
1115
1116}
1117
1118//---------------------------------------------------------------------------//
1119void
1122 Node &n_field,
1123 const std::string &main_topology_name)
1124{
1125 // For quadrature functions, use basis pattern:
1126 // QF_{ORDER}_{VDIM}
1127
1128 int qf_vdim = qf->GetVDim();
1129 int qf_order = qf->GetSpace()->GetOrder();
1130 int qf_size = qf->GetSpace()->GetSize();
1131
1132 {
1133 std::ostringstream oss;
1134 oss << "QF_" << qf_order << "_" << qf_vdim;
1135
1136 n_field["basis"] = oss.str();
1137 n_field["topology"] = main_topology_name;
1138 }
1139
1140 if (qf_vdim == 1) // scalar case
1141 {
1142 n_field["values"].set_external(const_cast<real_t *>(qf->HostRead()),
1143 qf_size);
1144 }
1145 else // vector case
1146 {
1147 // deal with striding of all components
1148 // quadrature functions are always byVDIM
1149 // or what conduit calls interleaved
1150
1151 index_t offset = 0;
1152 index_t stride = sizeof(real_t) * qf_vdim;
1153
1154 for (int d = 0; d < qf_vdim; d++)
1155 {
1156 std::ostringstream oss;
1157 oss << "v" << d;
1158 std::string comp_name = oss.str();
1159 n_field["values"][comp_name].set_external(const_cast<real_t *>(qf->HostRead()),
1160 qf_size,
1161 offset,
1162 stride);
1163 offset += sizeof(real_t);
1164 }
1165 }
1166
1167}
1168
1169
1170
1171//------------------------------
1172// end static public methods
1173//------------------------------
1174
1175//------------------------------
1176// end public methods
1177//------------------------------
1178
1179//------------------------------
1180// begin protected methods
1181//------------------------------
1182
1183//---------------------------------------------------------------------------//
1184std::string
1186{
1187 std::string res = prefix_path + name + "_" +
1189 ".root";
1190 return res;
1191}
1192
1193//---------------------------------------------------------------------------//
1194std::string
1196 const std::string &relay_protocol_)
1197{
1198 std::string res = prefix_path +
1199 name +
1200 "_" +
1202 "/domain_" +
1203 to_padded_string(domain_id, pad_digits_rank) +
1204 "." +
1205 relay_protocol_;
1206
1207 return res;
1208}
1209
1210//---------------------------------------------------------------------------//
1211std::string
1213{
1214 std::string res = prefix_path +
1215 name +
1216 "_" +
1218 return res;
1219}
1220
1221//---------------------------------------------------------------------------//
1222std::string
1223ConduitDataCollection::MeshFilePattern(const std::string &relay_protocol_)
1224{
1225 std::ostringstream oss;
1226 oss << name
1227 << "_"
1229 << "/domain_%0"
1231 << "d."
1232 << relay_protocol_;
1233
1234 return oss.str();
1235}
1236
1237
1238//---------------------------------------------------------------------------//
1239void
1241 const Node &n_mesh,
1242 const std::string &relay_protocol_)
1243{
1244 // default to json root file, except for hdf5 case
1245 std::string root_proto = "json";
1246
1247 if (relay_protocol_ == "hdf5")
1248 {
1249 root_proto = relay_protocol_;
1250 }
1251
1252 Node n_root;
1253 // create blueprint index
1254 Node &n_bp_idx = n_root["blueprint_index"];
1255
1256 blueprint::mesh::generate_index(n_mesh,
1257 "",
1258 num_domains,
1259 n_bp_idx["mesh"]);
1260
1261 // there are cases where the data backing the gf fields doesn't
1262 // accurately represent the number of components in physical space,
1263 // so we loop over all gfs and fix those that are incorrect
1264
1266 for ( itr = field_map.begin(); itr != field_map.end(); itr++)
1267 {
1268 std::string gf_name = itr->first;
1269 GridFunction *gf = itr->second;
1270
1271 Node &idx_gf_ncomps = n_bp_idx["mesh/fields"][gf_name]["number_of_components"];
1272 // check that the number_of_components in the index matches what we expect
1273 // correct if necessary
1274 if ( idx_gf_ncomps.to_int() != gf->VectorDim() )
1275 {
1276 idx_gf_ncomps = gf->VectorDim();
1277 }
1278 }
1279 // add extra header info
1280 n_root["protocol/name"] = relay_protocol_;
1281 n_root["protocol/version"] = "0.3.1";
1282
1283
1284 // we will save one file per domain, so trees == files
1285 n_root["number_of_files"] = num_domains;
1286 n_root["number_of_trees"] = num_domains;
1287 n_root["file_pattern"] = MeshFilePattern(relay_protocol_);
1288 n_root["tree_pattern"] = "";
1289
1290 // Add the time, time step, and cycle
1291 n_root["blueprint_index/mesh/state/time"] = time;
1292 n_root["blueprint_index/mesh/state/time_step"] = time_step;
1293 n_root["blueprint_index/mesh/state/cycle"] = cycle;
1294
1295 relay::io::save(n_root, RootFileName(), root_proto);
1296}
1297
1298//---------------------------------------------------------------------------//
1299void
1301 const Node &n_mesh,
1302 const std::string &relay_protocol_)
1303{
1304 relay::io::save(n_mesh, MeshFileName(domain_id, relay_protocol_));
1305}
1306
1307//---------------------------------------------------------------------------//
1308void
1310{
1311 if (myid == 0)
1312 {
1313 // assume root file is json, unless hdf5 is specified
1314 std::string root_protocol = "json";
1315
1316 if ( relay_protocol.find("hdf5") != std::string::npos )
1317 {
1318 root_protocol = "hdf5";
1319 }
1320
1321
1322 relay::io::load(RootFileName(), root_protocol, root_out);
1323#ifdef MFEM_USE_MPI
1324 // broadcast contents of root file other ranks
1325 // (conduit relay mpi would simplify, but we would need to link another
1326 // lib for mpi case)
1327
1328 // create json string
1329 std::string root_json = root_out.to_json();
1330 // string size +1 for null term
1331 int json_str_size = root_json.size() + 1;
1332
1333 // broadcast json string buffer size
1334 int mpi_status = MPI_Bcast((void*)&json_str_size, // ptr
1335 1, // size
1336 MPI_INT, // type
1337 0, // root
1338 m_comm); // comm
1339
1340 if (mpi_status != MPI_SUCCESS)
1341 {
1342 MFEM_ABORT("Broadcast of root file json string size failed");
1343 }
1344
1345 // broadcast json string
1346 mpi_status = MPI_Bcast((void*)root_json.c_str(), // ptr
1347 json_str_size, // size
1348 MPI_CHAR, // type
1349 0, // root
1350 m_comm); // comm
1351
1352 if (mpi_status != MPI_SUCCESS)
1353 {
1354 MFEM_ABORT("Broadcast of root file json string failed");
1355 }
1356
1357#endif
1358 }
1359
1360#ifdef MFEM_USE_MPI
1361 else
1362 {
1363 // recv json string buffer size via broadcast
1364 int json_str_size = -1;
1365 int mpi_status = MPI_Bcast(&json_str_size, // ptr
1366 1, // size
1367 MPI_INT, // type
1368 0, // root
1369 m_comm); // comm
1370
1371 if (mpi_status != MPI_SUCCESS)
1372 {
1373 MFEM_ABORT("Broadcast of root file json string size failed");
1374 }
1375
1376 // recv json string buffer via broadcast
1377 char *json_buff = new char[json_str_size];
1378 mpi_status = MPI_Bcast(json_buff, // ptr
1379 json_str_size, // size
1380 MPI_CHAR, // type
1381 0, // root
1382 m_comm); // comm
1383
1384 if (mpi_status != MPI_SUCCESS)
1385 {
1386 MFEM_ABORT("Broadcast of root file json string failed");
1387 }
1388
1389 // reconstruct root file contents
1390 Generator g(std::string(json_buff),"json");
1391 g.walk(root_out);
1392 // cleanup temp buffer
1393 delete [] json_buff;
1394 }
1395#endif
1396}
1397
1398//---------------------------------------------------------------------------//
1399void
1401 const std::string &relay_protocol_)
1402{
1403 // Note: This path doesn't use any info from the root file
1404 // it uses the implicit mfem ConduitDataCollection layout
1405
1406 Node n_mesh;
1407 relay::io::load( MeshFileName(domain_id, relay_protocol_), n_mesh);
1408
1409
1410 Node verify_info;
1411 if (!blueprint::mesh::verify(n_mesh,verify_info))
1412 {
1413 MFEM_ABORT("Conduit Mesh Blueprint Verify Failed:\n"
1414 << verify_info.to_json());
1415 }
1416
1417 mesh = BlueprintMeshToMesh(n_mesh);
1418
1419 field_map.clear();
1420
1421 NodeConstIterator itr = n_mesh["fields"].children();
1422
1423 std::string nodes_gf_name = "";
1424
1425 const Node &n_topo = n_mesh["topologies/main"];
1426 if (n_topo.has_child("grid_function"))
1427 {
1428 nodes_gf_name = n_topo["grid_function"].as_string();
1429 }
1430
1431 while (itr.has_next())
1432 {
1433 const Node &n_field = itr.next();
1434 std::string field_name = itr.name();
1435
1436 // skip mesh nodes gf since they are already processed
1437 // skip attribute fields, they aren't grid functions
1438 if ( field_name != nodes_gf_name &&
1439 field_name.find("_attribute") == std::string::npos
1440 )
1441 {
1443 field_map.Register(field_name, gf, true);
1444 }
1445 }
1446}
1447
1448//------------------------------
1449// end protected methods
1450//------------------------------
1451
1452//------------------------------
1453// begin static private methods
1454//------------------------------
1455
1456//---------------------------------------------------------------------------//
1457std::string
1458ConduitDataCollection::ElementTypeToShapeName(Element::Type element_type)
1459{
1460 // Adapted from SidreDataCollection
1461
1462 // Note -- the mapping from Element::Type to string is based on
1463 // enum Element::Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
1464 // TETRAHEDRON, HEXAHEDRON };
1465 // Note: -- the string names are from conduit's blueprint
1466
1467 switch (element_type)
1468 {
1469 case Element::POINT: return "point";
1470 case Element::SEGMENT: return "line";
1471 case Element::TRIANGLE: return "tri";
1472 case Element::QUADRILATERAL: return "quad";
1473 case Element::TETRAHEDRON: return "tet";
1474 case Element::HEXAHEDRON: return "hex";
1475 case Element::WEDGE:
1476 default: ;
1477 }
1478
1479 return "unknown";
1480}
1481
1482//---------------------------------------------------------------------------//
1484ConduitDataCollection::ShapeNameToGeomType(const std::string &shape_name)
1485{
1486 // Note: must init to something to avoid invalid memory access
1487 // in the mfem mesh constructor
1489
1490 if (shape_name == "point")
1491 {
1493 }
1494 else if (shape_name == "line")
1495 {
1497 }
1498 else if (shape_name == "tri")
1499 {
1501 }
1502 else if (shape_name == "quad")
1503 {
1505 }
1506 else if (shape_name == "tet")
1507 {
1509 }
1510 else if (shape_name == "hex")
1511 {
1513 }
1514 else
1515 {
1516 MFEM_ABORT("Unsupported Element Shape: " << shape_name);
1517 }
1518
1519 return res;
1520}
1521
1522//------------------------------
1523// end static private methods
1524//------------------------------
1525
1526} // end namespace mfem
1527
1528#endif
void DeleteFirst(const T &el)
Delete the first entry with value == 'el'.
Definition array.hpp:1019
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
Definition array.hpp:341
int Size() const
Return the logical size of the array.
Definition array.hpp:192
T * GetData()
Returns the data.
Definition array.hpp:159
static Mesh * BlueprintMeshToMesh(const conduit::Node &n_mesh, const std::string &main_toplogy_name="", bool zero_copy=false)
Constructs and MFEM mesh from a Conduit Blueprint Description.
std::string RootFileName()
Returns blueprint root file name for the current cycle.
void SaveRootFile(int num_domains, const conduit::Node &n_mesh, const std::string &file_protocol)
Saves root file for the current cycle.
void LoadMeshAndFields(int domain_id, const std::string &file_protocol)
Loads all meshes and fields of a given domain id for the current cycle.
static GridFunction * BlueprintFieldToGridFunction(Mesh *mesh, const conduit::Node &n_field, bool zero_copy=false)
Constructs and MFEM Grid Function from a Conduit Blueprint Description.
virtual void Load(int cycle=0)
Load the collection based blueprint data.
static void MeshToBlueprintMesh(Mesh *m, conduit::Node &out, const std::string &coordset_name="coords", const std::string &main_topology_name="main", const std::string &boundary_topology_name="boundary", const std::string &main_adjset_name="main_adjset")
Describes a MFEM mesh using the mesh blueprint.
std::string MeshDirectoryName()
Returns the mesh output directory for the current cycle.
void SetProtocol(const std::string &protocol)
Set the Conduit relay i/o protocol to use.
std::string MeshFileName(int domain_id, const std::string &file_protocol="hdf5")
Returns the mesh file name for a given domain at the current cycle.
static void GridFunctionToBlueprintField(GridFunction *gf, conduit::Node &out, const std::string &main_topology_name="main")
Describes a MFEM grid function using the mesh blueprint.
std::string MeshFilePattern(const std::string &file_protocol="hdf5")
Returns the mesh file pattern for the current cycle.
static QuadratureFunction * BlueprintFieldToQuadratureFunction(Mesh *mesh, const conduit::Node &n_field, bool zero_copy=false)
Constructs and MFEM Quadrature Function from a Conduit Blueprint Description.
static void QuadratureFunctionToBlueprintField(QuadratureFunction *qf, conduit::Node &out, const std::string &main_topology_name="main")
Describes a MFEM quadrature function using the mesh blueprint.
virtual void Save()
Save the collection and a Conduit blueprint root file.
void SaveMeshAndFields(int domain_id, const conduit::Node &n_mesh, const std::string &file_protocol)
Saves all meshes and fields for the current cycle.
virtual ~ConduitDataCollection()
We will delete the mesh and fields if we own them.
void LoadRootFile(conduit::Node &n_root_out)
Loads contents of the root field for the current cycle into n_root_out.
ConduitDataCollection(const std::string &collection_name, Mesh *mesh=NULL)
Constructor. The collection name is used when saving the data.
int cycle
Time cycle; for time-dependent simulations cycle >= 0, otherwise = -1.
real_t time
Physical time (for time-dependent simulations)
bool own_data
Should the collection delete its mesh and fields.
static int create_directory(const std::string &dir_name, const Mesh *mesh, int myid)
void DeleteAll()
Delete data owned by the DataCollection including field information.
GFieldMap::const_iterator FieldMapConstIterator
QFieldMap::const_iterator QFieldMapConstIterator
int pad_digits_cycle
Number of digits used for the cycle and MPI rank in filenames.
std::string prefix_path
A path where the directory with results is saved. If not empty, it has '/' at the end.
int myid
MPI rank (in parallel)
real_t time_step
Time step i.e. delta_t (for time-dependent simulations)
int num_procs
Number of MPI ranks (in parallel)
bool appendRankToFileName
Append rank to any output file names.
std::string name
Name of the collection, used as a directory name when saving.
MPI_Comm m_comm
Associated MPI communicator.
Mesh * mesh
The (common) mesh for the collected fields.
Abstract data type element.
Definition element.hpp:29
Geometry::Type GetGeometryType() const
Definition element.hpp:55
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
virtual Type GetType() const =0
Returns element's type.
Type
Constants for the classes derived from Element.
Definition element.hpp:41
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Definition fe_coll.cpp:124
virtual const char * Name() const
Definition fe_coll.hpp:79
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
static const int NumVerts[NumGeom]
Definition geom.hpp:53
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
Definition gridfunc.hpp:160
FiniteElementSpace * FESpace()
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
Definition gridfunc.hpp:166
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor.
int GetGroupSize(int g) const
Get the number of processors in a group.
int NGroups() const
Return the number of groups.
Mesh data type.
Definition mesh.hpp:67
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition mesh.cpp:8445
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1497
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1705
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1503
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1447
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1462
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:10112
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1387
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1393
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition mesh.cpp:10139
virtual bool HasBoundaryElements() const
Checks if the mesh has boundary elements.
Definition mesh.hpp:1344
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1429
void Register(const std::string &fname, T *field, bool own_data)
Register field field with name fname.
iterator end()
Returns an end iterator to the registered fields.
iterator begin()
Returns a begin iterator to the registered fields.
void clear()
Clears the map of registered fields without reclaiming memory.
Type
Ordering methods:
Definition ordering.hpp:17
Class for parallel meshes.
Definition pmesh.hpp:35
int GetMyRank() const
Definition pmesh.hpp:405
int GroupVertex(int group, int i) const
Accessors for entities within a shared group structure.
Definition pmesh.hpp:491
GroupTopology gtopo
Definition pmesh.hpp:457
int GroupNVertices(int group) const
Definition pmesh.hpp:475
Represents values or vectors of values at quadrature points on a mesh.
Definition qfunction.hpp:24
QuadratureSpaceBase * GetSpace()
Get the associated QuadratureSpaceBase object.
Definition qfunction.hpp:94
void SetOwnsSpace(bool own)
Set the QuadratureSpaceBase ownership flag.
int GetVDim() const
Get the vector dimension.
Definition qfunction.hpp:87
void SetSpace(QuadratureSpaceBase *qspace_, int vdim_=-1)
Change the QuadratureSpaceBase and optionally the vector dimension.
int GetSize() const
Return the total number of quadrature points.
Definition qspace.hpp:107
int GetOrder() const
Return the order of the quadrature rule(s) used by all elements.
Definition qspace.hpp:110
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:164
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
Data type for vertex.
Definition vertex.hpp:23
int dim
Definition ex24.cpp:53
constexpr conduit::index_t mfem_precision_conduit_id
std::string to_padded_string(int i, int digits)
Convert an integer to a 0-padded string with the given number of digits.
Definition text.hpp:96
float real_t
Definition config.hpp:46
std::array< int, NCMesh::MaxFaceNodes > nodes