14 #include "smith/differentiable_numerics/field_store.hpp"
17 #include "smith/differentiable_numerics/multiphysics_time_integrator.hpp"
40 template <
int dim,
int disp_order,
int temp_order,
41 typename DisplacementTimeRule = QuasiStaticSecondOrderTimeIntegrationRule,
42 typename TemperatureTimeRule = BackwardEulerFirstOrderTimeIntegrationRule,
typename... parameter_space>
44 static_assert(DisplacementTimeRule::num_states == 4,
45 "ThermoMechanicsSystem requires a 4-state displacement time rule");
46 static_assert(TemperatureTimeRule::num_states == 2,
"ThermoMechanicsSystem requires a 2-state temperature time rule");
70 std::shared_ptr<DirichletBoundaryConditions>
disp_bc;
121 template <
typename MaterialType>
122 void setMaterial(
const MaterialType& material,
const std::string& domain_name)
128 domain_name, [=](
auto t_info,
auto ,
auto u,
auto u_old,
auto v_old,
auto a_old,
auto temperature,
129 auto temperature_old,
auto... params) {
130 auto [u_current, v_current, a_current] = captured_disp_rule->interpolate(t_info, u, u_old, v_old, a_old);
131 auto T = captured_temp_rule->value(t_info, temperature, temperature_old);
133 typename MaterialType::State state;
134 auto [pk, C_v, s0, q0] = material(t_info.dt(), state, get<DERIVATIVE>(u_current), get<DERIVATIVE>(v_current),
135 get<VALUE>(T), get<DERIVATIVE>(T), params...);
136 return smith::tuple{get<VALUE>(a_current) * material.density, pk};
139 thermal_weak_form->addBodyIntegral(domain_name, [=](
auto t_info,
auto ,
auto T,
auto T_old,
auto disp,
140 auto disp_old,
auto v_old,
auto a_old,
auto... params) {
141 auto [T_current, T_dot] = captured_temp_rule->interpolate(t_info, T, T_old);
142 auto [u, v, a] = captured_disp_rule->interpolate(t_info, disp, disp_old, v_old, a_old);
144 typename MaterialType::State state;
145 auto [pk, C_v, s0, q0] = material(t_info.dt(), state, get<DERIVATIVE>(u), get<DERIVATIVE>(v),
146 get<VALUE>(T_current), get<DERIVATIVE>(T_current), params...);
147 auto dT_dt = get<VALUE>(T_dot);
152 cycle_zero_weak_form->addBodyIntegral(domain_name, [=](
auto t_info,
auto ,
auto u,
auto v,
auto a,
153 auto temperature,
auto temperature_old,
auto... params) {
154 auto T = captured_temp_rule->value(t_info, temperature, temperature_old);
156 typename MaterialType::State state;
157 auto [pk, C_v, s0, q0] = material(t_info.dt(), state, get<DERIVATIVE>(u), get<DERIVATIVE>(v), get<VALUE>(T),
158 get<DERIVATIVE>(T), params...);
159 return smith::tuple{get<VALUE>(a) * material.density, pk};
166 template <
int... active_parameters,
typename BodyForceType>
168 BodyForceType force_function)
174 depends_on, domain_name,
175 [=](
auto t_info,
auto X,
auto u,
auto u_old,
auto v_old,
auto a_old,
auto temperature,
auto temperature_old,
177 auto [u_current, v_current, a_current] = captured_disp_rule->interpolate(t_info, u, u_old, v_old, a_old);
178 auto [current_T, T_dot] = captured_temp_rule->interpolate(t_info, temperature, temperature_old);
179 return force_function(t_info.time(), X, u_current, v_current, a_current, current_T, T_dot, params...);
186 template <
typename BodyForceType>
189 addSolidBodyForceAllParams(domain_name, force_function, std::make_index_sequence<6 +
sizeof...(parameter_space)>{});
195 template <
int... active_parameters,
typename SurfaceFluxType>
197 SurfaceFluxType flux_function)
203 depends_on, domain_name,
204 [=](
auto t_info,
auto X,
auto n,
auto u,
auto u_old,
auto v_old,
auto a_old,
auto temperature,
205 auto temperature_old,
auto... params) {
206 auto [u_current, v_current, a_current] = captured_disp_rule->interpolate(t_info, u, u_old, v_old, a_old);
207 auto [current_T, T_dot] = captured_temp_rule->interpolate(t_info, temperature, temperature_old);
208 return flux_function(t_info.time(), X, n, u_current, v_current, a_current, current_T, T_dot, params...);
215 template <
typename SurfaceFluxType>
218 addSolidTractionAllParams(domain_name, flux_function, std::make_index_sequence<6 +
sizeof...(parameter_space)>{},
219 std::make_index_sequence<5 +
sizeof...(parameter_space)>{});
225 template <
int... active_parameters,
typename BodySourceType>
227 BodySourceType source_function)
233 depends_on, domain_name,
234 [=](
auto t_info,
auto X,
auto T,
auto T_old,
auto disp,
auto disp_old,
auto v_old,
auto a_old,
auto... params) {
235 auto [current_u, v_current, a_current] =
236 captured_disp_rule->interpolate(t_info, disp, disp_old, v_old, a_old);
237 auto [T_current, T_dot] = captured_temp_rule->interpolate(t_info, T, T_old);
238 return source_function(t_info.time(), X, current_u, v_current, a_current, T_current, T_dot, params...);
245 template <
typename BodySourceType>
246 void addHeatSource(
const std::string& domain_name, BodySourceType source_function)
248 addHeatSourceAllParams(domain_name, source_function, std::make_index_sequence<6 +
sizeof...(parameter_space)>{});
254 template <
int... active_parameters,
typename SurfaceFluxType>
256 SurfaceFluxType flux_function)
262 [=](
auto t_info,
auto X,
auto n,
auto T,
auto T_old,
auto disp,
auto disp_old,
263 auto v_old,
auto a_old,
auto... params) {
264 auto [current_u, v_current, a_current] =
265 captured_disp_rule->interpolate(t_info, disp, disp_old, v_old, a_old);
266 auto [T_current, T_dot] = captured_temp_rule->interpolate(t_info, T, T_old);
267 return -flux_function(t_info.time(), X, n, current_u, v_current, a_current,
268 T_current, T_dot, params...);
275 template <
typename SurfaceFluxType>
276 void addHeatFlux(
const std::string& domain_name, SurfaceFluxType flux_function)
278 addHeatFluxAllParams(domain_name, flux_function, std::make_index_sequence<6 +
sizeof...(parameter_space)>{});
284 template <
int... active_parameters,
typename PressureType>
286 PressureType pressure_function)
292 depends_on, domain_name,
293 [=](
auto t_info,
auto X,
auto u,
auto u_old,
auto v_old,
auto a_old,
auto temperature,
auto temperature_old,
295 auto [u_current, v_current, a_current] = captured_disp_rule->interpolate(t_info, u, u_old, v_old, a_old);
296 auto [T_current, T_dot] = captured_temp_rule->interpolate(t_info, temperature, temperature_old);
298 auto x_current = X + u_current;
299 auto n_deformed =
cross(get<DERIVATIVE>(x_current));
300 auto n_shape_norm =
norm(
cross(get<DERIVATIVE>(X)));
302 auto pressure = pressure_function(t_info.time(), get<VALUE>(X), u_current, v_current, a_current, T_current,
303 T_dot, get<VALUE>(params)...);
305 return pressure * n_deformed * (1.0 / n_shape_norm);
312 template <
typename PressureType>
313 void addPressure(
const std::string& domain_name, PressureType pressure_function)
315 addPressureAllParams(domain_name, pressure_function, std::make_index_sequence<6 +
sizeof...(parameter_space)>{});
319 template <
typename BodyForceType, std::size_t... Is>
320 void addSolidBodyForceAllParams(
const std::string& domain_name, BodyForceType force_function,
321 std::index_sequence<Is...>)
326 template <
typename SurfaceFluxType, std::size_t... MainIs, std::size_t... CycleZeroIs>
327 void addSolidTractionAllParams(
const std::string& domain_name, SurfaceFluxType flux_function,
328 std::index_sequence<MainIs...>, std::index_sequence<CycleZeroIs...>)
330 addSolidTraction(DependsOn<
static_cast<int>(MainIs)...>{}, domain_name, flux_function);
334 DependsOn<
static_cast<int>(CycleZeroIs)...>{}, domain_name,
335 [=](
auto t_info,
auto X,
auto n,
auto u,
auto v,
auto a,
auto temperature,
auto temperature_old,
337 auto [current_T, T_dot] = captured_temp_rule->interpolate(t_info, temperature, temperature_old);
338 return flux_function(t_info.time(), X, n, u, v, a, current_T, T_dot, params...);
342 template <
typename PressureType, std::size_t... Is>
343 void addPressureAllParams(
const std::string& domain_name, PressureType pressure_function, std::index_sequence<Is...>)
345 addPressure(DependsOn<
static_cast<int>(Is)...>{}, domain_name, pressure_function);
348 template <
typename BodySourceType, std::size_t... Is>
349 void addHeatSourceAllParams(
const std::string& domain_name, BodySourceType source_function,
350 std::index_sequence<Is...>)
352 addHeatSource(DependsOn<
static_cast<int>(Is)...>{}, domain_name, source_function);
355 template <
typename SurfaceFluxType, std::size_t... Is>
356 void addHeatFluxAllParams(
const std::string& domain_name, SurfaceFluxType flux_function, std::index_sequence<Is...>)
358 addHeatFlux(DependsOn<
static_cast<int>(Is)...>{}, domain_name, flux_function);
373 template <
int dim,
int disp_order,
int temp_order,
typename DisplacementTimeRule,
typename TemperatureTimeRule,
374 typename... parameter_space>
375 ThermoMechanicsSystem<dim, disp_order, temp_order, DisplacementTimeRule, TemperatureTimeRule, parameter_space...>
377 DisplacementTimeRule disp_rule, TemperatureTimeRule temp_rule, std::string prepend_name =
"",
378 std::shared_ptr<CoupledSystemSolver> cycle_zero_solver =
nullptr,
381 auto field_store = std::make_shared<FieldStore>(mesh, 100);
383 auto prefix = [&](
const std::string& name) {
384 if (prepend_name.empty()) {
387 return prepend_name +
"_" + name;
391 field_store->addShapeDisp(shape_disp_type);
394 auto disp_time_rule_ptr = std::make_shared<DisplacementTimeRule>(disp_rule);
396 auto disp_bc = field_store->addIndependent(disp_type, disp_time_rule_ptr);
397 auto disp_old_type = field_store->addDependent(disp_type, FieldStore::TimeDerivative::VAL, prefix(
"displacement"));
402 auto temperature_time_rule_ptr = std::make_shared<TemperatureTimeRule>(temp_rule);
404 auto temperature_bc = field_store->addIndependent(temperature_type, temperature_time_rule_ptr);
405 auto temperature_old_type =
406 field_store->addDependent(temperature_type, FieldStore::TimeDerivative::VAL, prefix(
"temperature"));
408 std::vector<FieldState> parameter_fields;
410 (parameter_fields.push_back(field_store->getField(prefix(
"param_" + parameter_types.
name))), ...);
413 ThermoMechanicsSystem<dim, disp_order, temp_order, DisplacementTimeRule, TemperatureTimeRule, parameter_space...>;
416 std::string solid_force_name = prefix(
"solid_force");
417 auto solid_weak_form = std::make_shared<typename SystemType::SolidWeakFormType>(
418 solid_force_name, field_store->getMesh(), field_store->getField(disp_type.
name).get()->space(),
419 field_store->createSpaces(solid_force_name, disp_type.
name, disp_type, disp_old_type, velo_old_type,
420 accel_old_type, temperature_type, temperature_old_type,
424 std::string thermal_flux_name = prefix(
"thermal_flux");
425 auto thermal_weak_form = std::make_shared<typename SystemType::ThermalWeakFormType>(
426 thermal_flux_name, field_store->getMesh(), field_store->getField(temperature_type.
name).get()->space(),
427 field_store->createSpaces(thermal_flux_name, temperature_type.
name, temperature_type, temperature_old_type,
428 disp_type, disp_old_type, velo_old_type, accel_old_type,
432 std::string cycle_zero_name = prefix(
"solid_reaction");
433 auto cycle_zero_weak_form = std::make_shared<typename SystemType::CycleZeroWeakFormType>(
434 cycle_zero_name, field_store->getMesh(), field_store->getField(accel_old_type.name).get()->space(),
435 field_store->createSpaces(cycle_zero_name, accel_old_type.name, disp_type, velo_old_type, accel_old_type,
436 temperature_type, temperature_old_type,
439 if (cycle_zero_solver ==
nullptr) {
440 cycle_zero_solver = solver->singleBlockSolver(0);
442 SLIC_ERROR_IF(cycle_zero_solver ==
nullptr,
443 "Could not derive a cycle-zero solver for block 0 from the provided thermo-mechanics solver.");
446 std::vector<std::shared_ptr<WeakForm>> weak_forms{solid_weak_form, thermal_weak_form};
447 auto advancer = std::make_shared<MultiphysicsTimeIntegrator>(field_store, weak_forms, solver, cycle_zero_weak_form,
450 return SystemType{{field_store, solver, advancer, parameter_fields, prepend_name},
453 cycle_zero_weak_form,
457 temperature_time_rule_ptr};
463 template <
int dim,
int disp_order,
int temp_order,
typename DisplacementTimeRule,
typename TemperatureTimeRule,
464 typename... parameter_space>
466 DisplacementTimeRule disp_rule, TemperatureTimeRule temp_rule, std::string prepend_name,
469 return buildThermoMechanicsSystem<dim, disp_order, temp_order>(mesh, solver, disp_rule, temp_rule,
470 std::move(prepend_name),
nullptr, parameter_types...);
476 template <
int dim,
int disp_order,
int temp_order,
typename DisplacementTimeRule,
typename TemperatureTimeRule,
477 typename... parameter_space>
479 DisplacementTimeRule disp_rule, TemperatureTimeRule temp_rule,
480 std::shared_ptr<CoupledSystemSolver> cycle_zero_solver,
483 return buildThermoMechanicsSystem<dim, disp_order, temp_order>(mesh, solver, disp_rule, temp_rule,
"",
484 cycle_zero_solver, parameter_types...);
490 template <
int dim,
int disp_order,
int temp_order,
typename DisplacementTimeRule,
typename TemperatureTimeRule,
491 typename... parameter_space>
493 DisplacementTimeRule disp_rule, TemperatureTimeRule temp_rule,
496 return buildThermoMechanicsSystem<dim, disp_order, temp_order>(mesh, solver, disp_rule, temp_rule,
"",
nullptr,
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.
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)
ThermoMechanicsSystem< dim, disp_order, temp_order, DisplacementTimeRule, TemperatureTimeRule, parameter_space... > buildThermoMechanicsSystem(std::shared_ptr< Mesh > mesh, std::shared_ptr< CoupledSystemSolver > solver, DisplacementTimeRule disp_rule, TemperatureTimeRule temp_rule, std::string prepend_name="", std::shared_ptr< CoupledSystemSolver > cycle_zero_solver=nullptr, FieldType< parameter_space >... parameter_types)
Factory function to build a thermo-mechanical system.
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.
This file contains nonlinear block solver interfaces and helpers.
@ DOT
The first time derivative.
@ DDOT
The second time derivative.
Representation of a field type with a name and an optional unknown index.
std::string name
Name of the field.
a struct that is used in the physics modules to clarify which template arguments are user-controlled ...
Base struct for physics systems containing common members and helper functions.
std::string prefix(const std::string &name) const
Helper function to prepend the physics name to a string.
std::shared_ptr< StateAdvancer > advancer
The state advancer.
std::shared_ptr< FieldStore > field_store
Field store managing the system's fields.
const std::vector< FieldState > & getParameterFields() const
Get the list of all parameter fields.
Container for a coupled thermo-mechanical system with configurable time integration.
void addSolidBodyForce(const std::string &domain_name, BodyForceType force_function)
Add a body force to the solid mechanics part of the system.
std::shared_ptr< SolidWeakFormType > solid_weak_form
Solid mechanics weak form.
std::unique_ptr< DifferentiablePhysics > createDifferentiablePhysics(std::string physics_name)
Create a DifferentiablePhysics object for this system.
std::shared_ptr< CycleZeroWeakFormType > cycle_zero_weak_form
Cycle-zero weak form.
void addSolidTraction(const std::string &domain_name, SurfaceFluxType flux_function)
Add a surface traction to the solid mechanics part.
void addPressure(DependsOn< active_parameters... > depends_on, const std::string &domain_name, PressureType pressure_function)
Add a pressure boundary condition (follower force) to the solid part (with DependsOn).
void addHeatFlux(DependsOn< active_parameters... > depends_on, const std::string &domain_name, SurfaceFluxType flux_function)
Add a boundary heat flux to the thermal part (with DependsOn).
std::shared_ptr< DisplacementTimeRule > disp_time_rule
Time integration for displacement.
std::vector< ReactionInfo > getReactionInfos() const
Get information about reaction fields for this system.
void addHeatSource(DependsOn< active_parameters... > depends_on, const std::string &domain_name, BodySourceType source_function)
Add a body heat source to the thermal part (with DependsOn).
void addHeatSource(const std::string &domain_name, BodySourceType source_function)
Add a body heat source to the thermal part.
std::shared_ptr< DirichletBoundaryConditions > temperature_bc
Temperature boundary conditions.
std::shared_ptr< DirichletBoundaryConditions > disp_bc
Displacement boundary conditions.
void addPressure(const std::string &domain_name, PressureType pressure_function)
Add a pressure boundary condition (follower force) to the solid part.
std::shared_ptr< TemperatureTimeRule > temperature_time_rule
Time integration for temperature.
std::vector< FieldState > getStateFields() const
Get the list of all state fields (disp_pred, disp, vel, accel, temp_pred, temp).
std::shared_ptr< ThermalWeakFormType > thermal_weak_form
Thermal weak form.
void addHeatFlux(const std::string &domain_name, SurfaceFluxType flux_function)
Add a boundary heat flux to the thermal part.
void setMaterial(const MaterialType &material, const std::string &domain_name)
Set the material model for a domain, defining integrals for solid and thermal weak forms.
void addSolidTraction(DependsOn< active_parameters... > depends_on, const std::string &domain_name, SurfaceFluxType flux_function)
Add a surface traction to the solid mechanics part (with DependsOn).
void addSolidBodyForce(DependsOn< active_parameters... > depends_on, const std::string &domain_name, BodyForceType force_function)
Add a body force to the solid mechanics part of the system (with DependsOn).
Defines the SystemBase struct for common system functionality.
Provides templated implementations for discretizing values, velocities and accelerations from current...