17 const MixedNonLinearAssemblerData &data,
19 Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state)
21 const int n_phi_bases = int(data.phi_vals.basis_values.size());
22 const int n_psi_bases = int(data.psi_vals.basis_values.size());
23 const int phi_local_size = n_phi_bases *
dim;
24 const int local_size = phi_local_size + n_psi_bases;
26 Eigen::VectorXd values = Eigen::VectorXd::Zero(local_size);
27 for (
int i = 0; i < n_phi_bases; ++i)
29 const auto &bs = data.phi_vals.basis_values[i];
30 for (
const auto &global : bs.global)
32 for (
int d = 0; d <
dim; ++d)
33 values(i * dim + d) += global.val * data.x_phi(global.index * dim + d);
37 for (
int i = 0; i < n_psi_bases; ++i)
39 const auto &bs = data.psi_vals.basis_values[i];
40 for (
const auto &global : bs.global)
41 values(phi_local_size + i) += global.
val * data.x_psi(global.index);
45 local_state.resize(local_size);
47 const AutoDiffAllocator<T> allocate_auto_diff_scalar;
48 for (
int i = 0; i < local_size; ++i)
49 local_state(i) = allocate_auto_diff_scalar(i, values(i));
53 void displacement_gradient_at_quad(
54 const MixedNonLinearAssemblerData &data,
55 const Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state,
58 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> &grad_u)
60 grad_u.resize(dim, dim);
61 for (
int k = 0; k < grad_u.size(); ++k)
64 for (
int i = 0; i < data.phi_vals.basis_values.size(); ++i)
66 const auto &bs = data.phi_vals.basis_values[i];
67 const Eigen::Matrix<double, Eigen::Dynamic, 1, 0, 3, 1>
grad = bs.grad.row(p);
68 assert(
grad.size() == dim);
70 for (
int d = 0; d <
dim; ++d)
72 for (
int c = 0; c <
dim; ++c)
73 grad_u(d, c) +=
grad(c) * local_state(i * dim + d);
77 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> jac_it(dim, dim);
78 for (
int k = 0; k < jac_it.size(); ++k)
79 jac_it(k) =
T(data.phi_vals.jac_it[p](k));
80 grad_u = grad_u * jac_it;
84 T temperature_at_quad(
85 const MixedNonLinearAssemblerData &data,
86 const Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state,
90 const int phi_local_size = int(data.phi_vals.basis_values.size()) *
dim;
92 for (
int i = 0; i < data.psi_vals.basis_values.size(); ++i)
93 temperature += data.psi_vals.basis_values[i].val(p) * local_state(phi_local_size + i);
106 virtual std::map<std::string, Assembler::ParamFunc>
parameters()
const = 0;
115 template <
typename Elasticity>
122 std::map<std::string, Assembler::ParamFunc>
parameters()
const override;
135 template <
typename T>
149 if (elastic_formulation ==
"NeoHookean")
150 return std::make_unique<ThermoElasticityModelImpl<NeoHookeanElasticity>>();
152 log_and_throw_error(
"ThermoElasticity currently supports only NeoHookean elastic_material, got '{}'.", elastic_formulation);
156 template <
typename Elasticity>
158 : alpha_(
"alpha"), T0_(
"T0")
162 template <
typename Elasticity>
166 T0_.add_multimaterial(index, params, units.
temperature(), root_path);
168 if (!params.contains(
"elastic_material") || !params[
"elastic_material"].is_object())
169 log_and_throw_error(
"ThermoElasticity requires elastic_material to be an elastic material object.");
171 json elastic_params = params[
"elastic_material"];
172 const std::string type = elastic_params.value(
"type",
"");
173 if (type != elastic_.name())
174 log_and_throw_error(
"ThermoElasticity<{}> requires elastic_material '{}', got '{}'.", elastic_.name(), elastic_.name(), type);
176 if (params.contains(
"id"))
177 elastic_params[
"id"] = params[
"id"];
178 if (params.contains(
"rho"))
179 elastic_params[
"rho"] = params[
"rho"];
181 elastic_.add_multimaterial(index, elastic_params, units, root_path);
184 template <
typename Elasticity>
188 elastic_.set_size(size);
191 template <
typename Elasticity>
194 std::map<std::string, Assembler::ParamFunc> res;
195 res[
"alpha"] = [
this](
const RowVectorNd &uv,
const RowVectorNd &p,
double t,
int e) {
return alpha(uv, p, t, e); };
196 res[
"T0"] = [
this](
const RowVectorNd &uv,
const RowVectorNd &p,
double t,
int e) {
return T0(uv, p, t, e); };
200 template <
typename Elasticity>
203 return compute_energy_aux<double>(data);
206 template <
typename Elasticity>
209 const auto energy = compute_energy_aux<DScalar1<double, Eigen::VectorXd>>(data);
210 return energy.getGradient();
213 template <
typename Elasticity>
216 const auto energy = compute_energy_aux<DScalar2<double, Eigen::VectorXd, Eigen::MatrixXd>>(data);
217 return energy.getHessian();
220 template <
typename Elasticity>
221 template <
typename T>
224 assert(size() == 2 || size() == 3);
230 const int dim = size();
232 Eigen::Matrix<T, Eigen::Dynamic, 1> local_state;
233 get_local_state(data, dim, local_state);
235 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> grad_u(dim, dim);
236 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3>
F(dim, dim);
239 for (
int p = 0; p < data.
da.size(); ++p)
241 displacement_gradient_at_quad(data, local_state, p, dim, grad_u);
244 for (
int d = 0; d < dim; ++d)
247 const T temperature = temperature_at_quad(data, local_state, p, dim);
248 const double alpha = this->alpha(
250 const double T0 = this->T0(
254 const T theta = exp(T(alpha) * (temperature - T(T0)));
255 const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> Fe =
F / theta;
256 energy += (elastic_.elastic_energy_density(
258 - elastic_.elastic_energy_density(
266 template <
typename Elasticity>
269 return alpha_(p, t, element_id);
272 template <
typename Elasticity>
275 return T0_(p, t, element_id);
287 return model_->parameters();
294 model_->set_size(size);
299 if (!params.contains(
"elastic_material") || !params[
"elastic_material"].is_object())
300 log_and_throw_error(
"ThermoElasticity requires elastic_material to be an elastic material object.");
302 const std::string type = params[
"elastic_material"].value(
"type",
"");
306 elastic_formulation_ = type;
307 model_->set_size(size());
309 else if (type != elastic_formulation_)
312 "ThermoElasticity requires all elastic_material entries to have the same type, got '{}' and '{}'.",
313 elastic_formulation_, type);
316 model_->add_multimaterial(index, params, units, root_path);
321 return model().compute_energy(data);
326 return model().compute_gradient(data);
331 return model().compute_hessian(data);
337 log_and_throw_error(
"ThermoElasticity material model was used before materials were initialized.");
345 log_and_throw_error(
"ThermoElasticity material model was used before materials were initialized.");
std::string temperature() const
std::string one_over_temperature() const
virtual void set_size(const int size)
std::vector< AssemblyValues > basis_values
quadrature::Quadrature quadrature
const QuadratureVector & da
Contains both the quadrature weight and the change of metric in the integral.
const ElementAssemblyValues & phi_vals
Values for the first block, historically tensor velocity/displacement-like bases.
const ElementAssemblyValues & psi_vals
Values for the second block, historically scalar pressure-like bases.
std::map< std::string, ParamFunc > parameters() const override
double compute_energy(const MixedNonLinearAssemblerData &data) const override
void set_size(const int size) override
detail::ThermoElasticityModel & model()
Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const override
void add_multimaterial(const int index, const json ¶ms, const Units &units, const std::string &root_path) override
~ThermoElasticity() override
Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const override
virtual std::string elastic_name() const =0
virtual void set_size(const int size)=0
virtual Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const =0
virtual double compute_energy(const MixedNonLinearAssemblerData &data) const =0
virtual Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const =0
virtual ~ThermoElasticityModel()=default
virtual void add_multimaterial(const int index, const json ¶ms, const Units &units, const std::string &root_path)=0
virtual std::map< std::string, Assembler::ParamFunc > parameters() const =0
void add_multimaterial(const int index, const json ¶ms, const Units &units, const std::string &root_path) override
T compute_energy_aux(const MixedNonLinearAssemblerData &data) const
double compute_energy(const MixedNonLinearAssemblerData &data) const override
double alpha(const RowVectorNd &uv, const RowVectorNd &p, const double t, const int element_id) const
ThermoElasticityModelImpl()
std::map< std::string, Assembler::ParamFunc > parameters() const override
void set_size(const int size) override
Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const override
double T0(const RowVectorNd &uv, const RowVectorNd &p, const double t, const int element_id) const
Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const override
std::string elastic_name() const override
std::unique_ptr< ThermoElasticityModel > make_thermo_elasticity_model(const std::string &elastic_formulation)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
void log_and_throw_error(const std::string &msg)
static void setVariableCount(size_t value)
Set the independent variable count used by the automatic differentiation layer.