Composable Thermo-Mechanics Tutorial¶
This demo builds a minimal composable thermo-mechanics problem. It registers solid and thermal fields, builds two systems, couples them with a thermoelastic material, and advances the combined system.
The full source code lives in examples/thermo_mechanics/composable_thermo_mechanics.cpp.
Includes and Initialization¶
#include "smith/infrastructure/application_manager.hpp"
#include "smith/physics/state/state_manager.hpp"
#include "smith/physics/mesh.hpp"
#include "smith/numerics/solver_config.hpp"
#include "smith/differentiable_numerics/nonlinear_block_solver.hpp"
#include "smith/differentiable_numerics/system_solver.hpp"
#include "smith/differentiable_numerics/solid_mechanics_system.hpp"
#include "smith/differentiable_numerics/thermal_system.hpp"
#include "smith/differentiable_numerics/thermo_mechanics_system.hpp"
#include "smith/differentiable_numerics/make_time_info_material.hpp"
#include "smith/differentiable_numerics/combined_system.hpp"
#include "smith/differentiable_numerics/differentiable_physics.hpp"
#include "smith/physics/materials/green_saint_venant_thermoelastic.hpp"
smith::ApplicationManager application_manager(argc, argv);
axom::sidre::DataStore datastore;
smith::StateManager::initialize(datastore, "composable_thermo_mechanics");
Mesh Construction¶
constexpr int dim = 3;
constexpr int order = 1;
auto mesh = std::make_shared<smith::Mesh>(
mfem::Mesh::MakeCartesian3D(8, 2, 2, mfem::Element::HEXAHEDRON, 1.0, 0.1, 0.1), "mesh", 0, 0);
mesh->addDomainOfBoundaryElements("left", smith::by_attr<dim>(3));
mesh->addDomainOfBoundaryElements("right", smith::by_attr<dim>(5));
Field Registration¶
Registration declares all fields on one shared FieldStore before any system
is built. Register parameters in the same phase with
registerParameterFields(field_store, ...) and pass the returned bundle into
the build step.
smith::LinearSolverOptions linear_options{.linear_solver = smith::LinearSolver::SuperLU,
.relative_tol = 1e-8,
.absolute_tol = 1e-10,
.max_iterations = 200,
.print_level = 0};
smith::NonlinearSolverOptions nonlinear_options{.nonlin_solver = smith::NonlinearSolver::NewtonLineSearch,
.relative_tol = 1e-7,
.absolute_tol = 1e-8,
.max_iterations = 20,
.max_line_search_iterations = 6,
.print_level = 0};
auto field_store = std::make_shared<smith::FieldStore>(mesh, 100);
auto solid_fields =
smith::registerSolidMechanicsFields<dim, order, smith::QuasiStaticSecondOrderTimeIntegrationRule>(field_store);
auto thermal_fields =
smith::registerThermalFields<dim, order, smith::BackwardEulerFirstOrderTimeIntegrationRule>(field_store);
System Build and Coupling¶
The build step consumes each system's own field pack, then optional coupling and
parameter bundles. combineSystems(...) returns the combined system used by
makeDifferentiablePhysics(...).
auto solid_solver =
std::make_shared<smith::SystemSolver>(smith::buildNonlinearBlockSolver(nonlinear_options, linear_options, *mesh));
auto thermal_solver =
std::make_shared<smith::SystemSolver>(smith::buildNonlinearBlockSolver(nonlinear_options, linear_options, *mesh));
auto solid_system = smith::buildSolidMechanicsSystem(solid_solver, smith::SolidMechanicsOptions{}, solid_fields,
smith::couplingFields(thermal_fields));
auto thermal_system = smith::buildThermalSystem(thermal_solver, smith::ThermalOptions{}, thermal_fields,
smith::couplingFields(solid_fields));
auto coupled_system = smith::combineSystems(solid_system, thermal_system);
auto material = smith::makeTimeInfoMaterial(
smith::thermomechanics::GreenSaintVenantThermoelasticMaterial{1.0, 100.0, 0.25, 1.0, 0.0025, 0.0, 0.05});
smith::setCoupledThermoMechanicsMaterial(solid_system, thermal_system, material, mesh->entireBodyName());
Boundary Conditions and Loads¶
solid_system->setDisplacementBC(mesh->domain("left"));
thermal_system->setTemperatureBC(mesh->domain("left"), [](auto, auto) { return 1.0; });
thermal_system->setTemperatureBC(mesh->domain("right"), [](auto, auto) { return 0.0; });
solid_system->addTraction("right", [](double, auto X, auto, auto, auto, auto, auto... /*unused*/) {
auto traction = 0.0 * X;
traction[0] = -0.01;
return traction;
});
thermal_system->addHeatSource(mesh->entireBodyName(), [](auto, auto, auto, auto... /*unused*/) { return 0.5; });
Advance the Coupled System¶
auto physics = smith::makeDifferentiablePhysics(coupled_system, "composable_thermo_mechanics");
for (int step = 0; step < 2; ++step) {
physics->advanceTimestep(1.0);
}
This demo is intentionally small. Use it as a template for:
adding parameter fields
enabling stress output
adding internal variables