PolyFEM
Loading...
Searching...
No Matches
ThermoElasticity.cpp
Go to the documentation of this file.
2
5
8
9#include <cmath>
10
11namespace polyfem::assembler
12{
13 namespace
14 {
15 template <typename T>
16 void get_local_state(
17 const MixedNonLinearAssemblerData &data,
18 const int dim,
19 Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state)
20 {
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;
25
26 Eigen::VectorXd values = Eigen::VectorXd::Zero(local_size);
27 for (int i = 0; i < n_phi_bases; ++i)
28 {
29 const auto &bs = data.phi_vals.basis_values[i];
30 for (const auto &global : bs.global)
31 {
32 for (int d = 0; d < dim; ++d)
33 values(i * dim + d) += global.val * data.x_phi(global.index * dim + d);
34 }
35 }
36
37 for (int i = 0; i < n_psi_bases; ++i)
38 {
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);
42 }
43
45 local_state.resize(local_size);
46
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));
50 }
51
52 template <typename T>
53 void displacement_gradient_at_quad(
54 const MixedNonLinearAssemblerData &data,
55 const Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state,
56 const int p,
57 const int dim,
58 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> &grad_u)
59 {
60 grad_u.resize(dim, dim);
61 for (int k = 0; k < grad_u.size(); ++k)
62 grad_u(k) = T(0);
63
64 for (int i = 0; i < data.phi_vals.basis_values.size(); ++i)
65 {
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);
69
70 for (int d = 0; d < dim; ++d)
71 {
72 for (int c = 0; c < dim; ++c)
73 grad_u(d, c) += grad(c) * local_state(i * dim + d);
74 }
75 }
76
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;
81 }
82
83 template <typename T>
84 T temperature_at_quad(
85 const MixedNonLinearAssemblerData &data,
86 const Eigen::Matrix<T, Eigen::Dynamic, 1> &local_state,
87 const int p,
88 const int dim)
89 {
90 const int phi_local_size = int(data.phi_vals.basis_values.size()) * dim;
91 T temperature = T(0);
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);
94 return temperature;
95 }
96 } // namespace
97
98 namespace detail
99 {
101 {
102 public:
103 virtual ~ThermoElasticityModel() = default;
104
105 virtual std::string elastic_name() const = 0;
106 virtual std::map<std::string, Assembler::ParamFunc> parameters() const = 0;
107 virtual void set_size(const int size) = 0;
108 virtual void add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path) = 0;
109
110 virtual double compute_energy(const MixedNonLinearAssemblerData &data) const = 0;
111 virtual Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const = 0;
112 virtual Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const = 0;
113 };
114
115 template <typename Elasticity>
117 {
118 public:
120
121 std::string elastic_name() const override { return elastic_.name(); }
122 std::map<std::string, Assembler::ParamFunc> parameters() const override;
123
124 void set_size(const int size) override;
125 void add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path) override;
126
127 double compute_energy(const MixedNonLinearAssemblerData &data) const override;
128 Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const override;
129 Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const override;
130
131 private:
132 int size() const { return size_; }
133 int cols() const { return 1; }
134
135 template <typename T>
137
138 double alpha(const RowVectorNd &uv, const RowVectorNd &p, const double t, const int element_id) const;
139 double T0(const RowVectorNd &uv, const RowVectorNd &p, const double t, const int element_id) const;
140
141 int size_ = -1;
142 Elasticity elastic_;
145 };
146
147 std::unique_ptr<ThermoElasticityModel> make_thermo_elasticity_model(const std::string &elastic_formulation)
148 {
149 if (elastic_formulation == "NeoHookean")
150 return std::make_unique<ThermoElasticityModelImpl<NeoHookeanElasticity>>();
151
152 log_and_throw_error("ThermoElasticity currently supports only NeoHookean elastic_material, got '{}'.", elastic_formulation);
153 }
154 } // namespace detail
155
156 template <typename Elasticity>
161
162 template <typename Elasticity>
163 void detail::ThermoElasticityModelImpl<Elasticity>::add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path)
164 {
165 alpha_.add_multimaterial(index, params, units.one_over_temperature(), root_path);
166 T0_.add_multimaterial(index, params, units.temperature(), root_path);
167
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.");
170
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);
175
176 if (params.contains("id"))
177 elastic_params["id"] = params["id"];
178 if (params.contains("rho"))
179 elastic_params["rho"] = params["rho"];
180
181 elastic_.add_multimaterial(index, elastic_params, units, root_path);
182 }
183
184 template <typename Elasticity>
186 {
187 size_ = size;
188 elastic_.set_size(size);
189 }
190
191 template <typename Elasticity>
192 std::map<std::string, Assembler::ParamFunc> detail::ThermoElasticityModelImpl<Elasticity>::parameters() const
193 {
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); };
197 return res;
198 }
199
200 template <typename Elasticity>
202 {
203 return compute_energy_aux<double>(data);
204 }
205
206 template <typename Elasticity>
208 {
209 const auto energy = compute_energy_aux<DScalar1<double, Eigen::VectorXd>>(data);
210 return energy.getGradient();
211 }
212
213 template <typename Elasticity>
215 {
216 const auto energy = compute_energy_aux<DScalar2<double, Eigen::VectorXd, Eigen::MatrixXd>>(data);
217 return energy.getHessian();
218 }
219
220 template <typename Elasticity>
221 template <typename T>
223 {
224 assert(size() == 2 || size() == 3);
225 assert(cols() == 1);
226 assert(data.phi_vals.basis_values.size() > 0);
227 assert(data.psi_vals.basis_values.size() > 0);
228 assert(data.phi_vals.quadrature.weights.size() == data.psi_vals.quadrature.weights.size());
229
230 const int dim = size();
231
232 Eigen::Matrix<T, Eigen::Dynamic, 1> local_state;
233 get_local_state(data, dim, local_state);
234
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);
237
238 T energy = T(0);
239 for (int p = 0; p < data.da.size(); ++p)
240 {
241 displacement_gradient_at_quad(data, local_state, p, dim, grad_u);
242
243 F = grad_u;
244 for (int d = 0; d < dim; ++d)
245 F(d, d) += T(1);
246
247 const T temperature = temperature_at_quad(data, local_state, p, dim);
248 const double alpha = this->alpha(
249 data.phi_vals.quadrature.points.row(p), data.phi_vals.val.row(p), data.t, data.phi_vals.element_id);
250 const double T0 = this->T0(
251 data.phi_vals.quadrature.points.row(p), data.phi_vals.val.row(p), data.t, data.phi_vals.element_id);
252
253 using std::exp;
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(
257 data.phi_vals.quadrature.points.row(p), data.phi_vals.val.row(p), data.t, data.phi_vals.element_id, Fe)
258 - elastic_.elastic_energy_density(
259 data.phi_vals.quadrature.points.row(p), data.phi_vals.val.row(p), data.t, data.phi_vals.element_id, F))
260 * data.da(p);
261 }
262
263 return energy;
264 }
265
266 template <typename Elasticity>
267 double detail::ThermoElasticityModelImpl<Elasticity>::alpha(const RowVectorNd &, const RowVectorNd &p, const double t, const int element_id) const
268 {
269 return alpha_(p, t, element_id);
270 }
271
272 template <typename Elasticity>
273 double detail::ThermoElasticityModelImpl<Elasticity>::T0(const RowVectorNd &, const RowVectorNd &p, const double t, const int element_id) const
274 {
275 return T0_(p, t, element_id);
276 }
277
279
281
282 std::map<std::string, Assembler::ParamFunc> ThermoElasticity::parameters() const
283 {
284 if (!model_)
285 return {};
286
287 return model_->parameters();
288 }
289
290 void ThermoElasticity::set_size(const int size)
291 {
293 if (model_)
294 model_->set_size(size);
295 }
296
297 void ThermoElasticity::add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path)
298 {
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.");
301
302 const std::string type = params["elastic_material"].value("type", "");
303 if (!model_)
304 {
306 elastic_formulation_ = type;
307 model_->set_size(size());
308 }
309 else if (type != elastic_formulation_)
310 {
312 "ThermoElasticity requires all elastic_material entries to have the same type, got '{}' and '{}'.",
313 elastic_formulation_, type);
314 }
315
316 model_->add_multimaterial(index, params, units, root_path);
317 }
318
320 {
321 return model().compute_energy(data);
322 }
323
325 {
326 return model().compute_gradient(data);
327 }
328
330 {
331 return model().compute_hessian(data);
332 }
333
335 {
336 if (!model_)
337 log_and_throw_error("ThermoElasticity material model was used before materials were initialized.");
338
339 return *model_;
340 }
341
343 {
344 if (!model_)
345 log_and_throw_error("ThermoElasticity material model was used before materials were initialized.");
346
347 return *model_;
348 }
349
351
352} // namespace polyfem::assembler
double val
Definition Assembler.cpp:89
std::string temperature() const
Definition Units.hpp:38
std::string one_over_temperature() const
Definition Units.hpp:39
virtual void set_size(const int size)
Definition Assembler.hpp:66
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 &params, const Units &units, const std::string &root_path) override
Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const override
virtual std::string elastic_name() const =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 void add_multimaterial(const int index, const json &params, 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 &params, 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
std::map< std::string, Assembler::ParamFunc > parameters() const 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::unique_ptr< ThermoElasticityModel > make_thermo_elasticity_model(const std::string &elastic_formulation)
Used for test only.
nlohmann::json json
Definition Common.hpp:9
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
static void setVariableCount(size_t value)
Set the independent variable count used by the automatic differentiation layer.
Definition autodiff.h:54