20 #include "smith/physics/boundary_conditions/components.hpp"
28 namespace thermomechanics {
31 #ifdef MFEM_USE_STRUMPACK
41 .relative_tol = 1.0e-4,
42 .absolute_tol = 1.0e-8,
43 .max_iterations = 500,
48 template <
int order,
int dim,
typename parameters = Parameters<>,
49 typename parameter_indices = std::make_
integer_sequence<
int, parameters::n>>
57 template <
int order,
int dim,
typename... parameter_space,
int... parameter_indices>
59 std::integer_sequence<int, parameter_indices...>> :
public BasePhysics {
62 static constexpr
int VALUE = 0, DERIVATIVE = 1;
63 static constexpr
int SHAPE = 0;
64 static constexpr
auto I = Identity<dim>();
69 static constexpr
auto NUM_STATE_VARS = 2;
90 const std::string& physics_name, std::shared_ptr<smith::Mesh> smith_mesh,
91 std::vector<std::string> parameter_names = {},
int cycle = 0,
double time = 0.0,
92 bool checkpoint_to_disk =
false)
94 physics_name, smith_mesh, parameter_names, cycle, time, checkpoint_to_disk)
111 std::shared_ptr<smith::Mesh> smith_mesh, std::vector<std::string> parameter_names = {},
112 int cycle = 0,
double time = 0.0,
bool checkpoint_to_disk =
false)
113 :
BasePhysics(physics_name, smith_mesh, cycle, time, checkpoint_to_disk),
117 temperature_adjoint_(
118 StateManager::newState(H1<order>{}, detail::addPrefix(physics_name,
"temperature_adjoint"), mesh_->tag())),
120 H1<order, dim>{}, detail::addPrefix(physics_name,
"dispacement_adjoint"), mesh_->tag())),
122 H1<order>{}, detail::addPrefix(physics_name,
"temperature_adjoint_load"), mesh_->tag())),
124 H1<order, dim>{}, detail::addPrefix(physics_name,
"displacement_adjoint_load"), mesh_->tag())),
125 bcs_displacement_(mfemParMesh()),
126 block_residual_with_bcs_(temperature_.space().TrueVSize() + displacement_.space().TrueVSize()),
127 nonlin_solver_(std::move(solver))
130 SLIC_ERROR_ROOT_IF(mfemParMesh().Dimension() != dim,
131 std::format(
"Compile time dimension, {0}, and runtime mesh dimension, {1}, mismatch", dim,
132 mfemParMesh().Dimension()));
133 SLIC_ERROR_ROOT_IF(!nonlin_solver_,
134 "EquationSolver argument is nullptr in ThermoMechanics constructor. It is possible that it was "
135 "previously moved.");
137 is_quasistatic_ =
true;
139 states_.push_back(&temperature_);
140 states_.push_back(&displacement_);
142 adjoints_.push_back(&temperature_adjoint_);
143 adjoints_.push_back(&displacement_adjoint_);
145 const mfem::ParFiniteElementSpace* test_space_1 = &temperature_.space();
146 const mfem::ParFiniteElementSpace* test_space_2 = &displacement_.space();
147 const mfem::ParFiniteElementSpace* shape_space = &mesh_->shapeDisplacementSpace();
149 std::array<
const mfem::ParFiniteElementSpace*, NUM_STATE_VARS +
sizeof...(parameter_space)> trial_spaces;
150 trial_spaces[0] = &temperature_.space();
151 trial_spaces[1] = &displacement_.space();
154 sizeof...(parameter_space) != parameter_names.size(),
155 std::format(
"{} parameter spaces given in the template argument but {} parameter names were supplied.",
156 sizeof...(parameter_space), parameter_names.size()));
158 if constexpr (
sizeof...(parameter_space) > 0) {
159 tuple<parameter_space...> types{};
161 parameters_.emplace_back(mfemParMesh(), get<i>(types), detail::addPrefix(name_, parameter_names[i]));
162 trial_spaces[i + NUM_STATE_VARS] = &(parameters_[i].state->space());
166 residual_T_ = std::make_unique<
167 ShapeAwareFunctional<shape_trial, scalar_test(scalar_trial, vector_trial, parameter_space...)>>(
168 shape_space, test_space_1, trial_spaces);
169 residual_u_ = std::make_unique<
170 ShapeAwareFunctional<shape_trial, vector_test(scalar_trial, vector_trial, parameter_space...)>>(
171 shape_space, test_space_2, trial_spaces);
173 block_thermomech_offsets_.SetSize(NUM_STATE_VARS + 1);
174 block_thermomech_offsets_[0] = 0;
175 block_thermomech_offsets_[1] = temperature_.space().TrueVSize();
176 block_thermomech_offsets_[2] = displacement_.space().TrueVSize();
177 block_thermomech_offsets_.PartialSum();
179 block_thermomech_ = std::make_unique<mfem::BlockVector>(block_thermomech_offsets_);
181 block_thermomech_->GetBlock(0) = temperature_;
182 block_thermomech_->GetBlock(1) = displacement_;
184 block_thermomech_adjoint_ = std::make_unique<mfem::BlockVector>(block_thermomech_offsets_);
185 block_thermomech_adjoint_->GetBlock(0) = temperature_adjoint_;
186 block_thermomech_adjoint_->GetBlock(1) = displacement_adjoint_;
188 nonlin_solver_->setOperator(block_residual_with_bcs_);
190 block_nonlinear_oper_ = std::make_unique<mfem::BlockOperator>(block_thermomech_offsets_);
191 block_nonlinear_oper_transpose_ = std::make_unique<mfem::BlockOperator>(block_thermomech_offsets_);
193 initializeThermoMechanicsStates();
207 time_end_step_ = 0.0;
212 temperature_adjoint_ = 0.0;
213 displacement_adjoint_ = 0.0;
215 temperature_adjoint_load_ = 0.0;
216 displacement_adjoint_load_ = 0.0;
226 initializeThermoMechanicsStates();
228 if (!checkpoint_to_disk_) {
229 checkpoint_states_.clear();
230 auto state_names = stateNames();
231 for (
const auto& state_name : state_names) {
232 checkpoint_states_[state_name].push_back(state(state_name));
245 void setTemperatureBCs(
const std::set<int>& temp_bdr, std::function<
double(
const mfem::Vector& x,
double t)> temp)
248 temp_bdr_coef_ = std::make_shared<mfem::FunctionCoefficient>(temp);
250 bcs_.addEssential(temp_bdr, temp_bdr_coef_, temperature_.space());
261 template <
typename AppliedTemperatureFunction>
264 auto mfem_coefficient_function = [applied_temperature](
const mfem::Vector X_mfem,
double t) {
265 auto X = make_tensor<dim>([&X_mfem](
int i) {
return X_mfem[i]; });
266 return applied_temperature(X, t);
269 temp_bdr_coef_ = std::make_shared<mfem::FunctionCoefficient>(mfem_coefficient_function);
271 auto dof_list = domain.
dof_list(&temperature_.space());
273 bcs_.addEssential(dof_list, temp_bdr_coef_, temperature_.space(), 0);
298 template <
int... active_parameters,
typename FluxType>
301 residual_T_->AddBoundaryIntegral(
303 [flux_function](
double t,
auto X,
auto u,
auto... params) {
304 auto temp = get<VALUE>(u);
305 auto n =
cross(get<DERIVATIVE>(X));
307 return flux_function(X,
normalize(n), t, temp, params...);
313 template <
typename FluxType>
348 template <
typename AppliedDisplacementFunction>
352 for (
int i = 0; i < dim; ++i) {
353 if (components[
size_t(i)]) {
354 auto mfem_coefficient_function = [applied_displacement, i](
const mfem::Vector& X_mfem,
double t) {
355 auto X = make_tensor<dim>([&X_mfem](
int k) {
return X_mfem[k]; });
356 return applied_displacement(X, t)[i];
359 component_disp_bdr_coef_ = std::make_shared<mfem::FunctionCoefficient>(mfem_coefficient_function);
361 auto dof_list = domain.
dof_list(&displacement_.space());
364 displacement_.space().DofsToVDofs(i, dof_list);
366 bcs_displacement_.addEssential(dof_list, component_disp_bdr_coef_, displacement_.space(), i);
383 setDisplacementBCs(zero_vector_function, domain, components);
409 template <
int... active_parameters,
typename TractionType>
412 residual_u_->AddBoundaryIntegral(
414 [traction_function](
double t,
auto X,
auto... params) {
415 auto n =
cross(get<DERIVATIVE>(X));
417 return -1.0 * traction_function(get<VALUE>(X),
normalize(n), t, params...);
423 template <
typename TractionType>
426 setTraction(
DependsOn<>{}, traction_function, domain);
439 mfem::FunctionCoefficient temp_coef(temp);
441 temp_coef.SetTime(time_);
442 temperature_.project(temp_coef);
453 void setDisplacement(std::function<
void(
const mfem::Vector& x, mfem::Vector& disp)> disp)
456 mfem::VectorFunctionCoefficient disp_coef(dim, disp);
457 displacement_.project(disp_coef);
467 template <
typename MaterialType>
468 struct ThermalMaterialInterface {
480 template <
typename X,
typename T,
typename U,
typename... Params>
481 auto operator()(
double , X , T temperature, U displacement, Params... params)
const
483 typename MaterialType::State state{};
486 auto [theta, dtheta_dX] = temperature;
487 auto du_dX = get<DERIVATIVE>(displacement);
490 auto [stress, heat_accumulation, internal_heat_source, heat_flux] =
491 material_(state, du_dX, theta, dtheta_dX, params...);
494 return smith::tuple{-1.0 * internal_heat_source, -1.0 * heat_flux};
498 MaterialType material_;
505 template <
typename MaterialType>
506 struct SolidMaterialInterface {
513 template <
typename X,
typename T,
typename U,
typename... Params>
514 auto operator()(
double , X , T temperature, U displacement, Params... params)
const
516 typename MaterialType::State state{};
518 auto [theta, dtheta_dX] = temperature;
519 auto du_dX = get<DERIVATIVE>(displacement);
521 auto [stress, heat_accumulation, internal_heat_source, heat_flux] =
522 material_(state, du_dX, theta, dtheta_dX, params...);
528 MaterialType material_;
557 template <
int... active_parameters,
typename MaterialType>
561 ThermalMaterialInterface<MaterialType>(material), domain);
563 SolidMaterialInterface<MaterialType>(material), domain);
567 template <
typename MaterialType>
595 template <
int... active_parameters,
typename SourceType>
598 residual_T_->AddDomainIntegral(
600 [source_function](
double t,
auto x,
auto temperature,
auto... params) {
602 auto [T, dT_dX] = temperature;
604 auto source = source_function(x, t, T, dT_dX, params...);
613 template <
typename SourceType>
638 template <
int... active_parameters,
typename BodyForceType>
641 residual_u_->AddDomainIntegral(
643 [body_force](
double t,
auto x,
auto... params) {
644 auto bf = body_force(get<VALUE>(x), t, params...);
651 template <
typename BodyForceType>
662 temperature_.space().TrueVSize() + displacement_.space().TrueVSize(),
667 [
this](
const mfem::Vector& u, mfem::Vector& r) {
668 mfem::BlockVector block_u(const_cast<mfem::Vector&>(u), block_thermomech_offsets_);
669 mfem::BlockVector block_r(r, block_thermomech_offsets_);
671 auto temperature = block_u.GetBlock(0);
672 auto displacement = block_u.GetBlock(1);
674 auto r_1 = (*residual_T_)(time_, shapeDisplacement(), temperature, displacement,
675 *parameters_[parameter_indices].state...);
676 r_1.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0);
678 auto r_2 = (*residual_u_)(time_, shapeDisplacement(), temperature, displacement,
679 *parameters_[parameter_indices].state...);
680 r_2.SetSubVector(bcs_displacement_.allEssentialTrueDofs(), 0.0);
682 block_r.GetBlock(0) = r_1;
683 block_r.GetBlock(1) = r_2;
686 [
this](
const mfem::Vector& u) -> mfem::Operator& {
687 mfem::BlockVector block_u(const_cast<mfem::Vector&>(u), block_thermomech_offsets_);
689 auto temperature = block_u.GetBlock(0);
690 auto displacement = block_u.GetBlock(1);
693 auto [r1, dr1_dT] = (*residual_T_)(time_, shapeDisplacement(), differentiate_wrt(temperature), displacement,
694 *parameters_[parameter_indices].state...);
695 auto [_1, dr1_du] = (*residual_T_)(time_, shapeDisplacement(), temperature, differentiate_wrt(displacement),
696 *parameters_[parameter_indices].state...);
698 auto [r2, dr2_dT] = (*residual_u_)(time_, shapeDisplacement(), differentiate_wrt(temperature), displacement,
699 *parameters_[parameter_indices].state...);
700 auto [_2, dr2_du] = (*residual_u_)(time_, shapeDisplacement(), temperature, differentiate_wrt(displacement),
701 *parameters_[parameter_indices].state...);
704 J_11_ = assemble(dr1_dT);
705 J_12_ = assemble(dr1_du);
706 J_21_ = assemble(dr2_dT);
707 J_22_ = assemble(dr2_du);
710 auto ess_tdofs_T = bcs_.allEssentialTrueDofs();
712 mfem::HypreParMatrix* JTempTemp = J_11_->EliminateRowsCols(ess_tdofs_T);
713 mfem::HypreParMatrix* JDispTemp = J_21_->EliminateCols(ess_tdofs_T);
714 J_12_->EliminateRows(ess_tdofs_T);
719 auto ess_tdofs_u = bcs_displacement_.allEssentialTrueDofs();
721 mfem::HypreParMatrix* JDispDisp = J_22_->EliminateRowsCols(ess_tdofs_u);
722 mfem::HypreParMatrix* JTempDisp = J_12_->EliminateCols(ess_tdofs_u);
723 J_21_->EliminateRows(ess_tdofs_u);
729 block_nonlinear_oper_->SetBlock(0, 0, J_11_.get());
730 block_nonlinear_oper_->SetBlock(0, 1, J_12_.get());
731 block_nonlinear_oper_->SetBlock(1, 0, J_21_.get());
732 block_nonlinear_oper_->SetBlock(1, 1, J_22_.get());
734 return *block_nonlinear_oper_;
737 if (checkpoint_to_disk_) {
740 checkpoint_states_.clear();
741 auto state_names = stateNames();
742 for (
const auto& state_name : state_names) {
743 checkpoint_states_[state_name].push_back(state(state_name));
752 SLIC_ERROR_ROOT_IF(!residual_T_ || !residual_u_,
753 "completeSetup() must be called prior to advanceTimestep(dt) in ThermoMechanics.");
757 for (
auto& parameter : parameters_) {
758 *parameter.previous_state = *parameter.state;
764 for (
auto& bc : bcs_.essentials()) {
765 bc.setDofs(temperature_, time_);
768 for (
auto& bc : bcs_displacement_.essentials()) {
769 bc.setDofs(displacement_, time_);
773 block_thermomech_->GetBlock(0) = temperature_;
774 block_thermomech_->GetBlock(1) = displacement_;
777 nonlin_solver_->solve(*block_thermomech_);
780 static_cast<mfem::Vector&
>(temperature_) = block_thermomech_->GetBlock(0);
781 static_cast<mfem::Vector&
>(displacement_) = block_thermomech_->GetBlock(1);
785 if (checkpoint_to_disk_) {
788 auto state_names = stateNames();
789 for (
const auto& state_name : state_names) {
790 checkpoint_states_[state_name].push_back(state(state_name));
794 if (cycle_ > max_cycle_) {
795 timesteps_.push_back(dt);
813 void setAdjointLoad(std::unordered_map<std::string, const smith::FiniteElementDual&> loads)
override
815 SLIC_ERROR_ROOT_IF(loads.size() != 2,
816 "Adjoint load container is not the expected size of 2 in the thermomechanics module");
817 auto temperature_adjoint_load = loads.find(
"temperature");
819 SLIC_ERROR_ROOT_IF(temperature_adjoint_load == loads.end(),
"Adjoint load for \"temperature\" not found.");
821 temperature_adjoint_load_ = temperature_adjoint_load->second;
823 temperature_adjoint_load_ *= -1.0;
825 auto displacement_adjoint_load = loads.find(
"displacement");
827 SLIC_ERROR_ROOT_IF(displacement_adjoint_load == loads.end(),
"Adjoint load for \"displacement\" not found.");
829 displacement_adjoint_load_ = displacement_adjoint_load->second;
831 displacement_adjoint_load_ *= -1.0;
838 auto& linear_solver = nonlin_solver_->linearSolver();
842 double dt = getCheckpointedTimestep(cycle_ + 1);
844 auto end_step_solution = getCheckpointedStates(cycle_ + 1);
845 temperature_ = end_step_solution.at(
"temperature");
846 displacement_ = end_step_solution.at(
"displacement");
848 auto [r1, dr1_dT] = (*residual_T_)(time_, shapeDisplacement(),
differentiate_wrt(temperature_), displacement_,
849 *parameters_[parameter_indices].state...);
850 auto [_1, dr1_du] = (*residual_T_)(time_, shapeDisplacement(), temperature_,
differentiate_wrt(displacement_),
851 *parameters_[parameter_indices].state...);
853 auto [r2, dr2_dT] = (*residual_u_)(time_, shapeDisplacement(),
differentiate_wrt(temperature_), displacement_,
854 *parameters_[parameter_indices].state...);
855 auto [_2, dr2_du] = (*residual_u_)(time_, shapeDisplacement(), temperature_,
differentiate_wrt(displacement_),
856 *parameters_[parameter_indices].state...);
858 J_11_ = assemble(dr1_dT);
859 J_12_ = assemble(dr1_du);
860 J_21_ = assemble(dr2_dT);
861 J_22_ = assemble(dr2_du);
863 auto ess_tdofs_T = bcs_.allEssentialTrueDofs();
864 temperature_adjoint_load_.SetSubVector(ess_tdofs_T, 0.0);
866 mfem::HypreParMatrix* JTempTemp = J_11_->EliminateRowsCols(ess_tdofs_T);
867 mfem::HypreParMatrix* JDispTemp = J_21_->EliminateCols(ess_tdofs_T);
868 J_12_->EliminateRows(ess_tdofs_T);
873 auto ess_tdofs_u = bcs_displacement_.allEssentialTrueDofs();
874 displacement_adjoint_load_.SetSubVector(ess_tdofs_u, 0.0);
876 mfem::HypreParMatrix* JDispDisp = J_22_->EliminateRowsCols(ess_tdofs_u);
877 mfem::HypreParMatrix* JTempDisp = J_12_->EliminateCols(ess_tdofs_u);
878 J_21_->EliminateRows(ess_tdofs_u);
884 J_11_transpose_ = std::unique_ptr<mfem::HypreParMatrix>(J_11_->Transpose());
885 J_12_transpose_ = std::unique_ptr<mfem::HypreParMatrix>(J_12_->Transpose());
886 J_21_transpose_ = std::unique_ptr<mfem::HypreParMatrix>(J_21_->Transpose());
887 J_22_transpose_ = std::unique_ptr<mfem::HypreParMatrix>(J_22_->Transpose());
889 block_nonlinear_oper_transpose_->SetBlock(0, 0, J_11_transpose_.get());
890 block_nonlinear_oper_transpose_->SetBlock(0, 1, J_21_transpose_.get());
891 block_nonlinear_oper_transpose_->SetBlock(1, 0, J_12_transpose_.get());
892 block_nonlinear_oper_transpose_->SetBlock(1, 1, J_22_transpose_.get());
894 linear_solver.SetOperator(*block_nonlinear_oper_transpose_);
896 mfem::BlockVector block_thermomech_adjoint_load(block_thermomech_offsets_);
897 block_thermomech_adjoint_load.GetBlock(0) = temperature_adjoint_load_;
898 block_thermomech_adjoint_load.GetBlock(1) = displacement_adjoint_load_;
900 linear_solver.Mult(block_thermomech_adjoint_load, *block_thermomech_adjoint_);
903 static_cast<mfem::Vector&
>(temperature_adjoint_) = block_thermomech_adjoint_->GetBlock(0);
904 static_cast<mfem::Vector&
>(displacement_adjoint_) = block_thermomech_adjoint_->GetBlock(1);
907 nonlin_solver_->setOperator(block_residual_with_bcs_);
909 time_end_step_ = time_;
916 SLIC_ASSERT_MSG(parameter_field <
sizeof...(parameter_indices),
917 std::format(
"Invalid parameter index '{}' requested for sensitivity.", parameter_field));
919 auto dr1_dparam = smith::get<DERIVATIVE>(d_residual_T_d_[parameter_field](time_end_step_));
920 auto dr2_dparam = smith::get<DERIVATIVE>(d_residual_u_d_[parameter_field](time_end_step_));
922 auto dr1_dparam_mat = assemble(dr1_dparam);
923 auto dr2_dparam_mat = assemble(dr2_dparam);
925 dr1_dparam_mat->MultTranspose(temperature_adjoint_, *parameters_[parameter_field].sensitivity);
926 dr2_dparam_mat->AddMultTranspose(displacement_adjoint_, *parameters_[parameter_field].sensitivity);
928 return *parameters_[parameter_field].sensitivity;
935 smith::get<DERIVATIVE>((*residual_T_)(time_end_step_,
differentiate_wrt(shapeDisplacement()), temperature_,
936 displacement_, *parameters_[parameter_indices].state...));
938 smith::get<DERIVATIVE>((*residual_u_)(time_end_step_,
differentiate_wrt(shapeDisplacement()), temperature_,
939 displacement_, *parameters_[parameter_indices].state...));
941 auto dr1_dshape_mat = assemble(dr1_dshape);
942 auto dr2_dshape_mat = assemble(dr2_dshape);
944 dr1_dshape_mat->MultTranspose(temperature_adjoint_, shape_displacement_dual_);
945 dr2_dshape_mat->AddMultTranspose(displacement_adjoint_, shape_displacement_dual_);
947 return shapeDisplacementSensitivity();
953 if (state_name ==
"temperature") {
955 }
else if (state_name ==
"displacement") {
956 return displacement_;
958 SLIC_ERROR_ROOT(std::format(
"State '{}' requested from thermomechanics solver '{}', but it doesn't exist",
967 if (state_name ==
"temperature") {
968 temperature_ = state;
970 }
else if (state_name ==
"displacement") {
971 displacement_ = state;
976 std::format(
"setState for state name '{}' requested from thermomechanics module '{}', but it doesn't exist",
982 return std::vector<std::string>{{
"temperature"}, {
"displacement"}};
987 if (state_name ==
"temperature") {
988 return temperature_adjoint_;
989 }
else if (state_name ==
"displacement") {
990 return displacement_adjoint_;
992 SLIC_ERROR_ROOT(std::format(
"adjoint '{}' requested from thermomechanics solver '{}', but it doesn't exist",
996 return temperature_adjoint_;
1052 std::unique_ptr<smith::ShapeAwareFunctional<shape_trial, scalar_test(scalar_trial, vector_trial, parameter_space...)>>
1056 std::unique_ptr<smith::ShapeAwareFunctional<shape_trial, vector_test(scalar_trial, vector_trial, parameter_space...)>>
1066 std::unique_ptr<smith::EquationSolver> nonlin_solver_;
1069 mfem::Array<int> block_thermomech_offsets_;
1072 std::unique_ptr<mfem::BlockVector> block_thermomech_;
1075 std::unique_ptr<mfem::BlockVector> block_thermomech_adjoint_;
1078 std::unique_ptr<mfem::BlockOperator> block_nonlinear_oper_;
1081 std::unique_ptr<mfem::BlockOperator> block_nonlinear_oper_transpose_;
1084 std::unique_ptr<mfem::HypreParMatrix> J_11_;
1087 std::unique_ptr<mfem::HypreParMatrix> J_12_;
1090 std::unique_ptr<mfem::HypreParMatrix> J_21_;
1093 std::unique_ptr<mfem::HypreParMatrix> J_22_;
1096 std::unique_ptr<mfem::HypreParMatrix> J_11_transpose_;
1099 std::unique_ptr<mfem::HypreParMatrix> J_12_transpose_;
1102 std::unique_ptr<mfem::HypreParMatrix> J_21_transpose_;
1105 std::unique_ptr<mfem::HypreParMatrix> J_22_transpose_;
1109 double time_end_step_;
1112 std::shared_ptr<mfem::Coefficient> temp_bdr_coef_;
1115 std::shared_ptr<mfem::Coefficient> component_disp_bdr_coef_;
1120 std::array<std::function<decltype((*residual_T_)(
DifferentiateWRT<1>{}, 0.0, shape_displacement_, temperature_,
1121 displacement_, *parameters_[parameter_indices].state...))(double)>,
1122 sizeof...(parameter_indices)>
1123 d_residual_T_d_ = {[&](
double _t) {
1124 return (*residual_T_)(DifferentiateWRT<NUM_STATE_VARS + 1 + parameter_indices>{}, _t, shape_displacement_,
1125 temperature_, displacement_, *parameters_[parameter_indices].state...);
1128 std::array<std::function<decltype((*residual_u_)(DifferentiateWRT<1>{}, 0.0, shape_displacement_, temperature_,
1129 displacement_, *parameters_[parameter_indices].state...))(double)>,
1130 sizeof...(parameter_indices)>
1131 d_residual_u_d_ = {[&](
double _t) {
1132 return (*residual_u_)(DifferentiateWRT<NUM_STATE_VARS + 1 + parameter_indices>{}, _t, shape_displacement_,
1133 temperature_, displacement_, *parameters_[parameter_indices].state...);
The base interface class for a generic PDE solver.
This is the abstract base class for a generic forward solver.
void initializeBasePhysicsStates(int cycle, double time)
Protected, non-virtual method to reset physics states to zero. This does not reset design parameters ...
A container for the boundary condition information relating to a specific physics module.
A set to flag components of a vector field.
Class for encapsulating the dual vector space of a finite element space (i.e. the space of linear for...
Class for encapsulating the critical MFEM components of a primal finite element field.
static FiniteElementDual newDual(FunctionSpace space, const std::string &dual_name, const std::string &mesh_tag)
Factory method for creating a new FEDual object.
static FiniteElementState newState(FunctionSpace space, const std::string &state_name, const std::string &mesh_tag)
Factory method for creating a new FEState object.
void setFluxBCs(FluxType flux_function, Domain &domain)
This is an overloaded member function, provided for convenience. It differs from the above function o...
ThermomechanicsMonolithic(std::unique_ptr< EquationSolver > solver, const std::string &physics_name, std::shared_ptr< smith::Mesh > smith_mesh, std::vector< std::string > parameter_names={}, int cycle=0, double time=0.0, bool checkpoint_to_disk=false)
Construct a new Thermal-SolidMechanics object.
void setAdjointLoad(std::unordered_map< std::string, const smith::FiniteElementDual & > loads) override
Set the loads for the adjoint reverse timestep solve.
void setTemperatureBCs(const std::set< int > &temp_bdr, std::function< double(const mfem::Vector &x, double t)> temp)
Set essential temperature boundary conditions (strongly enforced)
void setTemperature(std::function< double(const mfem::Vector &x, double t)> temp)
Set the underlying finite element state to a prescribed temperature.
void addBodyForce(DependsOn< active_parameters... >, BodyForceType body_force, Domain &domain)
Set the body force function.
void setTraction(TractionType traction_function, Domain &domain)
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::shared_ptr< QuadratureData< T > > qdata_type
a container holding quadrature point data of the specified type
void completeSetup() override
This is an overloaded member function, provided for convenience. It differs from the above function o...
ThermomechanicsMonolithic(const NonlinearSolverOptions nonlinear_opts, const LinearSolverOptions lin_opts, const std::string &physics_name, std::shared_ptr< smith::Mesh > smith_mesh, std::vector< std::string > parameter_names={}, int cycle=0, double time=0.0, bool checkpoint_to_disk=false)
Construct a new Thermomechanics object.
const smith::FiniteElementState & displacement() const
Get the displacement state.
const smith::FiniteElementState & temperature() const
Get the temperature state.
void setState(const std::string &state_name, const FiniteElementState &state) override
Set the primal solution field values of the underlying physics solver.
const FiniteElementState & state(const std::string &state_name) const override
This is an overloaded member function, provided for convenience. It differs from the above function o...
const FiniteElementState & adjoint(const std::string &state_name) const override
Accessor for getting named finite element state adjoint solution from the physics modules.
const FiniteElementDual & computeTimestepShapeSensitivity() override
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setFluxBCs(DependsOn< active_parameters... >, FluxType flux_function, Domain &domain)
Set the thermal flux boundary condition.
std::vector< std::string > stateNames() const override
Get a vector of the finite element state primal solution names.
void addBodyForce(BodyForceType body_force, Domain &domain)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void reverseAdjointTimestep() override
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setTemperature(const FiniteElementState temp)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setSource(SourceType source_function, Domain &domain)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setDisplacement(std::function< void(const mfem::Vector &x, mfem::Vector &disp)> disp)
Set the underlying finite element state to a prescribed displacement.
virtual ~ThermomechanicsMonolithic()
Destroy the ThermoMechanics Functional object.
void setTraction(DependsOn< active_parameters... >, TractionType traction_function, Domain &domain)
Set the traction boundary condition.
void setFixedBCs(Domain &domain, Components components=Component::ALL)
Shortcut to set selected components of displacements to zero for all time.
void setTemperatureBCs(AppliedTemperatureFunction applied_temperature, Domain &domain)
Set essential temperature boundary conditions (strongly enforced) matching setDisplacementBCs signatu...
void setSource(DependsOn< active_parameters... >, SourceType source_function, Domain &domain)
Set the thermal source function.
void setMaterial(const MaterialType &material, Domain &domain)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setMaterial(DependsOn< active_parameters... >, const MaterialType &material, Domain &domain)
Set the thermomechanical material model for the physics solver.
void setDisplacement(const FiniteElementState &disp)
This is an overloaded member function, provided for convenience. It differs from the above function o...
FiniteElementDual computeTimestepSensitivity(size_t parameter_field) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
void resetStates(int cycle=0, double time=0.0) override
Virtual implementation of required state reset method.
void setDisplacementBCs(AppliedDisplacementFunction applied_displacement, Domain &domain, Components components=Component::ALL)
Set essential displacement boundary conditions on selected components.
void initializeThermoMechanicsStates()
Non virtual method to reset temperature and displacement states to zero. This does not reset design p...
void advanceTimestep(double dt) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
StdFunctionOperator is a class wrapping mfem::Operator so that the user can use std::function to defi...
Smith mesh class which assists in constructing the appropriate parallel mfem meshes and registering a...
const smith::LinearSolverOptions direct_linear_options
the default direct solver option for solving the linear stiffness equations
const smith::NonlinearSolverOptions default_nonlinear_options
Reasonable defaults for most thermomechanics nonlinear solver options.
Accelerator functionality.
tuple(T...) -> tuple< T... >
Class template argument deduction rule for tuples.
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 differentiate_wrt(const mfem::Vector &v)
this function is intended to only be used in combination with smith::Functional::operator(),...
SMITH_HOST_DEVICE auto normalize(const tensor< T, n... > &A)
Normalizes the tensor Each element is divided by the Frobenius norm of the tensor,...
#define SMITH_MARK_FUNCTION
Wrapper of smith::Functional for evaluating integrals and derivatives of quantities with shape displa...
This file contains the declaration of the StateManager class.
Classes for defining an mfem::Operator with std::functions.
Compile-time alias for a dimension.
a class for representing a geometric region that can be used for integration
mfem::Array< int > dof_list(const fes_t *fes) const
get mfem degree of freedom list for a given FiniteElementSpace
Parameters for an iterative linear solution scheme.
LinearSolver linear_solver
Linear solver selection.
Nonlinear solution scheme parameters.
NonlinearSolver nonlin_solver
Nonlinear solver selection.
a struct that is used in the physics modules to clarify which template arguments are user-controlled ...
auto operator()(double, X, T temperature, U displacement, Params... params) const
Material stress response call.
SolidMaterialInterface(MaterialType material)
Constructor for the functor.
ThermalMaterialInterface(MaterialType material)
Construct a ThermalMaterialIntegrand functor with material model of type MaterialType.
auto operator()(double, X, T temperature, U displacement, Params... params) const
Evaluate integrand.
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...
A sentinel struct for eliding no-op tensor operations.