11 #include "axom/fmt.hpp"
22 bool checkpoint_to_disk)
23 : name_(physics_name),
26 comm_(mesh_.GetComm()),
27 shape_displacement_(
StateManager::shapeDisplacement(mesh_tag_)),
29 checkpoint_to_disk_(checkpoint_to_disk)
33 if (
mesh_.Dimension() == 2) {
36 }
else if (
mesh_.Dimension() == 3) {
40 SLIC_ERROR_ROOT(axom::fmt::format(
"Mesh of dimension {} given, only dimensions 2 or 3 are available in Serac.",
85 axom::fmt::format(
"Parameter '{}' requested when only '{}' parameters exist in physics module '{}'",
88 SLIC_ERROR_ROOT_IF(¶meter_state.
mesh() != &
mesh_,
89 axom::fmt::format(
"Mesh of parameter '{}' is not the same as the physics mesh", parameter_index));
92 parameter_state.
space().GetTrueVSize() !=
parameters_[parameter_index].state->space().GetTrueVSize(),
94 "Physics module parameter '{}' has size '{}' while given state has size '{}'. The finite element "
95 "spaces are inconsistent.",
96 parameter_index,
parameters_[parameter_index].state->space().GetTrueVSize(),
97 parameter_state.
space().GetTrueVSize()));
98 *
parameters_[parameter_index].state = parameter_state;
103 SLIC_ERROR_ROOT_IF(&shape_displacement.
mesh() != &
mesh_,
104 axom::fmt::format(
"Mesh of shape displacement is not the same as the physics mesh"));
109 "Physics module shape displacement has size '{}' while given state has size '{}'. The finite element "
110 "spaces are inconsistent.",
117 std::string output_name =
name_;
118 if (output_name ==
"") {
119 output_name =
"default";
123 std::make_unique<mfem::ParaViewDataCollection>(output_name,
const_cast<mfem::ParMesh*
>(&
states_.front()->mesh()));
124 int max_order_in_fields = 0;
134 std::make_unique<mfem::ParGridFunction>(
const_cast<mfem::ParFiniteElementSpace*
>(&
dual->space()));
135 max_order_in_fields =
std::max(max_order_in_fields,
dual->space().GetOrder(0));
206 if (paraview_output_dir) {
240 const std::string summary_group_name =
"serac_summary";
241 axom::sidre::Group* sidre_root = datastore.getRoot();
243 sidre_root->hasGroup(summary_group_name),
244 axom::fmt::format(
"Sidre Group '{0}' cannot exist when initializeSummary is called", summary_group_name));
245 axom::sidre::Group* summary_group = sidre_root->createGroup(summary_group_name);
248 summary_group->createViewScalar(
"mpi_rank_count", count);
251 axom::sidre::Group* curves_group = summary_group->createGroup(
"curves");
254 axom::IndexType array_size =
static_cast<axom::IndexType
>(ceil(t_final / dt));
257 axom::sidre::View* t_array_view = curves_group->createView(
"t");
258 axom::sidre::Array<double> ts(t_array_view, 0, array_size);
262 axom::sidre::Group* state_group = curves_group->createGroup(
state->
name());
265 for (std::string stat_name : {
"l1norms",
"l2norms",
"linfnorms",
"avgs",
"mins",
"maxs"}) {
266 axom::sidre::View* curr_array_view = state_group->createView(stat_name);
267 axom::sidre::Array<double> array(curr_array_view, 0, array_size);
277 axom::sidre::Group* curves_group =
nullptr;
280 axom::sidre::Group* sidre_root = datastore.getRoot();
281 const std::string curves_group_name =
"serac_summary/curves";
282 SLIC_ERROR_IF(!sidre_root->hasGroup(curves_group_name),
283 axom::fmt::format(
"Sidre Group '{0}' did not exist when saveCurves was called", curves_group_name));
284 curves_group = sidre_root->getGroup(curves_group_name);
287 axom::sidre::Array<double> ts(curves_group->getView(
"t"));
292 double l1norm_value, l2norm_value, linfnorm_value, avg_value, max_value, min_value;
298 linfnorm_value =
norm(*
state, mfem::infinity());
306 axom::sidre::Group* state_group = curves_group->getGroup(
state->
name());
309 axom::sidre::View* l1norms_view = state_group->getView(
"l1norms");
310 axom::sidre::Array<double> l1norms(l1norms_view);
311 l1norms.push_back(l1norm_value);
313 axom::sidre::View* l2norms_view = state_group->getView(
"l2norms");
314 axom::sidre::Array<double> l2norms(l2norms_view);
315 l2norms.push_back(l2norm_value);
317 axom::sidre::View* linfnorms_view = state_group->getView(
"linfnorms");
318 axom::sidre::Array<double> linfnorms(linfnorms_view);
319 linfnorms.push_back(linfnorm_value);
321 axom::sidre::View* avgs_view = state_group->getView(
"avgs");
322 axom::sidre::Array<double> avgs(avgs_view);
323 avgs.push_back(avg_value);
325 axom::sidre::View* maxs_view = state_group->getView(
"maxs");
326 axom::sidre::Array<double> maxs(maxs_view);
327 maxs.push_back(max_value);
329 axom::sidre::View* mins_view = state_group->getView(
"mins");
330 axom::sidre::Array<double> mins(mins_view);
331 mins.push_back(min_value);
349 axom::fmt::format(
"Requested state name {} does not exist in physics module {}.", state_name,
name_));
356 axom::fmt::format(
"Requested state name {} does not exist in physics module {}.", state_name,
name_));
363 SLIC_ERROR_ROOT(axom::fmt::format(
364 "loadCheckpointedState and getCheckpointedStates not implemented for physics module {}.",
name_));
365 std::unordered_map<std::string, FiniteElementState> empty_container;
366 return empty_container;
371 SLIC_ERROR_ROOT_IF(
cycle < 0, axom::fmt::format(
"Negative cycle number requested for physics module {}.",
name_));
373 axom::fmt::format(
"Timestep for cycle {} requested, but physics module has only reached cycle {}.",
379 std::string addPrefix(
const std::string& prefix,
const std::string& target)
381 if (prefix.empty()) {
384 return prefix +
"_" + target;
387 std::string removePrefix(
const std::string& prefix,
const std::string& target)
389 std::string modified_target{target};
391 if (!prefix.empty()) {
393 auto index = modified_target.find(prefix +
"_");
396 modified_target.erase(0, prefix.size() + 1);
399 return modified_target;
The base interface class for a generic PDE solver.
virtual std::vector< double > timesteps() const
Get a vector of the timestep sizes (i.e. s) taken by the forward solver.
std::optional< int > cached_checkpoint_cycle_
An optional int for disk-based checkpointing containing the cycle number of the last retrieved checkp...
mfem::ParMesh & mesh_
The primary mesh.
std::unordered_map< std::string, serac::FiniteElementState > cached_checkpoint_states_
A container relating a checkpointed cycle and the associated finite element state fields.
std::vector< const serac::FiniteElementDual * > duals_
List of finite element duals associated with this physics module.
virtual void initializeSummary(axom::sidre::DataStore &datastore, const double t_final, const double dt) const
Initializes the Sidre structure for simulation summary data.
virtual void saveSummary(axom::sidre::DataStore &datastore, const double t) const
Saves the summary data to the Sidre Datastore.
std::unique_ptr< FiniteElementDual > shape_displacement_sensitivity_
Sensitivity with respect to the shape displacement field.
double max_time_
The maximum time reached for the forward solver.
int cycle_
Current cycle (forward pass time iteration count)
std::vector< const serac::FiniteElementState * > states_
List of finite element primal states associated with this physics module.
virtual double time() const
Get the current forward-solution time.
std::unordered_map< std::string, std::vector< serac::FiniteElementState > > checkpoint_states_
A map containing optionally in-memory checkpointed primal states for transient adjoint solvers.
double min_time_
The time the forward solver was initialized to.
double time_
Current time for the forward pass.
FiniteElementState & shape_displacement_
The parameter info associated with the shape displacement field.
int min_cycle_
The cycle the forward solver was initialized to.
bool checkpoint_to_disk_
A flag denoting whether to save the state to disk or memory as needed for dynamic adjoint solves.
double ode_time_point_
The value of time at which the ODE solver wants to evaluate the residual.
int max_cycle_
The maximum cycle (forward pass iteration count) reached by the forward solver.
virtual int cycle() const
Get the current forward-solution cycle iteration number.
void setShapeDisplacement(const FiniteElementState &shape_displacement)
Set the current shape displacement for the underlying mesh.
const FiniteElementState & parameter(const std::string ¶meter_name) const
Accessor for getting named finite element state parameter fields from the physics modules.
void UpdateParaviewDataCollection(const std::string ¶view_output_dir) const
Update the paraview states, duals, parameters, and metadata (cycle, time) in preparation for output.
virtual const FiniteElementState & state(const std::string &state_name) const =0
Accessor for getting named finite element state primal solution from the physics modules.
virtual double minTime() const
Get the initial time used by the forward solver.
std::string mesh_tag_
ID of the corresponding MFEMSidreDataCollection (denoting a mesh)
std::unique_ptr< mfem::ParaViewDataCollection > paraview_dc_
DataCollection pointer for optional paraview output.
FiniteElementState loadCheckpointedState(const std::string &state_name, int cycle) const
Accessor for getting a single named finite element state primal solution from the physics modules at ...
std::unique_ptr< mfem::ParGridFunction > shape_sensitivity_grid_function_
A optional view of the shape sensitivity in grid function form for paraview output.
virtual double getCheckpointedTimestep(int cycle) const
Get a timestep increment which has been previously checkpointed at the give cycle.
virtual void outputStateToDisk(std::optional< std::string > paraview_output_dir={}) const
Output the current state of the PDE fields in Sidre format and optionally in Paraview format if parav...
void setParameter(const size_t parameter_index, const FiniteElementState ¶meter_state)
Deep copy a parameter field into the internally-owned parameter used for simulations.
std::vector< ParameterInfo > parameters_
A vector of the parameters associated with this physics module.
virtual std::unordered_map< std::string, FiniteElementState > getCheckpointedStates(int cycle) const
Accessor for getting all of the primal solutions from the physics modules at a given checkpointed cyc...
std::string name_
Name of the physics module.
virtual int minCycle() const
Get the initial cycle (timestep iteration number) used by the forward solver.
void CreateParaviewDataCollection() const
Create a paraview data collection for the physics package if requested.
virtual double maxTime() const
Get the maximum time reached by the forward solver.
std::unordered_map< std::string, std::unique_ptr< mfem::ParGridFunction > > paraview_dual_grid_functions_
A optional map of the dual names and duals in grid function form for paraview output.
void initializeBasePhysicsStates(int cycle, double time)
Protected, non-virtual method to reset physics states to zero. This does not reset design parameters ...
MPI_Comm comm_
The MPI communicator.
std::vector< double > timesteps_
A vector of the timestep sizes (i.e. ) taken by the forward solver.
BasePhysics(std::string physics_name, std::string mesh_tag, int cycle=0, double time=0.0, bool checkpoint_to_disk=false)
Empty constructor.
virtual int maxCycle() const
The maximum cycle (timestep iteration number) reached by the forward solver.
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.
mfem::ParGridFunction & gridFunction() const
Construct a grid function from the finite element state true vector.
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.
Manages the lifetimes of FEState objects such that restarts are abstracted from physics modules.
static void updateState(const FiniteElementState &state)
Updates the StateManager-owned grid function using the values from a given FiniteElementState.
static void updateDual(const FiniteElementDual &dual)
Updates the StateManager-owned grid function using the values from a given FiniteElementDual.
static void storeDual(FiniteElementDual &dual)
Store a pre-constructed finite element dual 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.
This file contains the declaration of structure that manages the MFEM objects that make up the state ...
A function intended to be used as part of a driver to initialize common libraries.
This file contains the all the necessary functions and macros required for logging as well as a helpe...
Accelerator functionality.
SERAC_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
SERAC_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
double avg(const FiniteElementVector &fe_vector)
Find the average value of a finite element vector across all dofs.
std::pair< int, int > getMPIInfo(MPI_Comm comm)
Returns the number of processes and rank for an MPI communicator.
constexpr SERAC_HOST_DEVICE auto norm(const isotropic_tensor< T, m, m > &I)
compute the Frobenius norm (sqrt(tr(dot(transpose(I), I)))) of an isotropic tensor
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)
Helper functions for exiting Serac cleanly.