16 #include "smith/differentiable_numerics/field_store.hpp"
20 #include "smith/differentiable_numerics/multiphysics_time_integrator.hpp"
45 template <
int dim,
int order,
typename DisplacementTimeRule = ImplicitNewmarkSecondOrderTimeIntegrationRule,
46 typename Coupling = std::tuple<>>
50 static_assert(DisplacementTimeRule::num_states == 4,
"SolidMechanicsSystem requires a 4-state time integration rule");
64 std::shared_ptr<DirichletBoundaryConditions>
disp_bc;
78 template <
typename MaterialType>
79 void setMaterial(
const MaterialType& material,
const std::string& domain_name)
83 solid_weak_form->addBodyIntegral(domain_name, [=](
auto t_info,
auto ,
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;
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};
102 stress_weak_form->addBodyIntegral(domain_name, [=](
auto t_info,
auto ,
auto stress,
auto... raw_args) {
104 *captured_rule, *captured_coupling, t_info,
105 [&](
auto u_current,
auto v_current,
auto ,
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...);
110 auto flat_stress = [&]() {
112 static constexpr
auto I_ = Identity<dim>();
113 auto F = get<DERIVATIVE>(u_current) + I_;
116 return make_tensor<dim * dim>([&](
int i) {
return sigma[i / dim][i % dim]; });
118 return make_tensor<dim * dim>([&](
int i) {
return pk_stress[i / dim][i % dim]; });
133 template <
typename BodyForceType>
134 void addBodyForce(
const std::string& domain_name, BodyForceType force_function)
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...);
154 template <
typename TractionType>
155 void addTraction(
const std::string& domain_name, TractionType traction_function)
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...);
175 template <
typename PressureType>
176 void addPressure(
const std::string& domain_name, PressureType pressure_function)
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 ,
auto ,
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)));
188 auto pressure = pressure_function(t_info.time(), get<VALUE>(X), get<VALUE>(interpolated_params)...);
190 return pressure * n_deformed * (1.0 / n_shape_norm);
202 disp_bc->template setFixedVectorBCs<dim>(domain, components);
206 template <
typename AppliedDisplacementFunction>
209 disp_bc->template setVectorBCs<dim>(domain, f);
230 template <
int dim,
int order,
typename DisplacementTimeRule>
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);
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);
243 field_store->addDependent(disp_type, FieldStore::TimeDerivative::VAL,
"displacement");
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"))};
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);
260 return physics_fields;
272 return field_store->hasField(field_store->prefix(
"stress"));
279 if (
auto derived_solver = solver->singleBlockSolver(0)) {
280 return derived_solver;
285 .relative_tol = 1e-14,
286 .absolute_tol = 1e-14,
291 .relative_tol = 1e-14,
292 .absolute_tol = 1e-14,
293 .max_iterations = 1000,
301 template <
int dim,
int order,
typename DisplacementTimeRule,
typename Coupling>
302 requires detail::is_coupling_packs_v<Coupling>
305 bool has_stress_output)
307 auto disp_time_rule_ptr = std::make_shared<DisplacementTimeRule>();
315 auto disp_bc = field_store->getBoundaryConditions(disp_type.
name);
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);
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;
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);
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);
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);
353 if (has_stress_output) {
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);
362 .relative_tol = 1e-14,
363 .absolute_tol = 1e-14,
368 .relative_tol = 1e-14,
369 .absolute_tol = 1e-14,
370 .max_iterations = 1000,
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);
395 template <
typename SelfFields>
398 const SelfFields& self_fields)
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;
406 return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
413 template <
typename SelfFields,
typename... PFs>
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;
424 return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
431 template <
typename SelfFields,
typename... ParamSpaces>
432 requires(detail::has_time_rule_v<SelfFields>)
434 const SelfFields& self_fields,
const ParamFields<ParamSpaces...>& params)
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;
442 return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
449 template <
typename SelfFields,
typename... PFs,
typename... ParamSpaces>
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;
461 return detail::buildSolidMechanicsSystemImpl<dim, order, DisplacementTimeRule>(field_store, coupling, solver, options,
476 template <
int dim,
int order,
typename DisplacementTimeRule = ImplicitNewmarkSecondOrderTimeIntegrationRule,
477 typename... ParamSpaces>
482 auto field_store = std::make_shared<FieldStore>(mesh);
484 auto solid_fields = registerSolidMechanicsFields<dim, order, DisplacementTimeRule>(field_store, options);
485 if constexpr (
sizeof...(ParamSpaces) > 0) {
Helper class for constructing a mesh consistent with Smith.
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.
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.
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)
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.
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
@ 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...
std::string name
Name of the field.
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.
SystemBase()=default
Construct an empty system shell.
Type trait to append coupling parameter spaces to fixed parameters.
Arbitrary-rank tensor class.
Defines the SystemBase struct for common system functionality.
Provides templated implementations for discretizing values, velocities and accelerations from current...