Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
solid_mechanics_system.hpp
Go to the documentation of this file.
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 
12 #pragma once
13 
14 #include "smith/differentiable_numerics/field_store.hpp"
18 #include "smith/differentiable_numerics/multiphysics_time_integrator.hpp"
24 
25 namespace smith {
26 
39 template <int dim, int order, typename DisplacementTimeRule = ImplicitNewmarkSecondOrderTimeIntegrationRule,
40  typename... parameter_space>
42  static_assert(DisplacementTimeRule::num_states == 4, "SolidMechanicsSystem requires a 4-state time integration rule");
43 
48 
53 
54  std::shared_ptr<SolidWeakFormType> solid_weak_form;
55  std::shared_ptr<CycleZeroSolidWeakFormType>
57  std::shared_ptr<DirichletBoundaryConditions> disp_bc;
58  std::shared_ptr<DisplacementTimeRule> disp_time_rule;
59 
64  std::vector<FieldState> getStateFields() const
65  {
66  return {field_store->getField(prefix("displacement_solve_state")), field_store->getField(prefix("displacement")),
67  field_store->getField(prefix("velocity")), field_store->getField(prefix("acceleration"))};
68  }
69 
74  std::vector<FieldState> getOutputFieldStates() const
75  {
76  return {field_store->getField(prefix("displacement")), field_store->getField(prefix("velocity")),
77  field_store->getField(prefix("acceleration"))};
78  }
79 
84  std::vector<ReactionInfo> getReactionInfos() const
85  {
86  return {{prefix("reactions"), &field_store->getField(prefix("displacement")).get()->space()}};
87  }
88 
94  std::unique_ptr<DifferentiablePhysics> createDifferentiablePhysics(std::string physics_name)
95  {
96  return std::make_unique<DifferentiablePhysics>(field_store->getMesh(), field_store->graph(),
97  field_store->getShapeDisp(), getStateFields(), getParameterFields(),
98  advancer, physics_name, getReactionInfos());
99  }
100 
107  template <typename MaterialType>
108  void setMaterial(const MaterialType& material, const std::string& domain_name)
109  {
110  auto captured_rule = disp_time_rule;
111  solid_weak_form->addBodyIntegral(
112  domain_name, [=](auto t_info, auto /*X*/, auto u, auto u_old, auto v_old, auto a_old, auto... params) {
113  auto [u_current, v_current, a_current] = captured_rule->interpolate(t_info, u, u_old, v_old, a_old);
114 
115  typename MaterialType::State state;
116  auto pk_stress = material(state, get<DERIVATIVE>(u_current), params...);
117 
118  return smith::tuple{get<VALUE>(a_current) * material.density, pk_stress};
119  });
120 
121  // Add to cycle-zero weak form (at cycle 0, u and v are given, solve for a)
122  cycle_zero_solid_weak_form->addBodyIntegral(
123  domain_name, [=](auto /*t_info*/, auto /*X*/, auto u, auto /*v_old*/, auto a, auto... params) {
124  typename MaterialType::State state;
125  auto pk_stress = material(state, get<DERIVATIVE>(u), params...);
126 
127  return smith::tuple{get<VALUE>(a) * material.density, pk_stress};
128  });
129  }
130 
139  template <int... active_parameters, typename BodyForceType>
140  void addBodyForce(DependsOn<active_parameters...> depends_on, const std::string& domain_name,
141  BodyForceType force_function)
142  {
143  auto captured_rule = disp_time_rule;
144  solid_weak_form->addBodySource(
145  depends_on, domain_name, [=](auto t_info, auto X, auto u, auto u_old, auto v_old, auto a_old, auto... params) {
146  auto [u_current, v_current, a_current] = captured_rule->interpolate(t_info, u, u_old, v_old, a_old);
147  return force_function(t_info.time(), X, u_current, v_current, a_current, params...);
148  });
149 
150  addCycleZeroBodySourceImpl(
151  domain_name,
152  [=](auto t_info, auto X, auto u, auto v_old, auto a, auto... params) {
153  return force_function(t_info.time(), X, u, v_old, a, params...);
154  },
155  std::make_index_sequence<3 + sizeof...(parameter_space)>{});
156  }
157 
164  template <typename BodyForceType>
165  void addBodyForce(const std::string& domain_name, BodyForceType force_function)
166  {
167  addBodyForceAllParams(domain_name, force_function, std::make_index_sequence<4 + sizeof...(parameter_space)>{});
168  }
169 
178  template <int... active_parameters, typename TractionType>
179  void addTraction(DependsOn<active_parameters...> depends_on, const std::string& domain_name,
180  TractionType traction_function)
181  {
182  auto captured_rule = disp_time_rule;
183  solid_weak_form->addBoundaryFlux(
184  depends_on, domain_name,
185  [=](auto t_info, auto X, auto n, auto u, auto u_old, auto v_old, auto a_old, auto... params) {
186  auto [u_current, v_current, a_current] = captured_rule->interpolate(t_info, u, u_old, v_old, a_old);
187  return traction_function(t_info.time(), X, n, u_current, v_current, a_current, params...);
188  });
189 
190  addCycleZeroBoundaryFluxImpl(
191  domain_name,
192  [=](auto t_info, auto X, auto n, auto u, auto v_old, auto a, auto... params) {
193  return traction_function(t_info.time(), X, n, u, v_old, a, params...);
194  },
195  std::make_index_sequence<3 + sizeof...(parameter_space)>{});
196  }
197 
204  template <typename TractionType>
205  void addTraction(const std::string& domain_name, TractionType traction_function)
206  {
207  addTractionAllParams(domain_name, traction_function, std::make_index_sequence<4 + sizeof...(parameter_space)>{});
208  }
209 
218  template <int... active_parameters, typename PressureType>
219  void addPressure(DependsOn<active_parameters...> depends_on, const std::string& domain_name,
220  PressureType pressure_function)
221  {
222  auto captured_rule = disp_time_rule;
223  solid_weak_form->addBoundaryIntegral(
224  depends_on, domain_name, [=](auto t_info, auto X, auto u, auto u_old, auto v_old, auto a_old, auto... params) {
225  auto u_current = captured_rule->value(t_info, u, u_old, v_old, a_old);
226 
227  auto x_current = X + u_current;
228  auto n_deformed = cross(get<DERIVATIVE>(x_current));
229  auto n_shape_norm = norm(cross(get<DERIVATIVE>(X)));
230 
231  auto pressure = pressure_function(t_info.time(), get<VALUE>(X), get<VALUE>(params)...);
232 
233  return pressure * n_deformed * (1.0 / n_shape_norm);
234  });
235 
236  addCycleZeroBoundaryIntegralImpl(
237  domain_name,
238  [=](auto t_info, auto X, auto u, auto /*v_old*/, auto /*a*/, auto... params) {
239  auto u_current = u;
240 
241  auto x_current = X + u_current;
242  auto n_deformed = cross(get<DERIVATIVE>(x_current));
243  auto n_shape_norm = norm(cross(get<DERIVATIVE>(X)));
244 
245  auto pressure = pressure_function(t_info.time(), get<VALUE>(X), get<VALUE>(params)...);
246 
247  return pressure * n_deformed * (1.0 / n_shape_norm);
248  },
249  std::make_index_sequence<3 + sizeof...(parameter_space)>{});
250  }
251 
258  template <typename PressureType>
259  void addPressure(const std::string& domain_name, PressureType pressure_function)
260  {
261  addPressureAllParams(domain_name, pressure_function, std::make_index_sequence<4 + sizeof...(parameter_space)>{});
262  }
263 
264  private:
265  template <typename BodyForceType, std::size_t... Is>
266  void addBodyForceAllParams(const std::string& domain_name, BodyForceType force_function, std::index_sequence<Is...>)
267  {
268  addBodyForce(DependsOn<static_cast<int>(Is)...>{}, domain_name, force_function);
269  }
270 
271  template <typename TractionType, std::size_t... Is>
272  void addTractionAllParams(const std::string& domain_name, TractionType traction_function, std::index_sequence<Is...>)
273  {
274  addTraction(DependsOn<static_cast<int>(Is)...>{}, domain_name, traction_function);
275  }
276 
277  template <typename PressureType, std::size_t... Is>
278  void addPressureAllParams(const std::string& domain_name, PressureType pressure_function, std::index_sequence<Is...>)
279  {
280  addPressure(DependsOn<static_cast<int>(Is)...>{}, domain_name, pressure_function);
281  }
282 
283  // Cycle-zero helpers: always use all-params DependsOn with the 3-state cycle-zero form count
284  template <typename IntegrandType, std::size_t... Is>
285  void addCycleZeroBodySourceImpl(const std::string& name, IntegrandType f, std::index_sequence<Is...>)
286  {
287  cycle_zero_solid_weak_form->addBodySource(DependsOn<static_cast<int>(Is)...>{}, name, f);
288  }
289 
290  template <typename IntegrandType, std::size_t... Is>
291  void addCycleZeroBoundaryFluxImpl(const std::string& name, IntegrandType f, std::index_sequence<Is...>)
292  {
293  cycle_zero_solid_weak_form->addBoundaryFlux(DependsOn<static_cast<int>(Is)...>{}, name, f);
294  }
295 
296  template <typename IntegrandType, std::size_t... Is>
297  void addCycleZeroBoundaryIntegralImpl(const std::string& name, IntegrandType f, std::index_sequence<Is...>)
298  {
299  cycle_zero_solid_weak_form->addBoundaryIntegral(DependsOn<static_cast<int>(Is)...>{}, name, f);
300  }
301 };
302 
318 template <int dim, int order, typename DisplacementTimeRule, typename... parameter_space>
319 SolidMechanicsSystem<dim, order, DisplacementTimeRule, parameter_space...> buildSolidMechanicsSystem(
320  std::shared_ptr<Mesh> mesh, std::shared_ptr<CoupledSystemSolver> solver, DisplacementTimeRule disp_time_rule,
321  std::string prepend_name = "", std::shared_ptr<CoupledSystemSolver> cycle_zero_solver = nullptr,
322  FieldType<parameter_space>... parameter_types)
323 {
324  auto field_store = std::make_shared<FieldStore>(mesh, 100);
325 
326  auto prefix = [&](const std::string& name) {
327  if (prepend_name.empty()) {
328  return name;
329  }
330  return prepend_name + "_" + name;
331  };
332 
333  // Add shape displacement
334  FieldType<H1<1, dim>> shape_disp_type(prefix("shape_displacement"));
335  field_store->addShapeDisp(shape_disp_type);
336 
337  // Add displacement as independent (unknown) with time integration rule
338  auto disp_time_rule_ptr = std::make_shared<DisplacementTimeRule>(disp_time_rule);
339  FieldType<H1<order, dim>> disp_type(prefix("displacement_solve_state"));
340  auto disp_bc = field_store->addIndependent(disp_type, disp_time_rule_ptr);
341 
342  // Add dependent fields for time integration history
343  auto disp_old_type = field_store->addDependent(disp_type, FieldStore::TimeDerivative::VAL, prefix("displacement"));
344  auto velo_old_type = field_store->addDependent(disp_type, FieldStore::TimeDerivative::DOT, prefix("velocity"));
345  auto accel_old_type = field_store->addDependent(disp_type, FieldStore::TimeDerivative::DDOT, prefix("acceleration"));
346 
347  // Add parameters
348  std::vector<FieldState> parameter_fields;
349  (field_store->addParameter(FieldType<parameter_space>(prefix("param_" + parameter_types.name))), ...);
350  (parameter_fields.push_back(field_store->getField(prefix("param_" + parameter_types.name))), ...);
351 
352  using SystemType = SolidMechanicsSystem<dim, order, DisplacementTimeRule, parameter_space...>;
353 
354  // Create solid mechanics weak form (u, u_old, v_old, a_old)
355  std::string force_name = prefix("solid_force");
356  auto solid_weak_form = std::make_shared<typename SystemType::SolidWeakFormType>(
357  force_name, field_store->getMesh(), field_store->getField(disp_type.name).get()->space(),
358  field_store->createSpaces(force_name, disp_type.name, disp_type, disp_old_type, velo_old_type, accel_old_type,
359  FieldType<parameter_space>(prefix("param_" + parameter_types.name))...));
360 
361  // Create cycle-zero weak form (u, v, a) for initial acceleration solve — 3 states, no u_old
362  std::string cycle_zero_name = prefix("solid_reaction");
363  auto cycle_zero_solid_weak_form = std::make_shared<typename SystemType::CycleZeroSolidWeakFormType>(
364  cycle_zero_name, field_store->getMesh(), field_store->getField(accel_old_type.name).get()->space(),
365  field_store->createSpaces(cycle_zero_name, accel_old_type.name, disp_type, velo_old_type, accel_old_type,
366  FieldType<parameter_space>(prefix("param_" + parameter_types.name))...));
367 
368  if (cycle_zero_solver == nullptr) {
369  cycle_zero_solver = solver->singleBlockSolver(0);
370  }
371  SLIC_ERROR_IF(cycle_zero_solver == nullptr,
372  "Could not derive a cycle-zero solver for block 0 from the provided solid mechanics solver.");
373 
374  // Build advancer
375  std::vector<std::shared_ptr<WeakForm>> weak_forms{solid_weak_form};
376  auto advancer = std::make_shared<MultiphysicsTimeIntegrator>(field_store, weak_forms, solver,
377  cycle_zero_solid_weak_form, cycle_zero_solver);
378 
379  return SystemType{{field_store, solver, advancer, parameter_fields, prepend_name},
380  solid_weak_form,
381  cycle_zero_solid_weak_form,
382  disp_bc,
383  disp_time_rule_ptr};
384 }
385 
389 template <int dim, int order, typename DisplacementTimeRule, typename... parameter_space>
390 SolidMechanicsSystem<dim, order, DisplacementTimeRule, parameter_space...> buildSolidMechanicsSystem(
391  std::shared_ptr<Mesh> mesh, std::shared_ptr<CoupledSystemSolver> solver, DisplacementTimeRule disp_time_rule,
392  std::string prepend_name, FieldType<parameter_space>... parameter_types)
393 {
394  return buildSolidMechanicsSystem<dim, order>(mesh, solver, disp_time_rule, std::move(prepend_name), nullptr,
395  parameter_types...);
396 }
397 
401 template <int dim, int order, typename DisplacementTimeRule, typename... parameter_space>
402 SolidMechanicsSystem<dim, order, DisplacementTimeRule, parameter_space...> buildSolidMechanicsSystem(
403  std::shared_ptr<Mesh> mesh, std::shared_ptr<CoupledSystemSolver> solver, DisplacementTimeRule disp_time_rule,
404  std::shared_ptr<CoupledSystemSolver> cycle_zero_solver, FieldType<parameter_space>... parameter_types)
405 {
406  return buildSolidMechanicsSystem<dim, order>(mesh, solver, disp_time_rule, "", cycle_zero_solver, parameter_types...);
407 }
408 
412 template <int dim, int order, typename DisplacementTimeRule, typename... parameter_space>
413 SolidMechanicsSystem<dim, order, DisplacementTimeRule, parameter_space...> buildSolidMechanicsSystem(
414  std::shared_ptr<Mesh> mesh, std::shared_ptr<CoupledSystemSolver> solver, DisplacementTimeRule disp_time_rule,
415  FieldType<parameter_space>... parameter_types)
416 {
417  return buildSolidMechanicsSystem<dim, order>(mesh, solver, disp_time_rule, "", nullptr, parameter_types...);
418 }
419 
420 } // namespace smith
Defines a BasePhysics implementation backed by FieldState objects and a gretl computational graph.
Contains DirichletBoundaryConditions class for interaction with the differentiable solve interfaces.
Accelerator functionality.
Definition: smith.cpp:36
SMITH_HOST_DEVICE auto cross(const tensor< T, 3, 2 > &A)
compute the cross product of the columns of A: A(:,1) x A(:,2)
Definition: tensor.hpp:966
SolidMechanicsSystem< dim, order, DisplacementTimeRule, parameter_space... > buildSolidMechanicsSystem(std::shared_ptr< Mesh > mesh, std::shared_ptr< CoupledSystemSolver > solver, DisplacementTimeRule disp_time_rule, std::string prepend_name="", std::shared_ptr< CoupledSystemSolver > cycle_zero_solver=nullptr, FieldType< parameter_space >... parameter_types)
Factory function to build a solid dynamics system with configurable time integration.
constexpr SMITH_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
mfem::future::tuple< T... > tuple
Expose MFEM tuple in the Smith namespace.
Definition: tuple.hpp:241
decltype(detail::time_rule_params_impl< Space, Tail... >(std::make_index_sequence< Rule::num_states >{})) TimeRuleParams
Generate a Parameters<...> type with Rule::num_states copies of Space followed by additional Tail typ...
Definition: system_base.hpp:55
This file contains nonlinear block solver interfaces and helpers.
Interface and implementations for advancing from one step to the next. Typically these are time integ...
@ DOT
The first time derivative.
@ DDOT
The second time derivative.
Representation of a field type with a name and an optional unknown index.
Definition: field_store.hpp:30
std::string name
Name of the field.
Definition: field_store.hpp:37
H1 elements of order p.
a struct that is used in the physics modules to clarify which template arguments are user-controlled ...
Definition: common.hpp:45
System struct for solid dynamics with configurable time integration.
std::shared_ptr< DisplacementTimeRule > disp_time_rule
Time integration rule.
void addBodyForce(DependsOn< active_parameters... > depends_on, const std::string &domain_name, BodyForceType force_function)
Add a body force to the system (with DependsOn).
std::shared_ptr< CycleZeroSolidWeakFormType > cycle_zero_solid_weak_form
Cycle-zero weak form for initial acceleration solve.
std::shared_ptr< SolidWeakFormType > solid_weak_form
Solid mechanics weak form.
std::vector< ReactionInfo > getReactionInfos() const
Get information about reaction fields for this system.
void addBodyForce(const std::string &domain_name, BodyForceType force_function)
Add a body force to the system.
void addTraction(DependsOn< active_parameters... > depends_on, const std::string &domain_name, TractionType traction_function)
Add a surface traction (flux) to the system (with DependsOn).
std::vector< FieldState > getStateFields() const
Get the list of all state fields (displacement_solve_state, displacement, velocity,...
void addPressure(DependsOn< active_parameters... > depends_on, const std::string &domain_name, PressureType pressure_function)
Add a pressure boundary condition (follower force) (with DependsOn).
void addPressure(const std::string &domain_name, PressureType pressure_function)
Add a pressure boundary condition (follower force).
void setMaterial(const MaterialType &material, const std::string &domain_name)
Set the material model for a domain, defining integrals for the solid weak form.
std::shared_ptr< DirichletBoundaryConditions > disp_bc
Displacement boundary conditions.
std::vector< FieldState > getOutputFieldStates() const
Get the list of physical, non-solve state fields.
void addTraction(const std::string &domain_name, TractionType traction_function)
Add a surface traction (flux) to the system.
std::unique_ptr< DifferentiablePhysics > createDifferentiablePhysics(std::string physics_name)
Create a DifferentiablePhysics object for this system.
Base struct for physics systems containing common members and helper functions.
Definition: system_base.hpp:60
std::string prefix(const std::string &name) const
Helper function to prepend the physics name to a string.
Definition: system_base.hpp:78
std::shared_ptr< StateAdvancer > advancer
The state advancer.
Definition: system_base.hpp:63
std::shared_ptr< FieldStore > field_store
Field store managing the system's fields.
Definition: system_base.hpp:61
const std::vector< FieldState > & getParameterFields() const
Get the list of all parameter fields.
Definition: system_base.hpp:71
Defines the SystemBase struct for common system functionality.
Wraps FunctionalWeakForm to provide TimeInfo (time, dt, cycle) to integrands instead of just time.
Provides templated implementations for discretizing values, velocities and accelerations from current...
Specifies interface for evaluating weak form residuals and their gradients.