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