Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
field_store.hpp
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
7 #pragma once
8 
12 #include "smith/physics/mesh.hpp"
13 
14 #include <map>
15 #include <set>
16 #include <string>
17 #include <vector>
18 #include <memory>
19 
20 namespace smith {
21 
22 class DirichletBoundaryConditions;
23 class BoundaryConditionManager;
24 
28 struct ReactionInfo {
29  std::string name;
30  const mfem::ParFiniteElementSpace* space = nullptr;
31 };
32 
46 template <typename Space, typename Time = void*>
47 struct FieldType {
48  using space_type = Space;
49 
55  FieldType(std::string n, bool is_unknown_ = false) : name(n), is_unknown(is_unknown_) {}
56  std::string name;
57  bool is_unknown = false;
58 };
59 
63 struct FieldStore {
70  FieldStore(std::shared_ptr<Mesh> mesh, size_t storage_size = 50, std::string prepend_name = "");
71 
79  std::string prefix(const std::string& base) const;
80 
84  enum class TimeDerivative
85  {
86  VAL, //< The value of the field.
87  DOT,
88  DDOT,
89  DDDOT
90  };
91 
97  template <typename Space>
99  {
100  type.name = prefix(type.name);
101  shape_disp_.push_back(smith::createFieldState<Space>(*graph_, Space{}, type.name, mesh_->tag()));
102  }
103 
109  template <typename Space>
111  {
112  type.name = prefix(type.name);
113  if (to_params_index_.count(type.name)) {
114  // Already registered — expected when multiple systems share the same parameter.
115  // Verify the space matches by checking vdim (== Space::components).
116  auto& existing = params_[to_params_index_.at(type.name)];
117  SLIC_ERROR_ROOT_IF(existing.get()->space().GetVDim() != Space::components,
118  axom::fmt::format("Parameter '{}' re-registered with a different space "
119  "(existing vdim={}, new vdim={})",
120  type.name, existing.get()->space().GetVDim(), Space::components));
121  return;
122  }
123  to_params_index_[type.name] = params_.size();
124  params_.push_back(smith::createFieldState<Space>(*graph_, Space{}, type.name, mesh_->tag()));
125  }
126 
141  template <typename Space>
142  std::shared_ptr<DirichletBoundaryConditions> addIndependent(FieldType<Space>& type,
143  std::shared_ptr<TimeIntegrationRule> time_rule)
144  {
145  type.name = prefix(type.name);
146  type.is_unknown = true;
147  to_states_index_[type.name] = states_.size();
148  FieldState new_field = smith::createFieldState<Space>(*graph_, Space{}, type.name, mesh_->tag());
149  states_.push_back(new_field);
150  is_solve_state_.push_back(true);
151  auto latest_bc = addBoundaryConditions(new_field.get());
152  boundary_conditions_[type.name] = latest_bc;
153 
154  SLIC_ERROR_IF(!time_rule, "Invalid time_rule");
155 
156  TimeIntegrationMapping mapping;
157  mapping.primary_name = type.name;
158  independent_name_to_rule_index_[type.name] = time_integration_rules_.size();
159  time_integration_rules_.push_back({time_rule, mapping});
160 
161  return latest_bc;
162  }
163 
186  template <typename Space>
187  auto addDependent(FieldType<Space> independent_field, TimeDerivative derivative, std::string name_override = "")
188  {
189  std::string suffix;
190  if (derivative == TimeDerivative::VAL) {
191  suffix = "_old";
192  } else if (derivative == TimeDerivative::DOT) {
193  suffix = "_dot_old";
194  } else if (derivative == TimeDerivative::DDOT) {
195  suffix = "_ddot_old";
196  } else {
197  SLIC_ERROR("Unsupported TimeDerivative");
198  }
199 
200  std::string name = name_override.empty() ? independent_field.name + suffix : prefix(name_override);
201 
202  if (independent_name_to_rule_index_.count(independent_field.name)) {
203  size_t rule_idx = independent_name_to_rule_index_.at(independent_field.name);
204  auto& mapping = time_integration_rules_[rule_idx].second;
205  if (derivative == TimeDerivative::VAL) {
206  mapping.history_name = name;
207  } else if (derivative == TimeDerivative::DOT) {
208  mapping.dot_name = name;
209  } else if (derivative == TimeDerivative::DDOT) {
210  mapping.ddot_name = name;
211  }
212  } else {
213  SLIC_WARNING("Adding dependent time integration field for independent field '"
214  << independent_field.name << "' which has no registered TimeIntegrationRule.");
215  }
216 
217  to_states_index_[name] = states_.size();
218  states_.push_back(smith::createFieldState<Space>(*graph_, Space{}, name, mesh_->tag()));
219  is_solve_state_.push_back(false);
220  return FieldType<Space>(name);
221  }
222 
229  void addWeakFormUnknownArg(std::string weak_form_name, std::string argument_name, size_t argument_index);
230 
237  void addWeakFormArg(std::string weak_form_name, std::string argument_name, size_t argument_index);
238 
249  void addWeakFormReaction(std::string weak_form_name, std::string field_name);
250 
257  void markWeakFormInternal(const std::string& weak_form_name);
258 
264  std::string getWeakFormReaction(const std::string& weak_form_name) const;
265 
289  template <typename... FieldTypes>
290  std::vector<const mfem::ParFiniteElementSpace*> createSpaces(const std::string& weak_form_name,
291  const std::string& reaction_field_name,
292  FieldTypes... types)
293  {
294  addWeakFormReaction(weak_form_name, reaction_field_name);
295  std::vector<const mfem::ParFiniteElementSpace*> spaces;
296  size_t arg_num = 0;
297  auto register_field = [&](auto type) {
298  spaces.push_back(&getField(type.name).get()->space());
299  addWeakFormArg(weak_form_name, type.name, arg_num);
300  if (type.is_unknown) {
301  addWeakFormUnknownArg(weak_form_name, type.name, arg_num);
302  }
303  ++arg_num;
304  };
305  (register_field(types), ...);
306  return spaces;
307  }
308 
313  std::string primary_name;
314  std::string history_name;
315  std::string dot_name;
316  std::string ddot_name;
317  };
318 
324  const std::vector<std::pair<std::shared_ptr<TimeIntegrationRule>, TimeIntegrationMapping>>& getTimeIntegrationRules()
325  const;
326 
330  void printMap();
331 
337  std::vector<std::vector<size_t>> indexMap(const std::vector<std::string>& residual_names) const;
338 
354  std::vector<const BoundaryConditionManager*> getBoundaryConditionManagers(
355  const std::vector<std::string>& weak_form_names) const;
356 
358  std::vector<const BoundaryConditionManager*> getBoundaryConditionManagersForFields(
359  const std::vector<std::string>& field_names) const;
360 
366  bool hasField(const std::string& field_name) const;
367 
373  size_t getFieldIndex(const std::string& field_name) const;
374 
380  FieldState getField(const std::string& field_name) const;
381 
387  FieldState getParameter(const std::string& param_name) const;
388 
394  void setField(const std::string& field_name, FieldState updated_field);
395 
401  void setField(size_t index, FieldState updated_field);
402 
407  FieldState getShapeDisp() const;
408 
413  const std::vector<FieldState>& getAllFields() const;
414 
420  std::vector<FieldState> getStates(const std::string& weak_form_name) const;
421 
429  std::vector<FieldState> getStatesFromVectors(const std::string& weak_form_name,
430  const std::vector<FieldState>& state_fields,
431  const std::vector<FieldState>& param_fields) const;
432 
436  const std::vector<FieldState>& getParameterFields() const;
437 
441  const std::vector<FieldState>& getStateFields() const;
442 
446  std::vector<FieldState> getOutputFieldStates() const;
447 
451  std::vector<ReactionInfo> getReactionInfos() const;
452 
456  const std::shared_ptr<smith::Mesh>& getMesh() const;
457 
461  std::shared_ptr<DirichletBoundaryConditions> getBoundaryConditions(const std::string& field_name) const;
462 
467  const std::shared_ptr<gretl::DataStore>& graph() const;
468 
469  private:
470  std::string resolveFieldName(const std::string& field_name) const;
471 
472  std::shared_ptr<Mesh> mesh_;
473  std::shared_ptr<gretl::DataStore> graph_;
474  std::string prepend_name_;
475 
476  std::vector<FieldState> shape_disp_;
477  std::vector<FieldState> params_;
478  std::vector<FieldState> states_;
479  std::vector<bool> is_solve_state_;
480 
481  std::map<std::string, size_t> to_states_index_;
482  std::map<std::string, size_t> to_params_index_;
483 
485  std::map<std::string, std::shared_ptr<DirichletBoundaryConditions>> boundary_conditions_;
486 
487  struct FieldLabel {
488  std::string field_name;
489  size_t field_index_in_residual;
490  };
491 
492  std::shared_ptr<DirichletBoundaryConditions> addBoundaryConditions(FEFieldPtr field);
493 
494  std::map<std::string, std::vector<FieldLabel>> weak_form_name_to_unknown_name_index_;
495 
496  std::map<std::string, std::vector<size_t>> weak_form_name_to_field_indices_;
497  std::map<std::string, std::vector<std::string>> weak_form_name_to_field_names_;
498 
499  std::vector<std::pair<std::string, std::string>> weak_form_to_test_field_;
500  std::set<std::string> internal_weak_forms_;
501 
502  std::vector<std::pair<std::shared_ptr<TimeIntegrationRule>, TimeIntegrationMapping>> time_integration_rules_;
503  std::map<std::string, size_t> independent_name_to_rule_index_;
504 };
505 
512 template <int spatial_dim, typename TestSpaceType, typename... InputSpaceTypes>
513 auto createWeakForm(std::string name, FieldType<TestSpaceType> test_type, FieldStore& field_store,
514  FieldType<InputSpaceTypes>... field_types)
515 {
516  return std::make_shared<FunctionalWeakForm<spatial_dim, TestSpaceType, Parameters<InputSpaceTypes...>>>(
517  name, field_store.getMesh(), field_store.getField(test_type.name).get()->space(),
518  field_store.createSpaces(name, test_type.name, field_types...));
519 }
520 
525 inline std::shared_ptr<FieldStore> fieldStore(std::shared_ptr<Mesh> mesh, std::size_t storage_size = 200,
526  std::string prefix = "")
527 {
528  return std::make_shared<FieldStore>(std::move(mesh), storage_size, std::move(prefix));
529 }
530 
531 } // namespace smith
Implements the WeakForm interface using smith::ShapeAwareFunctional. Allows for generic specification...
Smith mesh class which assists in constructing the appropriate parallel mfem meshes and registering a...
Accelerator functionality.
Definition: smith.cpp:36
std::vector< const mfem::ParFiniteElementSpace * > spaces(const std::vector< FieldState > &states, const std::vector< FieldState > &params={})
Get the spaces from the primal fields of a vector of field states.
std::shared_ptr< FiniteElementState > FEFieldPtr
typedef
Definition: field_state.hpp:20
auto createWeakForm(std::string name, FieldType< TestSpaceType > test_type, FieldStore &field_store, FieldType< InputSpaceTypes >... field_types)
Create a FunctionalWeakForm and register its fields in the FieldStore.
gretl::State< FEFieldPtr, FEDualPtr > FieldState
typedef
Definition: field_state.hpp:22
std::shared_ptr< FieldStore > fieldStore(std::shared_ptr< Mesh > mesh, std::size_t storage_size=200, std::string prefix="")
Construct a shared_ptr<FieldStore> over a mesh. Inline call-site helper for standalone-physics setup;...
Mapping between primary and history/derivative fields for time integration.
std::string history_name
Previous time step value field name.
std::string primary_name
Primary unknown field name.
std::string ddot_name
Second time derivative field name.
std::string dot_name
First time derivative field name.
Manages storage and metadata for fields, parameters, and weak forms.
Definition: field_store.hpp:63
void printMap()
Print the internal field maps for debugging.
Definition: field_store.cpp:56
std::vector< FieldState > getOutputFieldStates() const
Get the list of physical, non-solve state fields suitable for output.
const std::vector< FieldState > & getParameterFields() const
Get the list of all parameter fields.
const std::vector< std::pair< std::shared_ptr< TimeIntegrationRule >, TimeIntegrationMapping > > & getTimeIntegrationRules() const
Get all registered time integration rules and their mappings.
bool hasField(const std::string &field_name) const
Check whether a field exists.
const std::vector< FieldState > & getAllFields() const
Get all fields stored in the FieldStore.
std::vector< std::vector< size_t > > indexMap(const std::vector< std::string > &residual_names) const
Generate an index map for the residuals.
Definition: field_store.cpp:67
std::string prefix(const std::string &base) const
Apply this store's namespace prefix to a base name.
Definition: field_store.cpp:21
std::string getWeakFormReaction(const std::string &weak_form_name) const
Get the name of the reaction (test) field for a weak form.
std::shared_ptr< DirichletBoundaryConditions > addIndependent(FieldType< Space > &type, std::shared_ptr< TimeIntegrationRule > time_rule)
Add an independent field (a solver unknown) to the store.
const std::shared_ptr< smith::Mesh > & getMesh() const
Get associated mesh shared by all registered fields.
const std::vector< FieldState > & getStateFields() const
Get the list of all state fields.
void setField(const std::string &field_name, FieldState updated_field)
Update a field in the store by name.
void addWeakFormArg(std::string weak_form_name, std::string argument_name, size_t argument_index)
Register an argument to a weak form.
Definition: field_store.cpp:44
TimeDerivative
Enum for different types of time derivatives.
Definition: field_store.hpp:85
@ DDDOT
The third time derivative.
@ DOT
The first time derivative.
@ DDOT
The second time derivative.
void addWeakFormReaction(std::string weak_form_name, std::string field_name)
Register the reaction (test) field for a weak form.
FieldState getParameter(const std::string &param_name) const
Get a parameter field by name.
size_t getFieldIndex(const std::string &field_name) const
Get the internal index of a field by name.
std::vector< FieldState > getStates(const std::string &weak_form_name) const
Get the state fields associated with a weak form.
void addShapeDisp(FieldType< Space > &type)
Add a shape displacement field to the store.
Definition: field_store.hpp:98
FieldState getShapeDisp() const
Get the shape displacement field.
std::vector< const BoundaryConditionManager * > getBoundaryConditionManagers(const std::vector< std::string > &weak_form_names) const
Get the boundary condition managers for the given weak forms, one per residual row.
void addWeakFormUnknownArg(std::string weak_form_name, std::string argument_name, size_t argument_index)
Register an argument to a weak form as an unknown.
Definition: field_store.cpp:34
std::vector< const mfem::ParFiniteElementSpace * > createSpaces(const std::string &weak_form_name, const std::string &reaction_field_name, FieldTypes... types)
Register all input fields for a weak form and return their FE spaces.
auto addDependent(FieldType< Space > independent_field, TimeDerivative derivative, std::string name_override="")
Add a dependent field (history value, velocity, or acceleration) to the store.
std::vector< FieldState > getStatesFromVectors(const std::string &weak_form_name, const std::vector< FieldState > &state_fields, const std::vector< FieldState > &param_fields) const
Extract state fields for a weak form from provided state and parameter vectors.
std::shared_ptr< DirichletBoundaryConditions > getBoundaryConditions(const std::string &field_name) const
Get the boundary conditions for a given field name.
std::vector< const BoundaryConditionManager * > getBoundaryConditionManagersForFields(const std::vector< std::string > &field_names) const
Get ordered boundary condition managers corresponding to an ordered list of fields.
void addParameter(FieldType< Space > &type)
Add a parameter field to the store.
FieldState getField(const std::string &field_name) const
Get a FieldState by name.
const std::shared_ptr< gretl::DataStore > & graph() const
Get the associated data store graph.
std::vector< ReactionInfo > getReactionInfos() const
Get information about reaction fields.
FieldStore(std::shared_ptr< Mesh > mesh, size_t storage_size=50, std::string prepend_name="")
Construct a new FieldStore object.
Definition: field_store.cpp:14
void markWeakFormInternal(const std::string &weak_form_name)
Mark a weak form as internal so it is excluded from getReactionInfos().
Representation of a field type with a name and a flag indicating whether it is an active Jacobian unk...
Definition: field_store.hpp:47
bool is_unknown
True if this field is a Jacobian variable in the current weak-form context.
Definition: field_store.hpp:57
std::string name
Name of the field.
Definition: field_store.hpp:56
Space space_type
The finite element space type.
Definition: field_store.hpp:48
FieldType(std::string n, bool is_unknown_=false)
Construct a new FieldType object.
Definition: field_store.hpp:55
a struct that is used in the physics modules to clarify which template arguments are user-controlled ...
Definition: common.hpp:59
Information about a dual field.
Definition: field_store.hpp:28
std::string name
The name of the dual field.
Definition: field_store.hpp:29
const mfem::ParFiniteElementSpace * space
The finite element space of the dual field.
Definition: field_store.hpp:30
Provides templated implementations for discretizing values, velocities and accelerations from current...