PolyFEM
Loading...
Searching...
No Matches
MatParams.cpp
Go to the documentation of this file.
1#include "MatParams.hpp"
2
4
5namespace polyfem::assembler
6{
7 namespace
8 {
9 double convert_to_lambda(const bool is_volume, const double E, const double nu)
10 {
11 if (is_volume)
12 return (E * nu) / ((1.0 + nu) * (1.0 - 2.0 * nu));
13
14 return (nu * E) / (1.0 - nu * nu);
15 }
16
17 double convert_to_mu(const double E, const double nu)
18 {
19 return E / (2.0 * (1.0 + nu));
20 }
21 } // namespace
22
23 GenericMatParam::GenericMatParam(const std::string &param_name)
24 : param_name_(param_name)
25 {
26 }
27
28 void GenericMatParam::add_multimaterial(const int index, const json &params, const std::string &unit_type)
29 {
30 for (int i = param_.size(); i <= index; ++i)
31 {
32 param_.emplace_back();
33 }
34
35 if (params.count(param_name_))
36 {
37 param_[index].init(params[param_name_]);
38 param_[index].set_unit_type(unit_type);
39 }
40 }
41
42 double GenericMatParam::operator()(const RowVectorNd &p, double t, int index) const
43 {
44 const double x = p(0);
45 const double y = p(1);
46 const double z = p.size() == 3 ? p(2) : 0;
47
48 return (*this)(x, y, z, t, index);
49 }
50
51 double GenericMatParam::operator()(double x, double y, double z, double t, int index) const
52 {
53 assert(param_.size() == 1 || index < param_.size());
54
55 const auto &tmp_param = param_.size() == 1 ? param_[0] : param_[index];
56
57 return tmp_param(x, y, z, t, index);
58 }
59
60 GenericMatParams::GenericMatParams(const std::string &param_name)
61 : param_name_(param_name)
62 {
63 }
64
65 void GenericMatParams::add_multimaterial(const int index, const json &params, const std::string &unit_type)
66 {
67 if (!params.contains(param_name_))
68 return;
69
70 std::vector<json> params_array = utils::json_as_array(params[param_name_]);
71 assert(params_array.size() == params_.size() || params_.empty());
72
73 if (params_.empty())
74 for (int i = 0; i < params_array.size(); ++i)
75 params_.emplace_back(param_name_ + "_" + std::to_string(i));
76
77 for (int i = 0; i < params_.size(); ++i)
78 {
79 for (int j = params_.at(i).param_.size(); j <= index; ++j)
80 {
81 params_.at(i).param_.emplace_back();
82 }
83
84 params_.at(i).param_[index].init(params_array[i]);
85 params_.at(i).param_[index].set_unit_type(unit_type);
86 }
87 }
88
89 void ElasticityTensor::resize(const int size)
90 {
91 if (size == 2)
92 stifness_tensor_.resize(3, 3);
93 else
94 stifness_tensor_.resize(6, 6);
95
96 stifness_tensor_.setZero();
97
98 size_ = size;
99 }
100
101 double ElasticityTensor::operator()(int i, int j) const
102 {
103 if (j < i)
104 {
105 std::swap(i, j);
106 }
107
108 assert(j >= i);
109 return stifness_tensor_(i, j);
110 }
111
112 double &ElasticityTensor::operator()(int i, int j)
113 {
114 if (j < i)
115 {
116 std::swap(i, j);
117 }
118
119 assert(j >= i);
120 return stifness_tensor_(i, j);
121 }
122
123 void ElasticityTensor::set_from_entries(const std::vector<double> &entries, const std::string &stress_units)
124 {
125 if (size_ == 2)
126 {
127 if (entries.size() == 4)
128 {
130 entries[0],
131 entries[1],
132 entries[2],
133 entries[3], stress_units);
134
135 return;
136 }
137
138 assert(entries.size() >= 6);
139
140 (*this)(0, 0) = entries[0];
141 (*this)(0, 1) = entries[1];
142 (*this)(0, 2) = entries[2];
143
144 (*this)(1, 1) = entries[3];
145 (*this)(1, 2) = entries[4];
146
147 (*this)(2, 2) = entries[5];
148 }
149 else
150 {
151 if (entries.size() == 9)
152 {
154 entries[0],
155 entries[1],
156 entries[2],
157 entries[3],
158 entries[4],
159 entries[5],
160 entries[6],
161 entries[7],
162 entries[8], stress_units);
163
164 return;
165 }
166 assert(entries.size() >= 21);
167
168 (*this)(0, 0) = entries[0];
169 (*this)(0, 1) = entries[1];
170 (*this)(0, 2) = entries[2];
171 (*this)(0, 3) = entries[3];
172 (*this)(0, 4) = entries[4];
173 (*this)(0, 5) = entries[5];
174
175 (*this)(1, 1) = entries[6];
176 (*this)(1, 2) = entries[7];
177 (*this)(1, 3) = entries[8];
178 (*this)(1, 4) = entries[9];
179 (*this)(1, 5) = entries[10];
180
181 (*this)(2, 2) = entries[11];
182 (*this)(2, 3) = entries[12];
183 (*this)(2, 4) = entries[13];
184 (*this)(2, 5) = entries[14];
185
186 (*this)(3, 3) = entries[15];
187 (*this)(3, 4) = entries[16];
188 (*this)(3, 5) = entries[17];
189
190 (*this)(4, 4) = entries[18];
191 (*this)(4, 5) = entries[19];
192
193 (*this)(5, 5) = entries[20];
194 }
195 }
196
197 void ElasticityTensor::set_from_lambda_mu(const double lambda, const double mu, const std::string &stress_units)
198 {
199 if (size_ == 2)
200 {
201 (*this)(0, 0) = 2 * mu + lambda;
202 (*this)(0, 1) = lambda;
203 (*this)(0, 2) = 0;
204
205 (*this)(1, 1) = 2 * mu + lambda;
206 (*this)(1, 2) = 0;
207
208 (*this)(2, 2) = mu;
209 }
210 else
211 {
212 (*this)(0, 0) = 2 * mu + lambda;
213 (*this)(0, 1) = lambda;
214 (*this)(0, 2) = lambda;
215 (*this)(0, 3) = 0;
216 (*this)(0, 4) = 0;
217 (*this)(0, 5) = 0;
218
219 (*this)(1, 1) = 2 * mu + lambda;
220 (*this)(1, 2) = lambda;
221 (*this)(1, 3) = 0;
222 (*this)(1, 4) = 0;
223 (*this)(1, 5) = 0;
224
225 (*this)(2, 2) = 2 * mu + lambda;
226 (*this)(2, 3) = 0;
227 (*this)(2, 4) = 0;
228 (*this)(2, 5) = 0;
229
230 (*this)(3, 3) = mu;
231 (*this)(3, 4) = 0;
232 (*this)(3, 5) = 0;
233
234 (*this)(4, 4) = mu;
235 (*this)(4, 5) = 0;
236
237 (*this)(5, 5) = mu;
238 }
239 }
240
241 void ElasticityTensor::set_from_young_poisson(const double young, const double nu, const std::string &stress_units)
242 {
243 if (size_ == 2)
244 {
245 stifness_tensor_ << 1.0, nu, 0.0,
246 nu, 1.0, 0.0,
247 0.0, 0.0, (1.0 - nu) / 2.0;
248 stifness_tensor_ *= young / (1.0 - nu * nu);
249 }
250 else
251 {
252 assert(size_ == 3);
253 const double v = nu;
254 stifness_tensor_ << 1. - v, v, v, 0, 0, 0,
255 v, 1. - v, v, 0, 0, 0,
256 v, v, 1. - v, 0, 0, 0,
257 0, 0, 0, (1. - 2. * v) / 2., 0, 0,
258 0, 0, 0, 0, (1. - 2. * v) / 2., 0,
259 0, 0, 0, 0, 0, (1. - 2. * v) / 2.;
260 stifness_tensor_ *= young / ((1. + v) * (1. - 2. * v));
261 }
262 }
263
265 double Ex, double Ey, double Ez,
266 double nuXY, double nuXZ, double nuYZ,
267 double muYZ, double muZX, double muXY, const std::string &stress_units)
268 {
269 assert(size_ == 3);
270
271 // from https://www.efunda.com/formulae/solid_mechanics/mat_mechanics/hooke_orthotropic.cfm
272 double nuYX = nuXY * Ey / Ex;
273 double nuZX = nuXZ * Ez / Ex;
274 double nuZY = nuYZ * Ez / Ey;
275
276 Eigen::MatrixXd compliance;
277 compliance.setZero(6, 6);
278 compliance << 1 / Ex, -nuYX / Ey, -nuZX / Ez, 0, 0, 0,
279 -nuXY / Ex, 1 / Ey, -nuZY / Ez, 0, 0, 0,
280 -nuXZ / Ex, -nuYZ / Ey, 1 / Ez, 0, 0, 0,
281 0, 0, 0, 1 / (2 * muYZ), 0, 0,
282 0, 0, 0, 0, 1 / (2 * muZX), 0,
283 0, 0, 0, 0, 0, 1 / (2 * muXY);
284 stifness_tensor_ = compliance.inverse();
285 }
286
287 void ElasticityTensor::set_orthotropic(double Ex, double Ey, double nuXY, double muXY, const std::string &stress_units)
288 {
289 assert(size_ == 2);
290
291 // from https://www.efunda.com/formulae/solid_mechanics/mat_mechanics/hooke_orthotropic.cfm
292 double nuYX = nuXY * Ey / Ex;
293
294 Eigen::MatrixXd compliance;
295 compliance.setZero(3, 3);
296 compliance << 1.0 / Ex, -nuYX / Ey, 0.0,
297 -nuXY / Ex, 1.0 / Ey, 0.0,
298 0.0, 0.0, 1.0 / (2 * muXY);
299 stifness_tensor_ = compliance.inverse();
300 }
301
302 template <int DIM>
303 double ElasticityTensor::compute_stress(const std::array<double, DIM> &strain, const int j) const
304 {
305 double res = 0;
306
307 for (int k = 0; k < DIM; ++k)
308 res += (*this)(j, k) * strain[k];
309
310 return res;
311 }
312
314 {
315 lambda_or_E_.emplace_back();
316 lambda_or_E_.back().init(1.0);
317
318 mu_or_nu_.emplace_back();
319 mu_or_nu_.back().init(1.0);
320 size_ = -1;
321 is_lambda_mu_ = true;
322 }
323
324 void LameParameters::lambda_mu(double px, double py, double pz, double x, double y, double z, double t, int el_id, double &lambda, double &mu) const
325 {
326 assert(lambda_or_E_.size() == 1 || el_id < lambda_or_E_.size());
327 assert(mu_or_nu_.size() == 1 || el_id < mu_or_nu_.size());
328 assert(size_ == 2 || size_ == 3);
329
330 const auto &tmp1 = lambda_or_E_.size() == 1 ? lambda_or_E_[0] : lambda_or_E_[el_id];
331 const auto &tmp2 = mu_or_nu_.size() == 1 ? mu_or_nu_[0] : mu_or_nu_[el_id];
332
333 double llambda = tmp1(x, y, z, t, el_id);
334 double mmu = tmp2(x, y, z, t, el_id);
335
336 if (!is_lambda_mu_)
337 {
338 lambda = convert_to_lambda(size_ == 3, llambda, mmu);
339 mu = convert_to_mu(llambda, mmu);
340 }
341 else
342 {
343 lambda = llambda;
344 mu = mmu;
345 }
346
347 if (lambda_mat_.size() > el_id && mu_mat_.size() > el_id)
348 {
349 lambda = lambda_mat_(el_id);
350 mu = mu_mat_(el_id);
351 }
352
353 assert(!std::isnan(lambda));
354 assert(!std::isnan(mu));
355 assert(!std::isinf(lambda));
356 assert(!std::isinf(mu));
357 }
358
359 void LameParameters::add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit)
360 {
361 const int size = is_volume ? 3 : 2;
362 assert(size_ == -1 || size == size_);
363 size_ = size;
364
365 for (int i = lambda_or_E_.size(); i <= index; ++i)
366 {
367 lambda_or_E_.emplace_back();
368 mu_or_nu_.emplace_back();
369 }
370
371 if (params.count("young"))
372 {
373 set_e_nu(index, params["young"], params["nu"], stress_unit);
374 }
375 else if (params.count("E"))
376 {
377 set_e_nu(index, params["E"], params["nu"], stress_unit);
378 }
379 else if (params.count("lambda"))
380 {
381 lambda_or_E_[index].init(params["lambda"]);
382 mu_or_nu_[index].init(params["mu"]);
383
384 lambda_or_E_[index].set_unit_type(stress_unit);
385 mu_or_nu_[index].set_unit_type(stress_unit);
386 is_lambda_mu_ = true;
387 }
388 }
389
390 void LameParameters::set_e_nu(const int index, const json &E, const json &nu, const std::string &stress_unit)
391 {
392 // TODO: conversion is always called
393 is_lambda_mu_ = false;
394 lambda_or_E_[index].init(E);
395 mu_or_nu_[index].init(nu);
396
397 lambda_or_E_[index].set_unit_type(stress_unit);
398 // nu has no unit
399 mu_or_nu_[index].set_unit_type("");
400 }
401
403 {
404 rho_.emplace_back();
405 rho_.back().init(1.0);
406 }
407
408 double Density::operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
409 {
410 assert(rho_.size() == 1 || el_id < rho_.size());
411
412 const auto &tmp = rho_.size() == 1 ? rho_[0] : rho_[el_id];
413 const double res = tmp(x, y, z, t, el_id);
414 assert(!std::isnan(res));
415 assert(!std::isinf(res));
416 return res;
417 }
418
419 void Density::add_multimaterial(const int index, const json &params, const std::string &density_unit)
420 {
421 for (int i = rho_.size(); i <= index; ++i)
422 {
423 rho_.emplace_back();
424 }
425
426 if (params.count("rho"))
427 {
428 rho_[index].init(params["rho"]);
429 }
430 else if (params.count("density"))
431 {
432 rho_[index].init(params["density"]);
433 }
434
435 rho_[index].set_unit_type(density_unit);
436 }
437
438 // template instantiation
439 template double ElasticityTensor::compute_stress<3>(const std::array<double, 3> &strain, const int j) const;
440 template double ElasticityTensor::compute_stress<6>(const std::array<double, 6> &strain, const int j) const;
441
442} // namespace polyfem::assembler
std::vector< Eigen::Triplet< double > > entries
int y
int z
int x
std::vector< utils::ExpressionValue > rho_
virtual void add_multimaterial(const int index, const json &params, const std::string &density_unit)
virtual double operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
double operator()(int i, int j) const
void set_from_entries(const std::vector< double > &entries, const std::string &stress_unit)
void set_from_young_poisson(const double young, const double poisson, const std::string &stress_unit)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6 > stifness_tensor_
Definition MatParams.hpp:63
void set_orthotropic(double Ex, double Ey, double Ez, double nuXY, double nuXZ, double nuYZ, double muYZ, double muZX, double muXY, const std::string &stress_unit)
double compute_stress(const std::array< double, DIM > &strain, const int j) const
void set_from_lambda_mu(const double lambda, const double mu, const std::string &stress_unit)
void add_multimaterial(const int index, const json &params, const std::string &unit_type)
Definition MatParams.cpp:28
double operator()(const RowVectorNd &p, double t, int index) const
Definition MatParams.cpp:42
GenericMatParam(const std::string &param_name)
Definition MatParams.cpp:23
std::vector< utils::ExpressionValue > param_
Definition MatParams.hpp:21
void add_multimaterial(const int index, const json &params, const std::string &unit_type)
Definition MatParams.cpp:65
std::vector< GenericMatParam > params_
Definition MatParams.hpp:38
GenericMatParams(const std::string &param_name)
Definition MatParams.cpp:60
std::vector< utils::ExpressionValue > mu_or_nu_
Definition MatParams.hpp:92
void lambda_mu(double px, double py, double pz, double x, double y, double z, double t, int el_id, double &lambda, double &mu) const
void set_e_nu(const int index, const json &E, const json &nu, const std::string &stress_unit)
std::vector< utils::ExpressionValue > lambda_or_E_
Definition MatParams.hpp:92
void add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit)
Used for test only.
std::vector< T > json_as_array(const json &j)
Return the value of a json object as an array.
Definition JSONUtils.hpp:38
nlohmann::json json
Definition Common.hpp:9
double convert_to_mu(const double E, const double nu)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
double convert_to_lambda(const bool is_volume, const double E, const double nu)