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 nuYX, double nuZX, double nuZY,
267 double muYZ, double muZX, double muXY, const std::string &stress_units)
268 {
269 // copied from Julian
270 assert(size_ == 3);
271 // Note: this isn't the flattened compliance tensor! Rather, it is the
272 // matrix inverse of the flattened elasticity tensor. See the tensor
273 // flattening writeup.
274 stifness_tensor_ << 1.0 / Ex, -nuYX / Ey, -nuZX / Ez, 0.0, 0.0, 0.0,
275 0.0, 1.0 / Ey, -nuZY / Ez, 0.0, 0.0, 0.0,
276 0.0, 0.0, 1.0 / Ez, 0.0, 0.0, 0.0,
277 0.0, 0.0, 0.0, 1.0 / muYZ, 0.0, 0.0,
278 0.0, 0.0, 0.0, 0.0, 1.0 / muZX, 0.0,
279 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 / muXY;
280 }
281
282 void ElasticityTensor::set_orthotropic(double Ex, double Ey, double nuYX, double muXY, const std::string &stress_units)
283 {
284 // copied from Julian
285 assert(size_ == 2);
286 // Note: this isn't the flattened compliance tensor! Rather, it is the
287 // matrix inverse of the flattened elasticity tensor.
288 stifness_tensor_ << 1.0 / Ex, -nuYX / Ey, 0.0,
289 0.0, 1.0 / Ey, 0.0,
290 0.0, 0.0, 1.0 / muXY;
291 }
292
293 template <int DIM>
294 double ElasticityTensor::compute_stress(const std::array<double, DIM> &strain, const int j) const
295 {
296 double res = 0;
297
298 for (int k = 0; k < DIM; ++k)
299 res += (*this)(j, k) * strain[k];
300
301 return res;
302 }
303
305 {
306 lambda_or_E_.emplace_back();
307 lambda_or_E_.back().init(1.0);
308
309 mu_or_nu_.emplace_back();
310 mu_or_nu_.back().init(1.0);
311 size_ = -1;
312 is_lambda_mu_ = true;
313 }
314
315 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
316 {
317 assert(lambda_or_E_.size() == 1 || el_id < lambda_or_E_.size());
318 assert(mu_or_nu_.size() == 1 || el_id < mu_or_nu_.size());
319 assert(size_ == 2 || size_ == 3);
320
321 const auto &tmp1 = lambda_or_E_.size() == 1 ? lambda_or_E_[0] : lambda_or_E_[el_id];
322 const auto &tmp2 = mu_or_nu_.size() == 1 ? mu_or_nu_[0] : mu_or_nu_[el_id];
323
324 double llambda = tmp1(x, y, z, t, el_id);
325 double mmu = tmp2(x, y, z, t, el_id);
326
327 if (!is_lambda_mu_)
328 {
329 lambda = convert_to_lambda(size_ == 3, llambda, mmu);
330 mu = convert_to_mu(llambda, mmu);
331 }
332 else
333 {
334 lambda = llambda;
335 mu = mmu;
336 }
337
338 if (lambda_mat_.size() > el_id && mu_mat_.size() > el_id)
339 {
340 lambda = lambda_mat_(el_id);
341 mu = mu_mat_(el_id);
342 }
343
344 assert(!std::isnan(lambda));
345 assert(!std::isnan(mu));
346 assert(!std::isinf(lambda));
347 assert(!std::isinf(mu));
348 }
349
350 void LameParameters::add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit)
351 {
352 const int size = is_volume ? 3 : 2;
353 assert(size_ == -1 || size == size_);
354 size_ = size;
355
356 for (int i = lambda_or_E_.size(); i <= index; ++i)
357 {
358 lambda_or_E_.emplace_back();
359 mu_or_nu_.emplace_back();
360 }
361
362 if (params.count("young"))
363 {
364 set_e_nu(index, params["young"], params["nu"], stress_unit);
365 }
366 else if (params.count("E"))
367 {
368 set_e_nu(index, params["E"], params["nu"], stress_unit);
369 }
370 else if (params.count("lambda"))
371 {
372 lambda_or_E_[index].init(params["lambda"]);
373 mu_or_nu_[index].init(params["mu"]);
374
375 lambda_or_E_[index].set_unit_type(stress_unit);
376 mu_or_nu_[index].set_unit_type(stress_unit);
377 is_lambda_mu_ = true;
378 }
379 }
380
381 void LameParameters::set_e_nu(const int index, const json &E, const json &nu, const std::string &stress_unit)
382 {
383 // TODO: conversion is always called
384 is_lambda_mu_ = false;
385 lambda_or_E_[index].init(E);
386 mu_or_nu_[index].init(nu);
387
388 lambda_or_E_[index].set_unit_type(stress_unit);
389 // nu has no unit
390 mu_or_nu_[index].set_unit_type("");
391 }
392
394 {
395 rho_.emplace_back();
396 rho_.back().init(1.0);
397 }
398
399 double Density::operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
400 {
401 assert(rho_.size() == 1 || el_id < rho_.size());
402
403 const auto &tmp = rho_.size() == 1 ? rho_[0] : rho_[el_id];
404 const double res = tmp(x, y, z, t, el_id);
405 assert(!std::isnan(res));
406 assert(!std::isinf(res));
407 return res;
408 }
409
410 void Density::add_multimaterial(const int index, const json &params, const std::string &density_unit)
411 {
412 for (int i = rho_.size(); i <= index; ++i)
413 {
414 rho_.emplace_back();
415 }
416
417 if (params.count("rho"))
418 {
419 rho_[index].init(params["rho"]);
420 }
421 else if (params.count("density"))
422 {
423 rho_[index].init(params["density"]);
424 }
425
426 rho_[index].set_unit_type(density_unit);
427 }
428
429 // template instantiation
430 template double ElasticityTensor::compute_stress<3>(const std::array<double, 3> &strain, const int j) const;
431 template double ElasticityTensor::compute_stress<6>(const std::array<double, 6> &strain, const int j) const;
432
433} // 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_orthotropic(double Ex, double Ey, double Ez, double nuYX, double nuZX, double nuZY, double muYZ, double muZX, double muXY, const std::string &stress_unit)
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
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:11
double convert_to_lambda(const bool is_volume, const double E, const double nu)