9 #include "axom/core.hpp"
14 std::unordered_map<std::string, axom::sidre::MFEMSidreDataCollection> StateManager::datacolls_;
15 std::unordered_map<std::string, std::unique_ptr<FiniteElementState>> StateManager::shape_displacements_;
16 bool StateManager::is_restart_ =
false;
17 axom::sidre::DataStore* StateManager::ds_ =
nullptr;
18 std::string StateManager::output_dir_ =
"";
19 std::unordered_map<std::string, mfem::ParGridFunction*> StateManager::named_states_;
20 std::unordered_map<std::string, mfem::ParGridFunction*> StateManager::named_duals_;
22 double StateManager::newDataCollection(
const std::string& name,
const std::optional<int> cycle_to_load)
24 SLIC_ERROR_ROOT_IF(!ds_,
"Cannot construct a DataCollection without a DataStore");
25 std::string coll_name = name +
"_datacoll";
27 auto global_grp = ds_->getRoot()->createGroup(coll_name +
"_global");
28 auto bp_index_grp = global_grp->createGroup(
"blueprint_index/" + coll_name);
29 auto domain_grp = ds_->getRoot()->createGroup(coll_name);
32 constexpr
bool owns_mesh_data =
true;
33 auto [iter, _] = datacolls_.emplace(std::piecewise_construct, std::forward_as_tuple(name),
34 std::forward_as_tuple(coll_name, bp_index_grp, domain_grp, owns_mesh_data));
35 auto& datacoll = iter->second;
36 datacoll.SetComm(MPI_COMM_WORLD);
38 datacoll.SetPrefixPath(output_dir_);
42 datacoll.Load(*cycle_to_load);
43 datacoll.SetGroupPointers(ds_->getRoot()->getGroup(coll_name +
"_global/blueprint_index/" + coll_name),
44 ds_->getRoot()->getGroup(coll_name));
45 SLIC_ERROR_ROOT_IF(datacoll.GetBPGroup()->getNumGroups() == 0,
46 "Loaded datastore is empty, was the datastore created on a "
47 "different number of nodes?");
49 datacoll.UpdateStateFromDS();
50 datacoll.UpdateMeshAndFieldsFromDS();
57 bool is_discontinuous =
false;
58 auto nodes =
mesh(name).GetNodes();
60 is_discontinuous = nodes->FESpace()->FEColl()->GetContType() == mfem::FiniteElementCollection::DISCONTINUOUS;
63 "Periodic mesh detected! This will only work on translational periodic surfaces for vector H1 fields and "
64 "has not been thoroughly tested. Proceed at your own risk.");
73 mesh(name).SetCurvature(1, is_discontinuous, -1, mfem::Ordering::byNODES);
76 mesh(name).SetNodesOwner(
false);
80 mesh(name).ExchangeFaceNbrData();
83 constructShapeFields(name);
87 datacoll.SetTime(0.0);
90 return datacoll.GetTime();
94 std::vector<std::reference_wrapper<FiniteElementState>> states_to_load)
96 std::string mesh_name =
collectionID(&states_to_load.begin()->get().mesh());
98 std::string coll_name = mesh_name +
"_datacoll";
100 axom::sidre::MFEMSidreDataCollection previous_datacoll(coll_name);
102 previous_datacoll.SetComm(states_to_load.begin()->get().mesh().GetComm());
103 previous_datacoll.SetPrefixPath(output_dir_);
104 previous_datacoll.Load(cycle_to_load);
106 for (
auto state : states_to_load) {
107 SLIC_ERROR_ROOT_IF(
collectionID(&state.get().mesh()) != mesh_name,
108 "Loading FiniteElementStates from two different meshes at one time is not allowed.");
109 mfem::ParGridFunction* datacoll_owned_grid_function = previous_datacoll.GetParField(state.get().name());
111 state.get().setFromGridFunction(*datacoll_owned_grid_function);
122 output_dir_ = output_directory;
123 if (output_directory.empty()) {
125 "DataCollection output directory cannot be empty - this will result in problems if executables are run in "
132 return *shape_displacements_[mesh_tag];
137 SLIC_ERROR_ROOT_IF(!ds_,
"Serac's data store was not initialized - call StateManager::initialize first");
139 SLIC_ERROR_ROOT_IF(named_states_.find(state.
name()) != named_states_.end(),
140 axom::fmt::format(
"StateManager already contains a state named '{}'", state.
name()));
141 auto& datacoll = datacolls_.at(mesh_tag);
142 const std::string name = state.
name();
143 mfem::ParGridFunction* grid_function;
145 grid_function = datacoll.GetParField(name);
148 SLIC_ERROR_ROOT_IF(datacoll.HasField(name),
149 axom::fmt::format(
"StateManager already given a field named '{0}'", name));
152 grid_function =
new mfem::ParGridFunction(&state.
space(),
static_cast<double*
>(
nullptr));
153 datacoll.RegisterField(name, grid_function);
156 named_states_[name] = grid_function;
161 std::string mesh_tag =
collectionID(space.GetParMesh());
163 SLIC_ERROR_ROOT_IF(!ds_,
"Serac's data store was not initialized - call StateManager::initialize first");
164 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
165 axom::fmt::format(
"Mesh tag '{}' not found in the data store", mesh_tag));
166 SLIC_ERROR_ROOT_IF(named_states_.find(state_name) != named_states_.end(),
167 axom::fmt::format(
"StateManager already contains a state named '{}'", state_name));
175 SLIC_ERROR_ROOT_IF(!ds_,
"Serac's data store was not initialized - call StateManager::initialize first");
177 SLIC_ERROR_ROOT_IF(named_duals_.find(
dual.name()) != named_duals_.end(),
178 axom::fmt::format(
"StateManager already contains a state named '{}'",
dual.name()));
179 auto& datacoll = datacolls_.at(mesh_tag);
180 const std::string name =
dual.name();
181 mfem::ParGridFunction* grid_function;
183 grid_function = datacoll.GetParField(name);
184 std::unique_ptr<mfem::HypreParVector> true_dofs(grid_function->GetTrueDofs());
187 SLIC_ERROR_ROOT_IF(datacoll.HasField(name),
188 axom::fmt::format(
"StateManager already given a field named '{0}'", name));
191 grid_function =
new mfem::ParGridFunction(&
dual.space(),
static_cast<double*
>(
nullptr));
192 datacoll.RegisterField(name, grid_function);
193 std::unique_ptr<mfem::HypreParVector> true_dofs(grid_function->GetTrueDofs());
196 named_duals_[name] = grid_function;
201 std::string mesh_tag =
collectionID(space.GetParMesh());
203 SLIC_ERROR_ROOT_IF(!ds_,
"Serac's data store was not initialized - call StateManager::initialize first");
204 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
205 axom::fmt::format(
"Mesh tag '{}' not found in the data store", mesh_tag));
206 SLIC_ERROR_ROOT_IF(named_duals_.find(dual_name) != named_duals_.end(),
207 axom::fmt::format(
"StateManager already contains a dual named '{}'", dual_name));
215 SLIC_ERROR_ROOT_IF(!ds_,
"Serac's data store was not initialized - call StateManager::initialize first");
216 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
217 axom::fmt::format(
"Mesh tag '{}' not found in the data store", mesh_tag));
218 auto& datacoll = datacolls_.at(mesh_tag);
219 std::string file_path = axom::utilities::filesystem::joinPath(datacoll.GetPrefixPath(), datacoll.GetCollectionName());
221 axom::fmt::format(
"Saving data collection at time: '{}' and cycle: '{}' to path: '{}'", t,
cycle, file_path));
224 datacoll.SetCycle(
cycle);
233 bool is_discontinuous =
false;
234 auto nodes = pmesh->GetNodes();
236 is_discontinuous = nodes->FESpace()->FEColl()->GetContType() == mfem::FiniteElementCollection::DISCONTINUOUS;
237 SLIC_WARNING_ROOT_IF(
239 "Periodic mesh detected! This will only work on translational periodic surfaces for vector H1 fields and "
240 "has not been thoroughly tested. Proceed at your own risk.");
249 pmesh->SetCurvature(1, is_discontinuous, -1, mfem::Ordering::byNODES);
252 pmesh->SetNodesOwner(
false);
254 newDataCollection(mesh_tag);
255 auto& datacoll = datacolls_.at(mesh_tag);
256 datacoll.SetMesh(pmesh.release());
257 datacoll.SetOwnData(
true);
260 auto& new_pmesh =
mesh(mesh_tag);
264 new_pmesh.ExchangeFaceNbrData();
268 constructShapeFields(mesh_tag);
273 void StateManager::constructShapeFields(
const std::string& mesh_tag)
276 auto& new_mesh =
mesh(mesh_tag);
278 if (new_mesh.Dimension() == 2) {
279 shape_displacements_[mesh_tag] =
280 std::make_unique<FiniteElementState>(new_mesh,
SHAPE_DIM_2, mesh_tag +
"_shape_displacement");
281 }
else if (new_mesh.Dimension() == 3) {
282 shape_displacements_[mesh_tag] =
283 std::make_unique<FiniteElementState>(new_mesh,
SHAPE_DIM_3, mesh_tag +
"_shape_displacement");
285 SLIC_ERROR_ROOT(axom::fmt::format(
"Mesh of dimension {} given, only dimensions 2 or 3 are available in Serac.",
286 new_mesh.Dimension()));
291 *shape_displacements_[mesh_tag] = 0.0;
296 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
297 axom::fmt::format(
"Mesh tag \"{}\" not found in the data store", mesh_tag));
298 auto mesh = datacolls_.at(mesh_tag).GetMesh();
299 SLIC_ERROR_ROOT_IF(!
mesh,
"The datacollection does not contain a mesh object");
300 return static_cast<mfem::ParMesh&
>(*mesh);
305 for (
auto& [name, datacoll] : datacolls_) {
306 if (datacoll.GetMesh() == pmesh) {
310 SLIC_ERROR_ROOT(
"The mesh has not been registered with StateManager");
316 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
317 axom::fmt::format(
"Mesh tag \"{}\" not found in the data store", mesh_tag));
318 return datacolls_.at(mesh_tag).GetCycle();
323 SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
324 axom::fmt::format(
"Mesh tag \"{}\" not found in the data store", mesh_tag));
325 return datacolls_.at(mesh_tag).GetTime();
Class for encapsulating the dual vector space of a finite element space (i.e. the space of linear for...
Class for encapsulating the critical MFEM components of a primal finite element field.
void setFromGridFunction(const mfem::ParGridFunction &grid_function)
Initialize the true vector in the FiniteElementState based on an input grid function.
mfem::ParFiniteElementSpace & space()
Returns a non-owning reference to the internal FESpace.
std::string name() const
Returns the name of the FEState (field)
mfem::ParMesh & mesh()
Returns a non-owning reference to the internal mesh object.
static void loadCheckpointedStates(int cycle_to_load, std::vector< std::reference_wrapper< FiniteElementState >> states_to_load)
loads the finite element states from a previously checkpointed cycle
static void initialize(axom::sidre::DataStore &ds, const std::string &output_directory)
Initializes the StateManager with a sidre DataStore (into which state will be written/read)
static void storeDual(FiniteElementDual &dual)
Store a pre-constructed finite element dual in the state manager.
static int cycle(std::string mesh_tag)
Get the current cycle (iteration number) from the underlying datacollection.
static double time(std::string mesh_tag)
Get the current simulation time from the underlying datacollection.
static FiniteElementState newState(FunctionSpace space, const std::string &state_name, const std::string &mesh_tag)
Factory method for creating a new FEState object.
static std::string collectionID(const mfem::ParMesh *pmesh)
Returns the datacollection ID for a given mesh.
static void reset()
Resets the underlying global datacollection object.
static FiniteElementDual newDual(FunctionSpace space, const std::string &dual_name, const std::string &mesh_tag)
Factory method for creating a new FEDual object.
static mfem::ParMesh & mesh(const std::string &mesh_tag)
Returns a non-owning reference to mesh held by StateManager.
static void storeState(FiniteElementState &state)
Store a pre-constructed finite element state in the state manager.
static void save(const double t, const int cycle, const std::string &mesh_tag)
Updates the Conduit Blueprint state in the datastore and saves to a file.
static FiniteElementState & shapeDisplacement(const std::string &mesh_tag)
Get the shape displacement finite element state.
static mfem::ParMesh & setMesh(std::unique_ptr< mfem::ParMesh > pmesh, const std::string &mesh_tag)
Gives ownership of mesh to StateManager.
Accelerator functionality.
constexpr H1< SHAPE_ORDER, 2 > SHAPE_DIM_2
Function space for shape displacement on dimension 2 meshes.
constexpr H1< SHAPE_ORDER, 3 > SHAPE_DIM_3
Function space for shape displacement on dimension 2 meshes.
dual(double, T) -> dual< T >
class template argument deduction guide for type dual.
This file contains the declaration of the StateManager class.
Dual number struct (value plus gradient)