PolyFEM
Loading...
Searching...
No Matches
MatParams.cpp
Go to the documentation of this file.
1#include "MatParams.hpp"
2
5#include <polyfem/utils/StringUtils.hpp> // utils::resolve_path
6#include <iostream>
7#include <sstream>
8
9namespace polyfem::assembler
10{
11 namespace
12 {
13 double convert_to_lambda(const bool is_volume, const double E, const double nu)
14 {
15 if (is_volume)
16 return (E * nu) / ((1.0 + nu) * (1.0 - 2.0 * nu));
17
18 return (nu * E) / (1.0 - nu * nu);
19 }
20
21 // Reads a named VECTORS array under CELL_DATA from a legacy ASCII VTK
22 // file. Returns one Eigen::Vector3d per cell, in file order.
23 std::vector<Eigen::Vector3d> read_cell_vectors_legacy_vtk(
24 std::istream &in,
25 const std::string &description,
26 const std::string &field_name)
27 {
28 std::vector<Eigen::Vector3d> out;
29 std::string line;
30 int n_cell_data = -1;
31 bool found = false;
32
33 while (std::getline(in, line))
34 {
35 std::istringstream ss(line);
36 std::string tok;
37 ss >> tok;
38 if (tok == "CELL_DATA")
39 {
40 ss >> n_cell_data;
41 }
42 else if (tok == "VECTORS")
43 {
44 std::string name;
45 ss >> name;
46 if (name != field_name)
47 continue;
48 if (n_cell_data < 0)
49 log_and_throw_error("VECTORS encountered before CELL_DATA in fiber VTK");
50 out.resize(n_cell_data);
51 for (int i = 0; i < n_cell_data; ++i)
52 {
53 if (!(in >> out[i].x() >> out[i].y() >> out[i].z()))
54 log_and_throw_error(fmt::format(
55 "Fiber VTK '{}' ended early: expected {} vectors", description, n_cell_data));
56 }
57 found = true;
58 break;
59 }
60 }
61 if (!found)
62 log_and_throw_error(fmt::format(
63 "VECTORS '{}' not found under CELL_DATA in {}", field_name, description));
64 return out;
65 }
66
67 double convert_to_mu(const double E, const double nu)
68 {
69 return E / (2.0 * (1.0 + nu));
70 }
71 } // namespace
72
73 GenericMatParam::GenericMatParam(const std::string &param_name)
74 : param_name_(param_name)
75 {
76 }
77
78 void GenericMatParam::add_multimaterial(const int index, const json &params, const std::string &unit_type, const io::ResourceIO &resources)
79 {
80 for (int i = param_.size(); i <= index; ++i)
81 {
82 param_.emplace_back();
83 param_.back().set_unit_type(unit_type);
84 }
85
86 if (params.count(param_name_))
87 {
88 param_[index].init(params[param_name_], resources);
89 if (params.contains(MATERIAL_ELEMENT_INDEX))
90 param_[index].set_index(params[MATERIAL_ELEMENT_INDEX]);
91 }
92 }
93
94 double GenericMatParam::operator()(const RowVectorNd &p, double t, int index) const
95 {
96 const double x = p(0);
97 const double y = p(1);
98 const double z = p.size() == 3 ? p(2) : 0;
99
100 return (*this)(x, y, z, t, index);
101 }
102
103 double GenericMatParam::operator()(double x, double y, double z, double t, int index) const
104 {
105 assert(param_.size() == 1 || index < param_.size());
106
107 const auto &tmp_param = param_.size() == 1 ? param_[0] : param_[index];
108
109 return tmp_param(x, y, z, t, index);
110 }
111
112 GenericMatParams::GenericMatParams(const std::string &param_name)
113 : param_name_(param_name)
114 {
115 }
116
117 void GenericMatParams::add_multimaterial(const int index, const json &params, const std::string &unit_type, const io::ResourceIO &resources)
118 {
119 if (!params.contains(param_name_))
120 return;
121
122 std::vector<json> params_array = utils::json_as_array(params[param_name_]);
123 assert(params_array.size() == params_.size() || params_.empty());
124
125 if (params_.empty())
126 for (int i = 0; i < params_array.size(); ++i)
127 params_.emplace_back(param_name_ + "_" + std::to_string(i));
128
129 for (int i = 0; i < params_.size(); ++i)
130 {
131 for (int j = params_.at(i).param_.size(); j <= index; ++j)
132 {
133 params_.at(i).param_.emplace_back();
134 params_.at(i).param_.back().set_unit_type(unit_type);
135 }
136
137 params_.at(i).param_[index].init(params_array[i], resources);
138 if (params.contains(MATERIAL_ELEMENT_INDEX))
139 params_.at(i).param_[index].set_index(params[MATERIAL_ELEMENT_INDEX]);
140 }
141 }
142
143 void ElasticityTensor::resize(const int size)
144 {
145 if (size == 2)
146 stiffness_tensor_.resize(3, 3);
147 else
148 stiffness_tensor_.resize(6, 6);
149
150 stiffness_tensor_.setZero();
151
152 size_ = size;
153 }
154
155 double ElasticityTensor::operator()(int i, int j) const
156 {
157 if (j < i)
158 {
159 std::swap(i, j);
160 }
161
162 assert(j >= i);
163 return stiffness_tensor_(i, j);
164 }
165
166 double &ElasticityTensor::operator()(int i, int j)
167 {
168 if (j < i)
169 {
170 std::swap(i, j);
171 }
172
173 assert(j >= i);
174 return stiffness_tensor_(i, j);
175 }
176
177 void ElasticityTensor::set_from_entries(const std::vector<double> &entries, const std::string &stress_units, const io::ResourceIO &resources)
178 {
179 if (size_ == 2)
180 {
181 if (entries.size() == 4)
182 {
184 entries[0],
185 entries[1],
186 entries[2],
187 entries[3], stress_units, resources);
188
189 return;
190 }
191
192 assert(entries.size() >= 6);
193
194 (*this)(0, 0) = entries[0];
195 (*this)(0, 1) = entries[1];
196 (*this)(0, 2) = entries[2];
197
198 (*this)(1, 1) = entries[3];
199 (*this)(1, 2) = entries[4];
200
201 (*this)(2, 2) = entries[5];
202 }
203 else
204 {
205 if (entries.size() == 5)
206 {
208 entries[0],
209 entries[1],
210 entries[2],
211 entries[3],
212 entries[4],
213 stress_units, resources);
214
215 return;
216 }
217 else if (entries.size() == 9)
218 {
220 entries[0],
221 entries[1],
222 entries[2],
223 entries[3],
224 entries[4],
225 entries[5],
226 entries[6],
227 entries[7],
228 entries[8], stress_units, resources);
229
230 return;
231 }
232 assert(entries.size() >= 21);
233
234 (*this)(0, 0) = entries[0];
235 (*this)(0, 1) = entries[1];
236 (*this)(0, 2) = entries[2];
237 (*this)(0, 3) = entries[3];
238 (*this)(0, 4) = entries[4];
239 (*this)(0, 5) = entries[5];
240
241 (*this)(1, 1) = entries[6];
242 (*this)(1, 2) = entries[7];
243 (*this)(1, 3) = entries[8];
244 (*this)(1, 4) = entries[9];
245 (*this)(1, 5) = entries[10];
246
247 (*this)(2, 2) = entries[11];
248 (*this)(2, 3) = entries[12];
249 (*this)(2, 4) = entries[13];
250 (*this)(2, 5) = entries[14];
251
252 (*this)(3, 3) = entries[15];
253 (*this)(3, 4) = entries[16];
254 (*this)(3, 5) = entries[17];
255
256 (*this)(4, 4) = entries[18];
257 (*this)(4, 5) = entries[19];
258
259 (*this)(5, 5) = entries[20];
260 }
261 }
262
263 void ElasticityTensor::set_from_lambda_mu(const double lambda, const double mu, const std::string &stress_units, const io::ResourceIO &resources)
264 {
265 if (size_ == 2)
266 {
267 (*this)(0, 0) = 2 * mu + lambda;
268 (*this)(0, 1) = lambda;
269 (*this)(0, 2) = 0;
270
271 (*this)(1, 1) = 2 * mu + lambda;
272 (*this)(1, 2) = 0;
273
274 (*this)(2, 2) = mu;
275 }
276 else
277 {
278 (*this)(0, 0) = 2 * mu + lambda;
279 (*this)(0, 1) = lambda;
280 (*this)(0, 2) = lambda;
281 (*this)(0, 3) = 0;
282 (*this)(0, 4) = 0;
283 (*this)(0, 5) = 0;
284
285 (*this)(1, 1) = 2 * mu + lambda;
286 (*this)(1, 2) = lambda;
287 (*this)(1, 3) = 0;
288 (*this)(1, 4) = 0;
289 (*this)(1, 5) = 0;
290
291 (*this)(2, 2) = 2 * mu + lambda;
292 (*this)(2, 3) = 0;
293 (*this)(2, 4) = 0;
294 (*this)(2, 5) = 0;
295
296 (*this)(3, 3) = mu;
297 (*this)(3, 4) = 0;
298 (*this)(3, 5) = 0;
299
300 (*this)(4, 4) = mu;
301 (*this)(4, 5) = 0;
302
303 (*this)(5, 5) = mu;
304 }
305 }
306
307 void ElasticityTensor::set_from_young_poisson(const double young, const double nu, const std::string &stress_units, const io::ResourceIO &resources)
308 {
309 if (size_ == 2)
310 {
311 stiffness_tensor_ << 1.0, nu, 0.0,
312 nu, 1.0, 0.0,
313 0.0, 0.0, (1.0 - nu) / 2.0;
314 stiffness_tensor_ *= young / (1.0 - nu * nu);
315 }
316 else
317 {
318 assert(size_ == 3);
319 const double v = nu;
320 stiffness_tensor_ << 1. - v, v, v, 0, 0, 0,
321 v, 1. - v, v, 0, 0, 0,
322 v, v, 1. - v, 0, 0, 0,
323 0, 0, 0, (1. - 2. * v) / 2., 0, 0,
324 0, 0, 0, 0, (1. - 2. * v) / 2., 0,
325 0, 0, 0, 0, 0, (1. - 2. * v) / 2.;
326 stiffness_tensor_ *= young / ((1. + v) * (1. - 2. * v));
327 }
328 }
329
331 double Ex, double Ey, double Ez,
332 double nuXY, double nuXZ, double nuYZ,
333 double muYZ, double muZX, double muXY, const std::string &stress_units, const io::ResourceIO &resources)
334 {
335 assert(size_ == 3);
336
337 // from https://www.efunda.com/formulae/solid_mechanics/mat_mechanics/hooke_orthotropic.cfm
338 double nuYX = nuXY * Ey / Ex;
339 double nuZX = nuXZ * Ez / Ex;
340 double nuZY = nuYZ * Ez / Ey;
341
342 Eigen::MatrixXd compliance;
343 compliance.setZero(6, 6);
344 compliance << 1 / Ex, -nuYX / Ey, -nuZX / Ez, 0, 0, 0,
345 -nuXY / Ex, 1 / Ey, -nuZY / Ez, 0, 0, 0,
346 -nuXZ / Ex, -nuYZ / Ey, 1 / Ez, 0, 0, 0,
347 0, 0, 0, 1 / (2 * muYZ), 0, 0,
348 0, 0, 0, 0, 1 / (2 * muZX), 0,
349 0, 0, 0, 0, 0, 1 / (2 * muXY);
350 stiffness_tensor_ = compliance.inverse();
351 }
352
353 void ElasticityTensor::set_orthotropic(double Ex, double Ey, double nuXY, double muXY, const std::string &stress_units, const io::ResourceIO &resources)
354 {
355 assert(size_ == 2);
356
357 // from https://www.efunda.com/formulae/solid_mechanics/mat_mechanics/hooke_orthotropic.cfm
358 double nuYX = nuXY * Ey / Ex;
359
360 Eigen::MatrixXd compliance;
361 compliance.setZero(3, 3);
362 compliance << 1.0 / Ex, -nuYX / Ey, 0.0,
363 -nuXY / Ex, 1.0 / Ey, 0.0,
364 0.0, 0.0, 1.0 / (2 * muXY);
365 stiffness_tensor_ = compliance.inverse();
366 }
367
369 double Et, double Ea,
370 double nu_t, double nu_a,
371 double Ga, const std::string &stress_units, const io::ResourceIO &resources)
372 {
373 assert(size_ == 3);
374
375 // from https://osupdocs.forestry.oregonstate.edu/index.php/Transversely_Isotropic_Material
376 Eigen::MatrixXd compliance;
377 compliance.setZero(6, 6);
378 compliance << 1 / Et, -nu_t / Et, -nu_a / Ea, 0, 0, 0,
379 -nu_t / Et, 1 / Et, -nu_a / Ea, 0, 0, 0,
380 -nu_a / Ea, -nu_a / Ea, 1 / Ea, 0, 0, 0,
381 0, 0, 0, 1 / Ga, 0, 0,
382 0, 0, 0, 0, 1 / Ga, 0,
383 0, 0, 0, 0, 0, (2 * (1 + nu_t)) / Et;
384 stiffness_tensor_ = compliance.inverse();
385 }
386
387 template <int DIM>
388 double ElasticityTensor::compute_stress(const std::array<double, DIM> &strain, const int j) const
389 {
390 double res = 0;
391
392 for (int k = 0; k < DIM; ++k)
393 res += (*this)(j, k) * strain[k];
394
395 return res;
396 }
397
398 void ElasticityTensor::rotate_stiffness(const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6> &rotation_mtx_voigt)
399 {
401 stiffness_tensor_ = rotation_mtx_voigt * stiffness_tensor_ * rotation_mtx_voigt.transpose();
402 }
403
408
410 {
411 lambda_or_E_.emplace_back();
412 lambda_or_E_.back().init(1.0);
413
414 mu_or_nu_.emplace_back();
415 mu_or_nu_.back().init(1.0);
416 size_ = -1;
417 is_lambda_mu_ = true;
418 }
419
420 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
421 {
422 assert(lambda_or_E_.size() == 1 || el_id < lambda_or_E_.size());
423 assert(mu_or_nu_.size() == 1 || el_id < mu_or_nu_.size());
424 assert(size_ == 2 || size_ == 3);
425
426 const auto &tmp1 = lambda_or_E_.size() == 1 ? lambda_or_E_[0] : lambda_or_E_[el_id];
427 const auto &tmp2 = mu_or_nu_.size() == 1 ? mu_or_nu_[0] : mu_or_nu_[el_id];
428
429 double llambda = tmp1(x, y, z, t, el_id);
430 double mmu = tmp2(x, y, z, t, el_id);
431
432 if (!is_lambda_mu_)
433 {
434 lambda = convert_to_lambda(size_ == 3, llambda, mmu);
435 mu = convert_to_mu(llambda, mmu);
436 }
437 else
438 {
439 lambda = llambda;
440 mu = mmu;
441 }
442
443 if (lambda_mat_.size() > el_id && mu_mat_.size() > el_id)
444 {
445 lambda = lambda_mat_(el_id);
446 mu = mu_mat_(el_id);
447 }
448
449 assert(!std::isnan(lambda));
450 assert(!std::isnan(mu));
451 assert(!std::isinf(lambda));
452 assert(!std::isinf(mu));
453 }
454
455 void LameParameters::add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit, const io::ResourceIO &resources)
456 {
457 const int size = is_volume ? 3 : 2;
458 assert(size_ == -1 || size == size_);
459 size_ = size;
460
461 for (int i = lambda_or_E_.size(); i <= index; ++i)
462 {
463 lambda_or_E_.emplace_back();
464 lambda_or_E_.back().set_unit_type(stress_unit);
465 mu_or_nu_.emplace_back();
466 mu_or_nu_.back().set_unit_type("");
467 }
468
469 if (params.count("young"))
470 {
471 set_e_nu(index, params["young"], params["nu"], stress_unit, resources);
472 }
473 else if (params.count("E"))
474 {
475 set_e_nu(index, params["E"], params["nu"], stress_unit, resources);
476 }
477 else if (params.count("lambda"))
478 {
479 lambda_or_E_[index].init(params["lambda"], resources);
480 mu_or_nu_[index].init(params["mu"], resources);
481
482 lambda_or_E_[index].set_unit_type(stress_unit);
483 mu_or_nu_[index].set_unit_type(stress_unit);
484 is_lambda_mu_ = true;
485 }
486
487 if (params.contains(MATERIAL_ELEMENT_INDEX))
488 {
489 lambda_or_E_[index].set_index(params[MATERIAL_ELEMENT_INDEX]);
490 mu_or_nu_[index].set_index(params[MATERIAL_ELEMENT_INDEX]);
491 }
492 }
493
494 void LameParameters::set_e_nu(const int index, const json &E, const json &nu, const std::string &stress_unit, const io::ResourceIO &resources)
495 {
496 // TODO: conversion is always called
497 is_lambda_mu_ = false;
498 lambda_or_E_[index].init(E, resources);
499 mu_or_nu_[index].init(nu, resources);
500
501 lambda_or_E_[index].set_unit_type(stress_unit);
502 // nu has no unit
503 mu_or_nu_[index].set_unit_type("");
504 }
505
507 {
508 rho_.emplace_back();
509 rho_.back().init(1.0);
510 }
511
512 double Density::operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
513 {
514 assert(rho_.size() == 1 || el_id < rho_.size());
515
516 const auto &tmp = rho_.size() == 1 ? rho_[0] : rho_[el_id];
517 const double res = tmp(x, y, z, t, el_id);
518 assert(!std::isnan(res));
519 assert(!std::isinf(res));
520 return res;
521 }
522
523 void Density::add_multimaterial(const int index, const json &params, const std::string &density_unit, const io::ResourceIO &resources)
524 {
525 for (int i = rho_.size(); i <= index; ++i)
526 {
527 rho_.emplace_back();
528 }
529
530 if (params.count("rho"))
531 {
532 rho_[index].init(params["rho"], resources);
533 }
534 else if (params.count("density"))
535 {
536 rho_[index].init(params["density"], resources);
537 }
538 if (params.contains(MATERIAL_ELEMENT_INDEX))
539 rho_[index].set_index(params[MATERIAL_ELEMENT_INDEX]);
540
541 rho_[index].set_unit_type(density_unit);
542 }
543
545 : rho_("rho"), heat_capacity_("heat_capacity")
546 {
547 }
548
549 void ThermalMassDensity::add_multimaterial(const int index, const json &params, const std::string &density_unit, const io::ResourceIO &resources)
550 {
551 add_multimaterial(index, params, density_unit, "", resources);
552 }
553
554 void ThermalMassDensity::add_multimaterial(const int index, const json &params, const std::string &density_unit, const std::string &heat_capacity_unit, const io::ResourceIO &resources)
555 {
556 rho_.add_multimaterial(index, params, density_unit, resources);
557 heat_capacity_.add_multimaterial(index, params, heat_capacity_unit, resources);
558 }
559
560 double ThermalMassDensity::operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
561 {
562 const double rho = rho_(x, y, z, t, el_id);
563 const double heat_capacity = heat_capacity_(x, y, z, t, el_id);
564 const double res = rho * heat_capacity;
565 assert(!std::isnan(res));
566 assert(!std::isinf(res));
567 return res;
568 }
569
570 double ThermalMassDensity::rho(const RowVectorNd &p, double t, int el_id) const
571 {
572 return rho_(p, t, el_id);
573 }
574
575 double ThermalMassDensity::heat_capacity(const RowVectorNd &p, double t, int el_id) const
576 {
577 return heat_capacity_(p, t, el_id);
578 }
579
583
584 void FiberDirection::resize(const int size)
585 {
586 assert(size == 2 || size == 3);
587 size_ = size;
588 if (!dir_.empty())
589 {
590 for (const auto &m : dir_)
591 {
592 assert((m.rows() == size && m.cols() == size) || (m.rows() == size && m.cols() == 1));
593 }
594 }
595 }
596
597 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3> FiberDirection::operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
598 {
599 // Per-element fiber file: bound by global el_id, returned as a size_ x 1
600 // column vector so downstream is_a_vector logic is unchanged.
602 {
603 if (el_id < 0 || el_id >= static_cast<int>(per_el_fibers_.size()))
604 log_and_throw_error(fmt::format(
605 "Fiber el_id {} out of range [0,{})", el_id, per_el_fibers_.size()));
606 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3> res;
607 res.resize(size_, 1);
608 for (int i = 0; i < size_; ++i)
609 res(i, 0) = per_el_fibers_[el_id](i);
610 return res;
611 }
612
613 assert(dir_.size() == 1 || el_id < dir_.size());
614
615 const auto &tmp = dir_.size() == 1 ? dir_[0] : dir_[el_id];
616 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3> res;
617 res.resize(tmp.rows(), tmp.cols());
618 for (int i = 0; i < tmp.rows(); ++i)
619 {
620 for (int j = 0; j < tmp.cols(); ++j)
621 {
622 res(i, j) = tmp(i, j)(x, y, z, t, el_id);
623
624 assert(!std::isnan(res(i, j)));
625 assert(!std::isinf(res(i, j)));
626 }
627 }
628 return res;
629 }
630
631 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 6, 6> FiberDirection::stiffness_rotation_voigt(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
632 {
633 // Rotate stiffness mtx in voigt notation according to:
634 // https://scicomp.stackexchange.com/questions/35600/4th-order-tensor-rotation-sources-to-refer
635
636 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3> rot = (*this)(px, py, pz, x, y, z, t, el_id);
637 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 1, 6, 6> res;
638
639 int dim = rot.rows();
640
641 static const double sqrt2 = std::sqrt(2.0);
642
643 if (dim == 2)
644 {
645 res.resize(3, 3);
646 // Still need to compute for 2d
647 assert(false);
648 // res << rot(0, 0) * rot(0, 0), rot(0, 1) * rot(0, 1), 0,
649 // rot(1, 0) * rot(1, 0), rot(1, 1) * rot(1, 1), 0,
650 // 0, 0, 1;
651 }
652 else
653 {
654 assert(dim == 3);
655 res.resize(6, 6);
656 res << rot(0, 0) * rot(0, 0), rot(0, 1) * rot(0, 1), rot(0, 2) * rot(0, 2), sqrt2 * rot(0, 1) * rot(0, 2), sqrt2 * rot(0, 0) * rot(0, 2), sqrt2 * rot(0, 0) * rot(0, 1),
657 rot(1, 0) * rot(1, 0), rot(1, 1) * rot(1, 1), rot(1, 2) * rot(1, 2), sqrt2 * rot(1, 1) * rot(1, 2), sqrt2 * rot(1, 0) * rot(1, 2), sqrt2 * rot(1, 0) * rot(1, 1),
658 rot(2, 0) * rot(2, 0), rot(2, 1) * rot(2, 1), rot(2, 2) * rot(2, 2), sqrt2 * rot(2, 1) * rot(2, 2), sqrt2 * rot(2, 0) * rot(2, 2), sqrt2 * rot(2, 0) * rot(2, 1),
659 sqrt2 * rot(1, 0) * rot(2, 0), sqrt2 * rot(1, 1) * rot(2, 1), sqrt2 * rot(1, 2) * rot(2, 2), rot(1, 1) * rot(2, 2) + rot(1, 2) * rot(2, 1), rot(1, 0) * rot(2, 2) + rot(1, 2) * rot(2, 0), rot(1, 0) * rot(2, 1) + rot(1, 1) * rot(2, 0),
660 sqrt2 * rot(0, 0) * rot(2, 0), sqrt2 * rot(0, 1) * rot(2, 1), sqrt2 * rot(0, 2) * rot(2, 2), rot(0, 1) * rot(2, 2) + rot(0, 2) * rot(2, 1), rot(0, 0) * rot(2, 2) + rot(0, 2) * rot(2, 0), rot(0, 0) * rot(2, 1) + rot(0, 1) * rot(2, 0),
661 sqrt2 * rot(0, 0) * rot(1, 0), sqrt2 * rot(0, 1) * rot(1, 1), sqrt2 * rot(0, 2) * rot(1, 2), rot(0, 1) * rot(1, 2) + rot(0, 2) * rot(1, 1), rot(0, 0) * rot(1, 2) + rot(0, 2) * rot(1, 0), rot(0, 0) * rot(1, 1) + rot(0, 1) * rot(1, 0);
662 }
663
664 return res;
665 }
666
667 void FiberDirection::add_multimaterial(const int index, const json &dir, const std::string &unit, const io::ResourceIO &resources)
668 {
669 // Per-element fiber file:
670 // { "type": "per_element_file", "path": "...vtk", "field": "FIB_DIR1" }
671 // Read once at setup, bound by global el_id, normalized at load.
672 // NOTE: a JSON object with keys {type, path, field} reports size() == 3, so
673 // this MUST precede the size-based checks below to avoid being misread as a
674 // 3-component vector.
675 if (dir.is_object() && dir.value("type", std::string()) == "per_element_file")
676 {
677 const std::string field = dir.value("field", std::string("FIB_DIR1"));
678 const std::string path = dir.at("path").get<std::string>();
679 const std::string description = resources.describe(path);
680 auto input = resources.open(path, false);
681
682 per_el_fibers_ = read_cell_vectors_legacy_vtk(*input, description, field);
683 for (auto &v : per_el_fibers_)
684 {
685 const double n = v.norm();
686 if (n < 1e-12)
687 log_and_throw_error("Zero-length fiber vector in per-element file");
688 v /= n;
689 }
691 has_rotation_ = false; // a direction vector, not a rotation matrix
692 logger().info("FiberDirection: loaded {} per-element fibers ('{}') from {}",
693 per_el_fibers_.size(), field, description);
694 return; // dir_ left empty; operator() short-circuits
695 }
696
697 for (int i = dir_.size(); i <= index; ++i)
698 {
699 dir_.emplace_back();
700 }
701
702 if (dir.size() == 3 || dir.size() == 2)
703 {
704 const int size = dir.size();
705 const int other_size = dir[0].is_array() ? size : 1;
706
707 assert(size == size_);
708 dir_[index].resize(size, other_size);
709 for (int i = 0; i < size; ++i)
710 {
711 if (other_size == 1)
712 {
713 if (dir[i].is_array())
714 {
715 log_and_throw_error(fmt::format("Fiber must be a {} vector, row {} is {}", size, i, dir[i].dump()));
716 }
717 dir_[index](i, 0).init(dir[i], resources);
718 dir_[index](i, 0).set_unit_type(unit);
719 continue;
720 }
721 if (dir[i].size() != size)
722 {
723 log_and_throw_error(fmt::format("Fiber must be {}x{}, row {} is {}", size, other_size, i, dir[i].dump()));
724 }
725 for (int j = 0; j < size; ++j)
726 {
727 dir_[index](i, j).init(dir[i][j], resources);
728 dir_[index](i, j).set_unit_type(unit);
729 }
730 }
731 has_rotation_ = true;
732 }
733 else if (dir.size() == 9 || dir.size() == 4)
734 {
735 const int size = dir.size() == 9 ? 3 : 2;
736 assert(size == size_);
737 dir_[index].resize(size, size);
738 for (int i = 0; i < size; ++i)
739 {
740 for (int j = 0; j < size; ++j)
741 {
742 dir_[index](i, j).init(dir[i * size + j], resources);
743 dir_[index](i, j).set_unit_type(unit);
744 }
745 }
746 has_rotation_ = true;
747 }
748 else if (dir.empty())
749 {
750 dir_[index].resize(size_, size_);
751 for (int i = 0; i < size_; ++i)
752 {
753 for (int j = 0; j < size_; ++j)
754 {
755 dir_[index](i, j).init(i == j ? 1.0 : 0.0);
756 dir_[index](i, j).set_unit_type(unit);
757 }
758 }
759 has_rotation_ = false;
760 }
761 else
762 {
763 log_and_throw_error("Fiber direction must be a 3x3 or 2x2 matrix");
764 }
765 }
766
767 // template instantiation
768 template double ElasticityTensor::compute_stress<3>(const std::array<double, 3> &strain, const int j) const;
769 template double ElasticityTensor::compute_stress<6>(const std::array<double, 6> &strain, const int j) const;
770
771} // 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, const io::ResourceIO &resources)
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_young_poisson(const double young, const double poisson, const std::string &stress_unit, const io::ResourceIO &resources)
void set_from_entries(const std::vector< double > &entries, const std::string &stress_unit, const io::ResourceIO &resources)
void rotate_stiffness(const Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6 > &rotation_mtx_voigt)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6 > stiffness_tensor_
Definition MatParams.hpp:72
void set_transversely_isotropic(double Et, double Ea, double nu_t, double nu_a, double Ga, const std::string &stress_units, const io::ResourceIO &resources)
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, const io::ResourceIO &resources)
void set_from_lambda_mu(const double lambda, const double mu, const std::string &stress_unit, const io::ResourceIO &resources)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6 > reference_stiffness_tensor_
Definition MatParams.hpp:73
double compute_stress(const std::array< double, DIM > &strain, const int j) const
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 1, 6, 6 > stiffness_rotation_voigt(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
std::vector< Eigen::Matrix< utils::ExpressionValue, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3 > > dir_
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 1, 3, 3 > operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const
std::vector< Eigen::Vector3d > per_el_fibers_
void add_multimaterial(const int index, const json &params, const std::string &unit, const io::ResourceIO &resources)
double operator()(const RowVectorNd &p, double t, int index) const
Definition MatParams.cpp:94
GenericMatParam(const std::string &param_name)
Definition MatParams.cpp:73
void add_multimaterial(const int index, const json &params, const std::string &unit_type, const io::ResourceIO &resources)
Definition MatParams.cpp:78
std::vector< utils::ExpressionValue > param_
Definition MatParams.hpp:23
std::vector< GenericMatParam > params_
Definition MatParams.hpp:40
void add_multimaterial(const int index, const json &params, const std::string &unit_type, const io::ResourceIO &resources)
GenericMatParams(const std::string &param_name)
std::vector< utils::ExpressionValue > mu_or_nu_
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 add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit, const io::ResourceIO &resources)
std::vector< utils::ExpressionValue > lambda_or_E_
void set_e_nu(const int index, const json &E, const json &nu, const std::string &stress_unit, const io::ResourceIO &resources)
double rho(const RowVectorNd &p, double t, int el_id) const
double heat_capacity(const RowVectorNd &p, double t, int el_id) const
double operator()(double px, double py, double pz, double x, double y, double z, double t, int el_id) const override
void add_multimaterial(const int index, const json &params, const std::string &density_unit, const io::ResourceIO &resources) override
Read-only interface to a hierarchical collection of simulation resources.
virtual std::string describe(const std::string &path) const =0
virtual std::unique_ptr< std::istream > open(const std::string &path, bool binary) const =0
Used for test only.
constexpr const char * MATERIAL_ELEMENT_INDEX
Definition MatParams.hpp:9
std::vector< T > json_as_array(const json &j)
Return the value of a json object as an array.
Definition JSONUtils.hpp:49
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
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)
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73