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 <algorithm>
15 
16 #include "smith/differentiable_numerics/field_store.hpp"
20 #include "smith/differentiable_numerics/multiphysics_time_integrator.hpp"
27 
28 namespace smith {
29 
45 template <int dim, int order, typename DisplacementTimeRule = ImplicitNewmarkSecondOrderTimeIntegrationRule,
46  typename Coupling = std::tuple<>>
49 
50  static_assert(DisplacementTimeRule::num_states == 4, "SolidMechanicsSystem requires a 4-state time integration rule");
51 
55 
59  dim, L2<0, dim * dim>,
62 
63  std::shared_ptr<SolidWeakFormType> solid_weak_form;
64  std::shared_ptr<DirichletBoundaryConditions> disp_bc;
65  std::shared_ptr<DisplacementTimeRule> disp_time_rule;
66  std::shared_ptr<const Coupling> coupling;
67 
68  std::shared_ptr<StressOutputWeakFormType> stress_weak_form;
69  std::shared_ptr<SystemBase> stress_output_system;
70  bool output_cauchy_stress = false;
71 
78  template <typename MaterialType>
79  void setMaterial(const MaterialType& material, const std::string& domain_name)
80  {
81  auto captured_rule = disp_time_rule;
82  auto captured_coupling = coupling;
83  solid_weak_form->addBodyIntegral(domain_name, [=](auto t_info, auto /*X*/, auto... raw_args) {
85  *captured_rule, *captured_coupling, t_info,
86  [&](auto u_current, auto v_current, auto a_current, auto... interpolated_params) {
87  typename MaterialType::State state;
88  auto pk_stress =
89  material(t_info, state, get<DERIVATIVE>(u_current), get<DERIVATIVE>(v_current), interpolated_params...);
90  return smith::tuple{get<VALUE>(a_current) * material.density, pk_stress};
91  },
92  raw_args...);
93  });
94 
95  // Stress output projection: L2 projection of PK1 stress onto an L2 piecewise-constant field.
96  // Residual: ∫ test · (stress_unknown - pk_stress(u)) dx = 0.
97  // Args: (stress_unknown, u, u_old, v_old, a_old, params...). stress_unknown is the Jacobian
98  // variable so the solver builds the mass matrix against it, and the (- pk_stress) term
99  // becomes the RHS.
100  if (stress_weak_form) {
101  bool do_cauchy = this->output_cauchy_stress;
102  stress_weak_form->addBodyIntegral(domain_name, [=](auto t_info, auto /*X*/, auto stress, auto... raw_args) {
104  *captured_rule, *captured_coupling, t_info,
105  [&](auto u_current, auto v_current, auto /*a_current*/, auto... interpolated_params) {
106  typename MaterialType::State state;
107  auto pk_stress = material(t_info, state, get<DERIVATIVE>(u_current), get<DERIVATIVE>(v_current),
108  interpolated_params...);
109 
110  auto flat_stress = [&]() {
111  if (do_cauchy) {
112  static constexpr auto I_ = Identity<dim>();
113  auto F = get<DERIVATIVE>(u_current) + I_;
114  auto J = det(F);
115  auto sigma = (1.0 / J) * dot(pk_stress, transpose(F));
116  return make_tensor<dim * dim>([&](int i) { return sigma[i / dim][i % dim]; });
117  }
118  return make_tensor<dim * dim>([&](int i) { return pk_stress[i / dim][i % dim]; });
119  }();
120  return smith::tuple{get<VALUE>(stress) - flat_stress, tensor<double, dim * dim, dim>{}};
121  },
122  raw_args...);
123  });
124  }
125  }
126 
133  template <typename BodyForceType>
134  void addBodyForce(const std::string& domain_name, BodyForceType force_function)
135  {
136  auto captured_rule = disp_time_rule;
137  auto captured_coupling = coupling;
138  solid_weak_form->addBodySource(domain_name, [=](auto t_info, auto X, auto... raw_args) {
140  *captured_rule, *captured_coupling, t_info,
141  [&](auto u_current, auto v_current, auto a_current, auto... interpolated_params) {
142  return force_function(t_info.time(), X, u_current, v_current, a_current, interpolated_params...);
143  },
144  raw_args...);
145  });
146  }
147 
154  template <typename TractionType>
155  void addTraction(const std::string& domain_name, TractionType traction_function)
156  {
157  auto captured_rule = disp_time_rule;
158  auto captured_coupling = coupling;
159  solid_weak_form->addBoundaryFlux(domain_name, [=](auto t_info, auto X, auto n, auto... raw_args) {
161  *captured_rule, *captured_coupling, t_info,
162  [&](auto u_current, auto v_current, auto a_current, auto... interpolated_params) {
163  return traction_function(t_info.time(), X, n, u_current, v_current, a_current, interpolated_params...);
164  },
165  raw_args...);
166  });
167  }
168 
175  template <typename PressureType>
176  void addPressure(const std::string& domain_name, PressureType pressure_function)
177  {
178  auto captured_rule = disp_time_rule;
179  auto captured_coupling = coupling;
180  solid_weak_form->addBoundaryIntegral(domain_name, [=](auto t_info, auto X, auto... raw_args) {
182  *captured_rule, *captured_coupling, t_info,
183  [&](auto u_current, auto /*v_current*/, auto /*a_current*/, auto... interpolated_params) {
184  auto x_current = X + u_current;
185  auto n_deformed = cross(get<DERIVATIVE>(x_current));
186  auto n_shape_norm = norm(cross(get<DERIVATIVE>(X)));
187 
188  auto pressure = pressure_function(t_info.time(), get<VALUE>(X), get<VALUE>(interpolated_params)...);
189 
190  return pressure * n_deformed * (1.0 / n_shape_norm);
191  },
192  raw_args...);
193  });
194  }
195 
197  void setDisplacementBC(const Domain& domain) { disp_bc->template setFixedVectorBCs<dim>(domain); }
198 
200  void setDisplacementBC(const Domain& domain, std::vector<int> components)
201  {
202  disp_bc->template setFixedVectorBCs<dim>(domain, components);
203  }
204 
206  template <typename AppliedDisplacementFunction>
207  void setDisplacementBC(const Domain& domain, AppliedDisplacementFunction f)
208  {
209  disp_bc->template setVectorBCs<dim>(domain, f);
210  }
211 
212  private:
213 };
214 
219  bool enable_stress_output = false;
220  bool output_cauchy_stress = false;
221 };
222 
230 template <int dim, int order, typename DisplacementTimeRule>
231 auto registerSolidMechanicsFields(std::shared_ptr<FieldStore> field_store,
232  const SolidMechanicsOptions& options = SolidMechanicsOptions{})
233 {
234  FieldType<H1<1, dim>> shape_disp_type("shape_displacement");
235  if (!field_store->hasField(field_store->prefix(shape_disp_type.name))) {
236  field_store->addShapeDisp(shape_disp_type);
237  }
238 
239  auto disp_time_rule_ptr = std::make_shared<DisplacementTimeRule>();
240  FieldType<H1<order, dim>> disp_type("displacement_solve_state");
241  field_store->addIndependent(disp_type, disp_time_rule_ptr);
242 
243  field_store->addDependent(disp_type, FieldStore::TimeDerivative::VAL, "displacement");
244  field_store->addDependent(disp_type, FieldStore::TimeDerivative::DOT, "velocity");
245  field_store->addDependent(disp_type, FieldStore::TimeDerivative::DDOT, "acceleration");
246 
247  auto physics_fields =
248  PhysicsFields<dim, order, DisplacementTimeRule, H1<order, dim>, H1<order, dim>, H1<order, dim>, H1<order, dim>>{
249  field_store, FieldType<H1<order, dim>>(field_store->prefix("displacement_solve_state")),
250  FieldType<H1<order, dim>>(field_store->prefix("displacement")),
251  FieldType<H1<order, dim>>(field_store->prefix("velocity")),
252  FieldType<H1<order, dim>>(field_store->prefix("acceleration"))};
253 
254  if (options.enable_stress_output) {
255  auto stress_time_rule = std::make_shared<StaticTimeIntegrationRule>();
256  FieldType<L2<0, dim * dim>> stress_type("stress");
257  field_store->addIndependent(stress_type, stress_time_rule);
258  }
259 
260  return physics_fields;
261 }
267 namespace detail {
268 
270 inline bool hasRegisteredStressOutput(const std::shared_ptr<FieldStore>& field_store)
271 {
272  return field_store->hasField(field_store->prefix("stress"));
273 }
274 
276 inline std::shared_ptr<SystemSolver> makeCycleZeroSolver(std::shared_ptr<SystemSolver> solver, const Mesh& mesh)
277 {
278  if (solver) {
279  if (auto derived_solver = solver->singleBlockSolver(0)) {
280  return derived_solver;
281  }
282  }
283 
285  .relative_tol = 1e-14,
286  .absolute_tol = 1e-14,
287  .max_iterations = 2,
288  .print_level = 0};
290  .preconditioner = Preconditioner::HypreJacobi,
291  .relative_tol = 1e-14,
292  .absolute_tol = 1e-14,
293  .max_iterations = 1000,
294  .print_level = 0};
295  return std::make_shared<SystemSolver>(buildNonlinearBlockSolver(cycle_zero_nonlin, cycle_zero_lin, mesh));
296 }
297 
301 template <int dim, int order, typename DisplacementTimeRule, typename Coupling>
302  requires detail::is_coupling_packs_v<Coupling>
303 auto buildSolidMechanicsSystemImpl(std::shared_ptr<FieldStore> field_store, const Coupling& coupling,
304  std::shared_ptr<SystemSolver> solver, const SolidMechanicsOptions& options,
305  bool has_stress_output)
306 {
307  auto disp_time_rule_ptr = std::make_shared<DisplacementTimeRule>();
308 
309  FieldType<H1<1, dim>> shape_disp_type(field_store->prefix("shape_displacement"));
310  FieldType<H1<order, dim>> disp_type(field_store->prefix("displacement_solve_state"), true);
311  FieldType<H1<order, dim>> disp_old_type(field_store->prefix("displacement"));
312  FieldType<H1<order, dim>> velo_old_type(field_store->prefix("velocity"));
313  FieldType<H1<order, dim>> accel_old_type(field_store->prefix("acceleration"));
314 
315  auto disp_bc = field_store->getBoundaryConditions(disp_type.name);
316 
318 
319  auto coupling_fields_flat = detail::flattenCouplingFields(coupling);
320  std::string force_name = field_store->prefix("reactions");
321  auto solid_weak_form = detail::buildWeakFormWithCoupling<typename SystemType::SolidWeakFormType>(
322  field_store, force_name, disp_type.name, disp_type, disp_old_type, velo_old_type, accel_old_type,
323  coupling_fields_flat);
324 
325  auto sys = std::make_shared<SystemType>(field_store, solver, std::vector<std::shared_ptr<WeakForm>>{solid_weak_form});
326  sys->disp_bc = disp_bc;
327  sys->disp_time_rule = disp_time_rule_ptr;
328  sys->coupling = std::make_shared<Coupling>(coupling);
329  sys->solid_weak_form = solid_weak_form;
330  sys->output_cauchy_stress = options.output_cauchy_stress;
331 
332  if (disp_time_rule_ptr->requiresInitialAccelerationSolve()) {
333  std::string cycle_zero_name = field_store->prefix("cycle_zero_acceleration_reaction");
334  field_store->markWeakFormInternal(cycle_zero_name);
335  auto cycle_zero_solver = detail::makeCycleZeroSolver(solver, *field_store->getMesh());
336 
337  auto cycle_zero_system = makeSystem(field_store, cycle_zero_solver, {sys->solid_weak_form});
338  cycle_zero_system->solve_result_field_names = {accel_old_type.name};
339  auto cycle_zero_inputs =
340  std::vector<std::string>{disp_old_type.name, disp_old_type.name, velo_old_type.name, accel_old_type.name};
341  auto append_if_state = [&](const auto& field) {
342  const auto& states = field_store->getStateFields();
343  if (std::any_of(states.begin(), states.end(),
344  [&](const auto& state) { return state.get()->name() == field.name; })) {
345  cycle_zero_inputs.push_back(field.name);
346  }
347  };
348  std::apply([&](const auto&... coupling_fields) { (append_if_state(coupling_fields), ...); }, coupling_fields_flat);
349  cycle_zero_system->solve_input_field_names = {cycle_zero_inputs};
350  sys->cycle_zero_systems.push_back(cycle_zero_system);
351  }
352 
353  if (has_stress_output) {
354  FieldType<L2<0, dim * dim>> stress_type(field_store->prefix("stress"), true);
355  FieldType<H1<order, dim>> disp_as_input(disp_type.name);
356  std::string stress_name = field_store->prefix("stress_projection");
357  sys->stress_weak_form = detail::buildWeakFormWithCoupling<typename SystemType::StressOutputWeakFormType>(
358  field_store, stress_name, stress_type.name, stress_type, disp_as_input, disp_old_type, velo_old_type,
359  accel_old_type, coupling_fields_flat);
360 
362  .relative_tol = 1e-14,
363  .absolute_tol = 1e-14,
364  .max_iterations = 2,
365  .print_level = 0};
367  .preconditioner = Preconditioner::HypreJacobi,
368  .relative_tol = 1e-14,
369  .absolute_tol = 1e-14,
370  .max_iterations = 1000,
371  .print_level = 0};
372  auto stress_solver =
373  std::make_shared<SystemSolver>(buildNonlinearBlockSolver(stress_nonlin, stress_lin, *field_store->getMesh()));
374 
375  sys->stress_output_system = makeSystem(field_store, stress_solver, {sys->stress_weak_form});
376  sys->post_solve_systems.push_back(sys->stress_output_system);
377  }
378 
379  return sys;
380 }
381 
382 } // namespace detail
383 
395 template <typename SelfFields>
396  requires(detail::has_time_rule_v<SelfFields>)
397 auto buildSolidMechanicsSystem(std::shared_ptr<SystemSolver> solver, const SolidMechanicsOptions& options,
398  const SelfFields& self_fields)
399 {
400  constexpr int dim = SelfFields::dim;
401  constexpr int order = SelfFields::order;
402  using DisplacementTimeRule = typename std::decay_t<SelfFields>::time_rule_type;
403  auto field_store = self_fields.field_store;
404  auto coupling = detail::collectCouplingFields();
405  bool has_stress_output = detail::hasRegisteredStressOutput(field_store);
406  return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
407  has_stress_output);
408 }
409 
413 template <typename SelfFields, typename... PFs>
414  requires(detail::has_time_rule_v<SelfFields>)
415 auto buildSolidMechanicsSystem(std::shared_ptr<SystemSolver> solver, const SolidMechanicsOptions& options,
416  const SelfFields& self_fields, const CouplingFields<PFs...>& coupled)
417 {
418  constexpr int dim = SelfFields::dim;
419  constexpr int order = SelfFields::order;
420  using DisplacementTimeRule = typename std::decay_t<SelfFields>::time_rule_type;
421  auto field_store = self_fields.field_store;
422  auto coupling = detail::collectCouplingFields(coupled);
423  bool has_stress_output = detail::hasRegisteredStressOutput(field_store);
424  return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
425  has_stress_output);
426 }
427 
431 template <typename SelfFields, typename... ParamSpaces>
432  requires(detail::has_time_rule_v<SelfFields>)
433 auto buildSolidMechanicsSystem(std::shared_ptr<SystemSolver> solver, const SolidMechanicsOptions& options,
434  const SelfFields& self_fields, const ParamFields<ParamSpaces...>& params)
435 {
436  constexpr int dim = SelfFields::dim;
437  constexpr int order = SelfFields::order;
438  using DisplacementTimeRule = typename std::decay_t<SelfFields>::time_rule_type;
439  auto field_store = self_fields.field_store;
440  auto coupling = detail::collectCouplingFields(params);
441  bool has_stress_output = detail::hasRegisteredStressOutput(field_store);
442  return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
443  has_stress_output);
444 }
445 
449 template <typename SelfFields, typename... PFs, typename... ParamSpaces>
450  requires(detail::has_time_rule_v<SelfFields>)
451 auto buildSolidMechanicsSystem(std::shared_ptr<SystemSolver> solver, const SolidMechanicsOptions& options,
452  const SelfFields& self_fields, const CouplingFields<PFs...>& coupled,
453  const ParamFields<ParamSpaces...>& params)
454 {
455  constexpr int dim = SelfFields::dim;
456  constexpr int order = SelfFields::order;
457  using DisplacementTimeRule = typename std::decay_t<SelfFields>::time_rule_type;
458  auto field_store = self_fields.field_store;
459  auto coupling = detail::collectCouplingFields(coupled, params);
460  bool has_stress_output = detail::hasRegisteredStressOutput(field_store);
461  return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
462  has_stress_output);
463 }
464 
476 template <int dim, int order, typename DisplacementTimeRule = ImplicitNewmarkSecondOrderTimeIntegrationRule,
477  typename... ParamSpaces>
478 auto buildSolidMechanicsSystem(const NonlinearSolverOptions& nonlinear_opts, const LinearSolverOptions& linear_opts,
479  const SolidMechanicsOptions& options, std::shared_ptr<smith::Mesh> mesh,
480  FieldType<ParamSpaces>... params)
481 {
482  auto field_store = std::make_shared<FieldStore>(mesh);
483  auto solver = std::make_shared<SystemSolver>(buildNonlinearBlockSolver(nonlinear_opts, linear_opts, *mesh));
484  auto solid_fields = registerSolidMechanicsFields<dim, order, DisplacementTimeRule>(field_store, options);
485  if constexpr (sizeof...(ParamSpaces) > 0) {
486  auto param_fields = registerParameterFields(field_store, std::move(params)...);
487  return buildSolidMechanicsSystem(solver, options, solid_fields, param_fields);
488  } else {
489  return buildSolidMechanicsSystem(solver, options, solid_fields);
490  }
491 }
492 
493 } // namespace smith
Helper class for constructing a mesh consistent with Smith.
Definition: mesh.hpp:37
Coupling pack types and helpers for injecting explicit coupled-physics fields into weak form paramete...
Defines a BasePhysics implementation backed by FieldState objects and a gretl computational graph.
Contains DirichletBoundaryConditions class for interaction with the differentiable solve interfaces.
Implements the WeakForm interface using smith::ShapeAwareFunctional. Allows for generic specification...
std::shared_ptr< SystemSolver > makeCycleZeroSolver(std::shared_ptr< SystemSolver > solver, const Mesh &mesh)
Build a cycle-zero solver from the main solver when possible, else use fallback defaults.
decltype(auto) applyTimeRuleAndCoupling(const Rule &rule, const Coupling &coupling, const TimeInfoT &t_info, Callback &&callback, const RawArgs &... raw_args)
Interpolate self time-rule states then coupling segments, then invoke callback.
requires detail::is_coupling_packs_v< Coupling > auto buildSolidMechanicsSystemImpl(std::shared_ptr< FieldStore > field_store, const Coupling &coupling, std::shared_ptr< SystemSolver > solver, const SolidMechanicsOptions &options, bool has_stress_output)
Internal solid builder after public registration and coupling collection.
auto collectCouplingFields()
Collect no coupling or parameter packs.
bool hasRegisteredStressOutput(const std::shared_ptr< FieldStore > &field_store)
Return true when stress output fields were registered during phase 1.
typename TimeRuleParamsImpl< Rule, Space, flatten_coupling_t< PacksTuple > >::type TimeRuleParams
Typedef for TimeRuleParams.
auto flattenCouplingFields(const PacksTuple &packs)
Concatenate each pack's .fields tuple — used to derive trailing weak-form parameter spaces.
Accelerator functionality.
Definition: smith.cpp:36
std::shared_ptr< NonlinearBlockSolver > buildNonlinearBlockSolver(NonlinearSolverOptions nonlinear_opts, LinearSolverOptions linear_opts, const smith::Mesh &mesh)
Create an equation-backed nonlinear block solver.
requires(detail::has_time_rule_v< SelfFields >) auto buildSolidMechanicsSystem(std
Build a SolidMechanicsSystem from already-registered field packs.
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
auto registerSolidMechanicsFields(std::shared_ptr< FieldStore > field_store, const SolidMechanicsOptions &options=SolidMechanicsOptions{})
Register all solid mechanics fields into a FieldStore.
auto buildSolidMechanicsSystem(const NonlinearSolverOptions &nonlinear_opts, const LinearSolverOptions &linear_opts, const SolidMechanicsOptions &options, std::shared_ptr< smith::Mesh > mesh, FieldType< ParamSpaces >... params)
Build a SolidMechanicsSystem from solver options and a mesh, registering parameter fields inline.
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
constexpr SMITH_HOST_DEVICE auto transpose(const isotropic_tensor< T, m, m > &I)
return the transpose of an isotropic tensor
std::shared_ptr< SystemBase > makeSystem(std::shared_ptr< FieldStore > field_store, std::shared_ptr< SystemSolver > solver, std::vector< std::shared_ptr< WeakForm >> weak_forms)
Convenience factory for a plain SystemBase.
constexpr SMITH_HOST_DEVICE auto det(const isotropic_tensor< T, m, m > &I)
compute the determinant of an isotropic tensor
auto registerParameterFields(const std::shared_ptr< FieldStore > &field_store, FieldType< ParamSpaces >... param_types)
Register parameter fields as type-level tokens.
constexpr SMITH_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor
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...
Bundle of coupled PhysicsFields packs supplied to a builder as a single coupling arg.
a class for representing a geometric region that can be used for integration
Definition: domain.hpp:33
@ DOT
The first time derivative.
@ DDOT
The second time derivative.
Representation of a field type with a name and a flag indicating whether it is an active Jacobian unk...
Definition: field_store.hpp:47
std::string name
Name of the field.
Definition: field_store.hpp:56
H1 elements of order p.
Discontinuous elements of order p.
Parameters for an iterative linear solution scheme.
LinearSolver linear_solver
Linear solver selection.
Nonlinear solution scheme parameters.
NonlinearSolver nonlin_solver
Nonlinear solver selection.
Registered parameter-only field bundle.
Optional auxiliary systems and outputs for solid mechanics.
bool output_cauchy_stress
When true, project Cauchy stress (sigma) instead of PK1 (P).
bool enable_stress_output
Register stress output fields during phase 1.
System struct for solid dynamics with configurable time integration.
void setDisplacementBC(const Domain &domain)
Set zero-displacement Dirichlet BC on all components.
std::shared_ptr< SolidWeakFormType > solid_weak_form
Solid mechanics weak form.
void setMaterial(const MaterialType &material, const std::string &domain_name)
Set material model for domain.
void addTraction(const std::string &domain_name, TractionType traction_function)
Add a surface traction (flux) to the system.
std::shared_ptr< SystemBase > stress_output_system
Post-solve system for stress projection.
bool output_cauchy_stress
Project Cauchy stress instead of PK1 when true.
std::shared_ptr< StressOutputWeakFormType > stress_weak_form
Stress projection weak form (nullptr if disabled).
std::shared_ptr< const Coupling > coupling
Coupling metadata for callback interpolation.
std::shared_ptr< DisplacementTimeRule > disp_time_rule
Time integration rule.
void addPressure(const std::string &domain_name, PressureType pressure_function)
Add a pressure boundary condition (follower force).
void setDisplacementBC(const Domain &domain, std::vector< int > components)
Set zero-displacement BC on specific components.
std::shared_ptr< DirichletBoundaryConditions > disp_bc
Displacement boundary conditions.
void addBodyForce(const std::string &domain_name, BodyForceType force_function)
Add a body force to the system.
void setDisplacementBC(const Domain &domain, AppliedDisplacementFunction f)
Set displacement BC with a prescribed function.
Base struct for physics systems containing common members and helper functions.
Definition: system_base.hpp:52
SystemBase()=default
Construct an empty system shell.
Type trait to append coupling parameter spaces to fixed parameters.
Arbitrary-rank tensor class.
Definition: tensor.hpp:28
Defines the SystemBase struct for common system functionality.
Provides templated implementations for discretizing values, velocities and accelerations from current...
Specifies interface for evaluating weak form residuals and their gradients.