PolyFEM
Loading...
Searching...
No Matches
GenericProblem.cpp
Go to the documentation of this file.
1#include "GenericProblem.hpp"
2
7
8namespace polyfem
9{
10 using namespace utils;
11
12 namespace assembler
13 {
14 namespace
15 {
16 std::vector<json> flatten_ids(const json &p_j_boundary_tmp)
17 {
18 const std::vector<json> j_boundary_tmp = utils::json_as_array(p_j_boundary_tmp);
19
20 std::vector<json> j_boundary;
21
22 for (size_t i = 0; i < j_boundary_tmp.size(); ++i)
23 {
24 const auto &tmp = j_boundary_tmp[i];
25
26 if (tmp.is_string())
27 {
28 j_boundary.push_back(tmp);
29 continue;
30 }
31 if (!tmp.contains("id"))
32 continue;
33
34 if (tmp["id"].is_array())
35 {
36 for (size_t j = 0; j < tmp["id"].size(); ++j)
37 {
38 json newj = tmp;
39 newj["id"] = tmp["id"][j].get<int>();
40 j_boundary.push_back(newj);
41 }
42 }
43 else
44 j_boundary.push_back(tmp);
45 }
46
47 return j_boundary;
48 }
49 } // namespace
50
51 double TensorBCValue::eval(const RowVectorNd &pts, const int dim, const double t, const int el_id) const
52 {
53 double x = pts(0);
54 double y = pts(1);
55 double z = pts.size() == 2 ? 0 : pts(2);
56
57 double val = value[dim](x, y, z, t, el_id);
58
59 if (interpolation.empty())
60 {
61 }
62 else if (interpolation.size() == 1)
63 val *= interpolation[0]->eval(t);
64 else
65 {
66 assert(dim < interpolation.size());
67 val *= interpolation[dim]->eval(t);
68 }
69
70 return val;
71 }
72
73 double ScalarBCValue::eval(const RowVectorNd &pts, const double t) const
74 {
75 assert(pts.size() == 2 || pts.size() == 3);
76 double x = pts(0), y = pts(1), z = pts.size() == 3 ? pts(2) : 0.0;
77 return value(x, y, z, t) * interpolation->eval(t);
78 }
79
81 : Problem(name), is_all_(false)
82 {
83 }
84
85 void GenericTensorProblem::set_units(const assembler::Assembler &assembler, const Units &units)
86 {
87 if (assembler.is_fluid())
88 {
89 for (int i = 0; i < 3; ++i)
90 {
91 rhs_[i].set_unit_type(units.force());
92 exact_[i].set_unit_type(units.velocity());
93 }
94 for (int i = 0; i < 3; ++i)
95 exact_grad_[i].set_unit_type("");
96
97 for (auto &v : displacements_)
98 v.set_unit_type(units.velocity());
99
100 for (auto &v : forces_)
101 v.set_unit_type(units.force());
102
103 for (auto &v : normal_aligned_forces_)
104 v.set_unit_type(units.pressure());
105
106 for (auto &v : pressures_)
107 v.set_unit_type(units.pressure());
108
109 for (auto &v : cavity_pressures_)
110 v.second.set_unit_type(units.pressure());
111
112 for (auto &v : initial_position_)
113 for (int i = 0; i < 3; ++i)
114 v.second[i].set_unit_type(units.velocity());
115
116 for (auto &v : initial_velocity_)
117 for (int i = 0; i < 3; ++i)
118 v.second[i].set_unit_type(units.velocity());
119
120 for (auto &v : initial_acceleration_)
121 for (int i = 0; i < 3; ++i)
122 v.second[i].set_unit_type(units.acceleration());
123
124 for (auto &v : nodal_dirichlet_)
125 v.second.set_unit_type(units.velocity());
126
127 for (auto &v : nodal_neumann_)
128 v.second.set_unit_type(units.force());
129 }
130 else
131 {
132 for (int i = 0; i < 3; ++i)
133 {
134 rhs_[i].set_unit_type(units.acceleration());
135 exact_[i].set_unit_type(units.length());
136 }
137 for (int i = 0; i < 3; ++i)
138 exact_grad_[i].set_unit_type("");
139
140 for (auto &v : displacements_)
141 v.set_unit_type(units.length());
142
143 for (auto &v : forces_)
144 v.set_unit_type(units.force());
145
146 for (auto &v : normal_aligned_forces_)
147 v.set_unit_type(units.pressure());
148
149 for (auto &v : pressures_)
150 v.set_unit_type(units.pressure());
151
152 for (auto &v : cavity_pressures_)
153 v.second.set_unit_type(units.pressure());
154
155 for (auto &v : initial_position_)
156 for (int i = 0; i < 3; ++i)
157 v.second[i].set_unit_type(units.length());
158
159 for (auto &v : initial_velocity_)
160 for (int i = 0; i < 3; ++i)
161 v.second[i].set_unit_type(units.velocity());
162
163 for (auto &v : initial_acceleration_)
164 for (int i = 0; i < 3; ++i)
165 v.second[i].set_unit_type(units.acceleration());
166
167 for (auto &v : nodal_dirichlet_)
168 v.second.set_unit_type(units.length());
169
170 for (auto &v : nodal_neumann_)
171 v.second.set_unit_type(units.force());
172 }
173 }
174
175 void GenericTensorProblem::rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
176 {
177 val.resize(pts.rows(), pts.cols());
178
179 if (is_rhs_zero())
180 {
181 val.setZero();
182 return;
183 }
184
185 const bool planar = pts.cols() == 2;
186 for (int i = 0; i < pts.rows(); ++i)
187 {
188 for (int j = 0; j < pts.cols(); ++j)
189 {
190 double x = pts(i, 0), y = pts(i, 1), z = planar ? 0 : pts(i, 2);
191 val(i, j) = rhs_[j](x, y, z, t);
192 }
193 }
194 }
195
196 bool GenericTensorProblem::is_dimension_dirichet(const int tag, const int dim) const
197 {
199 return true;
200
201 if (is_all_)
202 {
203 assert(displacements_.size() == 1);
204 return displacements_[0].dirichlet_dimension[dim];
205 }
206
207 for (size_t b = 0; b < boundary_ids_.size(); ++b)
208 {
209 if (tag == boundary_ids_[b])
210 {
211 auto &tmp = displacements_[b].dirichlet_dimension;
212 return tmp[dim];
213 }
214 }
215
216 assert(false);
217 return true;
218 }
219
220 void GenericTensorProblem::dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
221 {
222 val = Eigen::MatrixXd::Zero(pts.rows(), mesh.dimension());
223
224 for (long i = 0; i < pts.rows(); ++i)
225 {
226 if (is_all_)
227 {
228 assert(displacements_.size() == 1);
229 for (int d = 0; d < val.cols(); ++d)
230 {
231 val(i, d) = displacements_[0].eval(pts.row(i), d, t);
232 }
233 }
234 else
235 {
236 const int id = mesh.get_boundary_id(global_ids(i));
237 for (size_t b = 0; b < boundary_ids_.size(); ++b)
238 {
239 if (id == boundary_ids_[b])
240 {
241 for (int d = 0; d < val.cols(); ++d)
242 {
243 val(i, d) = displacements_[b].eval(pts.row(i), d, t);
244 }
245
246 break;
247 }
248 }
249 }
250 }
251 }
252
253 void GenericTensorProblem::neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const
254 {
255 val = Eigen::MatrixXd::Zero(pts.rows(), mesh.dimension());
256
257 for (long i = 0; i < pts.rows(); ++i)
258 {
259 const int id = mesh.get_boundary_id(global_ids(i));
260
261 for (size_t b = 0; b < neumann_boundary_ids_.size(); ++b)
262 {
263 if (id == neumann_boundary_ids_[b])
264 {
265 for (int d = 0; d < val.cols(); ++d)
266 {
267 val(i, d) = forces_[b].eval(pts.row(i), d, t);
268 }
269
270 break;
271 }
272 }
273
274 for (size_t b = 0; b < normal_aligned_neumann_boundary_ids_.size(); ++b)
275 {
277 {
278 for (int d = 0; d < val.cols(); ++d)
279 {
280 val(i, d) = normal_aligned_forces_[b].eval(pts.row(i), t) * normals(i, d);
281 }
282 break;
283 }
284 }
285 }
286 }
287
288 void GenericTensorProblem::pressure_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const
289 {
290 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
291
292 for (long i = 0; i < pts.rows(); ++i)
293 {
294 const int id = mesh.get_boundary_id(global_ids(i));
295
296 for (size_t b = 0; b < pressure_boundary_ids_.size(); ++b)
297 {
298 if (id == pressure_boundary_ids_[b])
299 {
300 val(i) = pressures_[b].eval(pts.row(i), t);
301 break;
302 }
303 }
304 }
305 }
306
307 double GenericTensorProblem::pressure_cavity_bc(const int boundary_id, const double t) const
308 {
309 Eigen::VectorXd pt;
310 pt.setZero(3);
311 return cavity_pressures_.at(boundary_id).eval(pt, t);
312 }
313
314 void GenericTensorProblem::exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
315 {
316 assert(has_exact_sol());
317 const bool planar = pts.cols() == 2;
318 val.resize(pts.rows(), pts.cols());
319
320 for (int i = 0; i < pts.rows(); ++i)
321 {
322 for (int j = 0; j < pts.cols(); ++j)
323 {
324 double x = pts(i, 0), y = pts(i, 1), z = planar ? 0 : pts(i, 2);
325 val(i, j) = exact_[j](x, y, z, t);
326 }
327 }
328 }
329
330 void GenericTensorProblem::exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
331 {
332 const int size = pts.cols();
333 val.resize(pts.rows(), pts.cols() * size);
334 if (!has_exact_grad_)
335 return;
336
337 const bool planar = size == 2;
338 for (int i = 0; i < pts.rows(); ++i)
339 {
340 for (int j = 0; j < pts.cols() * size; ++j)
341 {
342 double x = pts(i, 0), y = pts(i, 1), z = planar ? 0 : pts(i, 2);
343 val(i, j) = exact_grad_[j](x, y, z, t);
344 }
345 }
346 }
347
348 void GenericTensorProblem::dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val) const
349 {
350 val = Eigen::MatrixXd::Zero(1, mesh.dimension());
351 const int tag = mesh.get_node_id(node_id);
352
353 if (is_all_)
354 {
355 assert(nodal_dirichlet_.size() == 1);
356 const auto &tmp = nodal_dirichlet_.begin()->second;
357
358 for (int d = 0; d < val.cols(); ++d)
359 {
360 val(d) = tmp.eval(pt, d, t);
361 }
362
363 return;
364 }
365
366 const auto it = nodal_dirichlet_.find(tag);
367 if (it != nodal_dirichlet_.end())
368 {
369 for (int d = 0; d < val.cols(); ++d)
370 {
371 val(d) = it->second.eval(pt, d, t);
372 }
373
374 return;
375 }
376
377 for (const auto &n_dirichlet : nodal_dirichlet_mat_)
378 {
379 for (int i = 0; i < n_dirichlet.rows(); ++i)
380 {
381 if (n_dirichlet(i, 0) == node_id)
382 {
383 for (int d = 0; d < val.cols(); ++d)
384 {
385 val(d) = n_dirichlet(i, d + 1);
386 }
387
388 return;
389 }
390 }
391 }
392
393 assert(false);
394 }
395
396 void GenericTensorProblem::neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val) const
397 {
398 // TODO implement me;
399 log_and_throw_error("Nodal neumann not implemented");
400 }
401
402 bool GenericTensorProblem::is_nodal_dirichlet_boundary(const int n_id, const int tag)
403 {
404 if (nodal_dirichlet_.find(tag) != nodal_dirichlet_.end())
405 return true;
406
407 for (const auto &n_dirichlet : nodal_dirichlet_mat_)
408 {
409 for (int i = 0; i < n_dirichlet.rows(); ++i)
410 {
411 if (n_dirichlet(i, 0) == n_id)
412 return true;
413 }
414 }
415
416 return false;
417 }
418
419 bool GenericTensorProblem::is_nodal_neumann_boundary(const int n_id, const int tag)
420 {
421 return nodal_neumann_.find(tag) != nodal_neumann_.end();
422 }
423
425 {
426 return nodal_dirichlet_mat_.size() > 0;
427 }
428
430 {
431 return false; // nodal_neumann_.size() > 0;
432 }
433
434 bool GenericTensorProblem::is_nodal_dimension_dirichlet(const int n_id, const int tag, const int dim) const
435 {
436 const auto it = nodal_dirichlet_.find(tag);
437 if (it != nodal_dirichlet_.end())
438 {
439 return it->second.dirichlet_dimension(dim);
440 }
441
442 for (const auto &n_dirichlet : nodal_dirichlet_mat_)
443 {
444 for (int i = 0; i < n_dirichlet.rows(); ++i)
445 {
446 if (n_dirichlet(i, 0) == n_id)
447 {
448 return !std::isnan(n_dirichlet(i, dim + 1));
449 }
450 }
451 }
452
453 assert(false);
454 return true;
455 }
456
457 void GenericTensorProblem::update_nodes(const Eigen::VectorXi &in_node_to_node)
458 {
459 for (auto &n_dirichlet : nodal_dirichlet_mat_)
460 {
461 for (int n = 0; n < n_dirichlet.rows(); ++n)
462 {
463 const int node_id = in_node_to_node[n_dirichlet(n, 0)];
464 n_dirichlet(n, 0) = node_id;
465 }
466 }
467 }
468
470 {
471 if (is_param_valid(params, "is_time_dependent"))
472 {
473 is_time_dept_ = params["is_time_dependent"];
474 }
475
476 if (is_param_valid(params, "rhs"))
477 {
478 auto rr = params["rhs"];
479 if (rr.is_array())
480 {
481 for (size_t k = 0; k < rr.size(); ++k)
482 rhs_[k].init(rr[k]);
483 }
484 else
485 {
486 logger().warn("Invalid problem rhs: should be an array.");
487 assert(false);
488 }
489 }
490
491 if (is_param_valid(params, "reference") && is_param_valid(params["reference"], "solution"))
492 {
493 auto ex = params["reference"]["solution"];
494 has_exact_ = ex.size() > 0;
495 if (ex.is_array())
496 {
497 for (size_t k = 0; k < ex.size(); ++k)
498 exact_[k].init(ex[k]);
499 }
500 else
501 {
502 assert(false);
503 }
504 }
505
506 if (is_param_valid(params, "reference") && is_param_valid(params["reference"], "gradient"))
507 {
508 auto ex = params["reference"]["gradient"];
509 has_exact_grad_ = ex.size() > 0;
510 if (ex.is_array())
511 {
512 for (size_t k = 0; k < ex.size(); ++k)
513 exact_grad_[k].init(ex[k]);
514 }
515 else
516 {
517 assert(false);
518 }
519 }
520
521 if (is_param_valid(params, "dirichlet_boundary"))
522 {
523 // boundary_ids_.clear();
524 int offset = boundary_ids_.size();
525 std::vector<json> j_boundary = flatten_ids(params["dirichlet_boundary"]);
526
527 boundary_ids_.resize(offset + j_boundary.size());
528 displacements_.resize(offset + j_boundary.size());
529
530 for (size_t i = offset; i < boundary_ids_.size(); ++i)
531 {
532 if (j_boundary[i - offset].is_string())
533 {
534 const std::string path = resolve_path(j_boundary[i - offset], params["root_path"]);
535 if (!std::filesystem::is_regular_file(path))
536 log_and_throw_error("unable to open {} file", path);
537
538 Eigen::MatrixXd tmp;
539 io::read_matrix(path, tmp);
540 nodal_dirichlet_mat_.emplace_back(tmp);
541
542 continue;
543 }
544
545 int current_id = -1;
546
547 if (j_boundary[i - offset]["id"] == "all")
548 {
549 assert(boundary_ids_.size() == 1);
550 boundary_ids_.clear();
551 is_all_ = true;
552 nodal_dirichlet_[current_id] = TensorBCValue();
553 }
554 else
555 {
556 boundary_ids_[i] = j_boundary[i - offset]["id"];
557 current_id = boundary_ids_[i];
558 nodal_dirichlet_[current_id] = TensorBCValue();
559 }
560
561 auto ff = j_boundary[i - offset]["value"];
562 if (ff.is_array())
563 {
564 for (size_t k = 0; k < ff.size(); ++k)
565 {
566 displacements_[i].value[k].init(ff[k]);
567 if (j_boundary[i - offset].contains("time_reference") && j_boundary[i - offset]["time_reference"].size() > 0)
568 displacements_[i].value[k].set_t(j_boundary[i - offset]["time_reference"]);
569 nodal_dirichlet_[current_id].value[k].init(ff[k]);
570 }
571 }
572 else
573 {
574 assert(false);
575 displacements_[i].value[0].init(0);
576 displacements_[i].value[1].init(0);
577 displacements_[i].value[2].init(0);
578 }
579
580 displacements_[i].dirichlet_dimension.setConstant(true);
581 nodal_dirichlet_[current_id].dirichlet_dimension.setConstant(true);
582 if (j_boundary[i - offset].contains("dimension"))
583 {
585 auto &tmp = j_boundary[i - offset]["dimension"];
586 assert(tmp.is_array());
587 for (size_t k = 0; k < tmp.size(); ++k)
588 {
589 displacements_[i].dirichlet_dimension[k] = tmp[k];
590 nodal_dirichlet_[current_id].dirichlet_dimension[k] = tmp[k];
591 }
592 }
593
594 if (j_boundary[i - offset]["interpolation"].is_array())
595 {
596 for (int ii = 0; ii < j_boundary[i - offset]["interpolation"].size(); ++ii)
597 displacements_[i].interpolation.push_back(Interpolation::build(j_boundary[i - offset]["interpolation"][ii]));
598 }
599 else
600 displacements_[i].interpolation.push_back(Interpolation::build(j_boundary[i - offset]["interpolation"]));
601
602 nodal_dirichlet_[current_id].interpolation = displacements_[i].interpolation;
603 }
604 }
605
606 if (is_param_valid(params, "neumann_boundary"))
607 {
608 // neumann_boundary_ids_.clear();
609 const int offset = neumann_boundary_ids_.size();
610
611 auto j_boundary_tmp = params["neumann_boundary"];
612 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
613
614 neumann_boundary_ids_.resize(offset + j_boundary.size());
615 forces_.resize(offset + j_boundary.size());
616
617 for (size_t i = offset; i < neumann_boundary_ids_.size(); ++i)
618 {
619 neumann_boundary_ids_[i] = j_boundary[i - offset]["id"];
620
621 auto ff = j_boundary[i - offset]["value"];
622 assert(ff.is_array());
623
624 for (size_t k = 0; k < ff.size(); ++k)
625 forces_[i].value[k].init(ff[k]);
626
627 if (j_boundary[i - offset]["interpolation"].is_array())
628 {
629 for (int ii = 0; ii < j_boundary[i - offset]["interpolation"].size(); ++ii)
630 forces_[i].interpolation.push_back(Interpolation::build(j_boundary[i - offset]["interpolation"][ii]));
631 }
632 else
633 {
634 forces_[i].interpolation.push_back(Interpolation::build(j_boundary[i - offset]["interpolation"]));
635 }
636 }
637 }
638
639 if (is_param_valid(params, "normal_aligned_neumann_boundary"))
640 {
641 const int offset = normal_aligned_neumann_boundary_ids_.size();
642
643 auto j_boundary_tmp = params["normal_aligned_neumann_boundary"];
644 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
645
646 normal_aligned_neumann_boundary_ids_.resize(offset + j_boundary.size());
647 normal_aligned_forces_.resize(offset + j_boundary.size());
648
649 for (size_t i = offset; i < normal_aligned_neumann_boundary_ids_.size(); ++i)
650 {
651 normal_aligned_neumann_boundary_ids_[i] = j_boundary[i - offset]["id"];
652
653 auto ff = j_boundary[i - offset]["value"];
654 normal_aligned_forces_[i].value.init(ff);
655
656 if (j_boundary[i - offset].contains("interpolation"))
657 normal_aligned_forces_[i].interpolation = Interpolation::build(j_boundary[i - offset]["interpolation"]);
658 else
659 normal_aligned_forces_[i].interpolation = std::make_shared<NoInterpolation>();
660 }
661 }
662
663 if (is_param_valid(params, "pressure_boundary"))
664 {
665 // pressure_boundary_ids_.clear();
666 const int offset = pressure_boundary_ids_.size();
667
668 auto j_boundary_tmp = params["pressure_boundary"];
669 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
670
671 pressure_boundary_ids_.resize(offset + j_boundary.size());
672 pressures_.resize(offset + j_boundary.size());
673
674 for (size_t i = offset; i < pressure_boundary_ids_.size(); ++i)
675 {
676 pressure_boundary_ids_[i] = j_boundary[i - offset]["id"];
677
678 auto ff = j_boundary[i - offset]["value"];
679 pressures_[i].value.init(ff);
680 if (j_boundary[i - offset].contains("time_reference") && j_boundary[i - offset]["time_reference"].size() > 0)
681 pressures_[i].value.set_t(j_boundary[i - offset]["time_reference"]);
682
683 pressures_[i].interpolation = std::make_shared<NoInterpolation>();
684 }
685 }
686
687 if (is_param_valid(params, "pressure_cavity"))
688 {
689 const int offset = pressure_cavity_ids_.size();
690
691 auto j_boundary_tmp = params["pressure_cavity"];
692 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
693
694 pressure_cavity_ids_.resize(offset + j_boundary.size());
695
696 for (size_t i = offset; i < pressure_cavity_ids_.size(); ++i)
697 {
698 int boundary_id = j_boundary[i - offset]["id"];
699 pressure_cavity_ids_[i] = boundary_id;
700
701 if (cavity_pressures_.find(boundary_id) == cavity_pressures_.end())
702 {
703 cavity_pressures_[boundary_id] = ScalarBCValue();
704
705 auto ff = j_boundary[i - offset]["value"];
706 cavity_pressures_[boundary_id].value.init(ff);
707
708 cavity_pressures_[boundary_id].interpolation = std::make_shared<NoInterpolation>();
709 }
710 }
711 }
712
713 if (is_param_valid(params, "solution"))
714 {
715 auto rr = params["solution"];
716 initial_position_.resize(rr.size());
717 assert(rr.is_array());
718
719 for (size_t k = 0; k < rr.size(); ++k)
720 {
721 initial_position_[k].first = rr[k]["id"];
722 const auto v = rr[k]["value"];
723 for (size_t d = 0; d < v.size(); ++d)
724 initial_position_[k].second[d].init(v[d]);
725 }
726 }
727
728 if (is_param_valid(params, "velocity"))
729 {
730 auto rr = params["velocity"];
731 initial_velocity_.resize(rr.size());
732 assert(rr.is_array());
733
734 for (size_t k = 0; k < rr.size(); ++k)
735 {
736 initial_velocity_[k].first = rr[k]["id"];
737 const auto v = rr[k]["value"];
738 for (size_t d = 0; d < v.size(); ++d)
739 initial_velocity_[k].second[d].init(v[d]);
740 }
741 }
742
743 if (is_param_valid(params, "acceleration"))
744 {
745 auto rr = params["acceleration"];
746 initial_acceleration_.resize(rr.size());
747 assert(rr.is_array());
748
749 for (size_t k = 0; k < rr.size(); ++k)
750 {
751 initial_acceleration_[k].first = rr[k]["id"];
752 const auto v = rr[k]["value"];
753 for (size_t d = 0; d < v.size(); ++d)
754 initial_acceleration_[k].second[d].init(v[d]);
755 }
756 }
757 }
758
759 void GenericTensorProblem::initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const
760 {
761 val.resize(pts.rows(), pts.cols());
762 if (initial_position_.empty())
763 {
764 val.setZero();
765 return;
766 }
767
768 const bool planar = pts.cols() == 2;
769 for (int i = 0; i < pts.rows(); ++i)
770 {
771 const int id = mesh.get_body_id(global_ids(i));
772 int index = -1;
773 for (int j = 0; j < initial_position_.size(); ++j)
774 {
775 if (initial_position_[j].first == id)
776 {
777 index = j;
778 break;
779 }
780 }
781 if (index < 0)
782 {
783 val.row(i).setZero();
784 continue;
785 }
786
787 for (int j = 0; j < pts.cols(); ++j)
788 val(i, j) = planar ? initial_position_[index].second[j](pts(i, 0), pts(i, 1)) : initial_position_[index].second[j](pts(i, 0), pts(i, 1), pts(i, 2));
789 }
790 }
791
792 void GenericTensorProblem::initial_velocity(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const
793 {
794 val.resize(pts.rows(), pts.cols());
795 if (initial_velocity_.empty())
796 {
797 val.setZero();
798 return;
799 }
800
801 const bool planar = pts.cols() == 2;
802 for (int i = 0; i < pts.rows(); ++i)
803 {
804 const int id = mesh.get_body_id(global_ids(i));
805 int index = -1;
806 for (int j = 0; j < initial_velocity_.size(); ++j)
807 {
808 if (initial_velocity_[j].first == id)
809 {
810 index = j;
811 break;
812 }
813 }
814 if (index < 0)
815 {
816 val.row(i).setZero();
817 continue;
818 }
819
820 for (int j = 0; j < pts.cols(); ++j)
821 val(i, j) = planar ? initial_velocity_[index].second[j](pts(i, 0), pts(i, 1)) : initial_velocity_[index].second[j](pts(i, 0), pts(i, 1), pts(i, 2));
822 }
823 }
824
825 void GenericTensorProblem::initial_acceleration(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const
826 {
827 val.resize(pts.rows(), pts.cols());
828 if (initial_acceleration_.empty())
829 {
830 val.setZero();
831 return;
832 }
833
834 const bool planar = pts.cols() == 2;
835 for (int i = 0; i < pts.rows(); ++i)
836 {
837 const int id = mesh.get_body_id(global_ids(i));
838 int index = -1;
839 for (int j = 0; j < initial_acceleration_.size(); ++j)
840 {
841 if (initial_acceleration_[j].first == id)
842 {
843 index = j;
844 break;
845 }
846 }
847 if (index < 0)
848 {
849 val.row(i).setZero();
850 continue;
851 }
852
853 for (int j = 0; j < pts.cols(); ++j)
854 val(i, j) = planar ? initial_acceleration_[index].second[j](pts(i, 0), pts(i, 1)) : initial_acceleration_[index].second[j](pts(i, 0), pts(i, 1), pts(i, 2));
855 }
856 }
857
859 {
861 has_exact_ = false;
862 has_exact_grad_ = false;
863 is_time_dept_ = false;
864
865 forces_.clear();
866 displacements_.clear();
868 pressures_.clear();
869 cavity_pressures_.clear();
870
871 nodal_dirichlet_.clear();
872 nodal_neumann_.clear();
873 nodal_dirichlet_mat_.clear();
874
875 initial_position_.clear();
876 initial_velocity_.clear();
877 initial_acceleration_.clear();
878
879 for (int i = 0; i < rhs_.size(); ++i)
880 rhs_[i].clear();
881 for (int i = 0; i < exact_.size(); ++i)
882 exact_[i].clear();
883 for (int i = 0; i < exact_grad_.size(); ++i)
884 exact_grad_[i].clear();
885 is_all_ = false;
886 }
887
889 : Problem(name), is_all_(false)
890 {
891 }
892
893 void GenericScalarProblem::set_units(const assembler::Assembler &assembler, const Units &units)
894 {
895 // TODO?
896
897 for (auto &v : neumann_)
898 v.set_unit_type("");
899
900 for (auto &v : dirichlet_)
901 v.set_unit_type("");
902
903 for (auto &v : initial_solution_)
904 v.second.set_unit_type("");
905
908
909 for (int i = 0; i < 3; ++i)
910 exact_grad_[i].set_unit_type("");
911 }
912
913 void GenericScalarProblem::rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
914 {
915 val.resize(pts.rows(), 1);
916 if (is_rhs_zero())
917 {
918 val.setZero();
919 return;
920 }
921 const bool planar = pts.cols() == 2;
922 for (int i = 0; i < pts.rows(); ++i)
923 {
924 double x = pts(i, 0), y = pts(i, 1), z = planar ? 0 : pts(i, 2);
925 val(i) = rhs_(x, y, z, t);
926 }
927 }
928
929 void GenericScalarProblem::dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
930 {
931 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
932
933 for (long i = 0; i < pts.rows(); ++i)
934 {
935 const int id = mesh.get_boundary_id(global_ids(i));
936 if (is_all_)
937 {
938 assert(dirichlet_.size() == 1);
939 val(i) = dirichlet_[0].eval(pts.row(i), t);
940 }
941 else
942 {
943 for (size_t b = 0; b < boundary_ids_.size(); ++b)
944 {
945 if (id == boundary_ids_[b])
946 {
947 val(i) = dirichlet_[b].eval(pts.row(i), t);
948 break;
949 }
950 }
951 }
952 }
953 }
954
955 void GenericScalarProblem::neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const
956 {
957 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
958
959 for (long i = 0; i < pts.rows(); ++i)
960 {
961 const int id = mesh.get_boundary_id(global_ids(i));
962
963 for (size_t b = 0; b < neumann_boundary_ids_.size(); ++b)
964 {
965 if (id == neumann_boundary_ids_[b])
966 {
967 double x = pts(i, 0), y = pts(i, 1), z = pts.cols() == 2 ? 0 : pts(i, 2);
968 val(i) = neumann_[b].eval(pts.row(i), t);
969 break;
970 }
971 }
972 }
973 }
974
975 void GenericScalarProblem::initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const
976 {
977 val.resize(pts.rows(), 1);
978 if (initial_solution_.empty())
979 {
980 val.setZero();
981 return;
982 }
983
984 const bool planar = pts.cols() == 2;
985 for (int i = 0; i < pts.rows(); ++i)
986 {
987 const int id = mesh.get_body_id(global_ids(i));
988 int index = -1;
989 for (int j = 0; j < initial_solution_.size(); ++j)
990 {
991 if (initial_solution_[j].first == id)
992 {
993 index = j;
994 break;
995 }
996 }
997 if (index < 0)
998 {
999 val(i) = 0;
1000 continue;
1001 }
1002
1003 val(i) = planar ? initial_solution_[index].second(pts(i, 0), pts(i, 1)) : initial_solution_[index].second(pts(i, 0), pts(i, 1), pts(i, 2));
1004 }
1005 }
1006
1007 void GenericScalarProblem::exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
1008 {
1009 assert(has_exact_sol());
1010 const bool planar = pts.cols() == 2;
1011 val.resize(pts.rows(), 1);
1012
1013 for (int i = 0; i < pts.rows(); ++i)
1014 {
1015 double x = pts(i, 0), y = pts(i, 1), z = pts.cols() == 2 ? 0 : pts(i, 2);
1016 val(i) = exact_(x, y, z, t);
1017 }
1018 }
1019
1020 void GenericScalarProblem::exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const
1021 {
1022 val.resize(pts.rows(), pts.cols());
1023 if (!has_exact_grad_)
1024 return;
1025
1026 const bool planar = pts.cols() == 2;
1027 for (int i = 0; i < pts.rows(); ++i)
1028 {
1029 for (int j = 0; j < pts.cols(); ++j)
1030 {
1031 double x = pts(i, 0), y = pts(i, 1), z = pts.cols() == 2 ? 0 : pts(i, 2);
1032 val(i, j) = exact_grad_[j](x, y, z, t);
1033 }
1034 }
1035 }
1036
1037 void GenericTensorProblem::update_pressure_boundary(const int id, const int time_step, const double val)
1038 {
1039 int index = -1;
1040 for (int i = 0; i < pressure_boundary_ids_.size(); ++i)
1041 {
1042 if (pressure_boundary_ids_[i] == id)
1043 {
1044 index = i;
1045 break;
1046 }
1047 }
1048 if (index == -1)
1049 {
1050 throw "Invalid boundary id for pressure update";
1051 }
1052
1053 if (pressures_[index].value.is_mat())
1054 {
1055 Eigen::MatrixXd curr_val = pressures_[index].value.get_mat();
1056 assert(time_step <= curr_val.size());
1057 assert(curr_val.cols() == 1);
1058 curr_val(time_step) = val;
1059 pressures_[index].value.set_mat(curr_val);
1060 }
1061 else
1062 {
1063 pressures_[index].value.init(val);
1064 }
1065 }
1066
1067 void GenericTensorProblem::update_dirichlet_boundary(const int id, const int time_step, const Eigen::VectorXd &val)
1068 {
1069 int index = -1;
1070 for (int i = 0; i < boundary_ids_.size(); ++i)
1071 {
1072 if (boundary_ids_[i] == id)
1073 {
1074 index = i;
1075 break;
1076 }
1077 }
1078 if (index == -1)
1079 {
1080 throw "Invalid boundary id for dirichlet update";
1081 }
1082
1083 for (int i = 0; i < val.size(); ++i)
1084 {
1085 if (displacements_[index].value[i].is_mat())
1086 {
1087 Eigen::MatrixXd curr_val = displacements_[index].value[i].get_mat();
1088 assert(time_step <= curr_val.size());
1089 assert(curr_val.cols() == 1);
1090 curr_val(time_step) = val(i);
1091 displacements_[index].value[i].set_mat(curr_val);
1092 }
1093 else
1094 {
1095 displacements_[index].value[i].init(val(i));
1096 }
1097 }
1098 }
1099
1100 void GenericScalarProblem::dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val) const
1101 {
1102 val = Eigen::MatrixXd::Zero(1, 1);
1103 const int tag = mesh.get_node_id(node_id);
1104
1105 if (is_all_)
1106 {
1107 assert(nodal_dirichlet_.size() == 1);
1108 const auto &tmp = nodal_dirichlet_.begin()->second;
1109
1110 val(0) = tmp.eval(pt, t);
1111 return;
1112 }
1113
1114 const auto it = nodal_dirichlet_.find(tag);
1115 if (it != nodal_dirichlet_.end())
1116 {
1117 val(0) = it->second.eval(pt, t);
1118 return;
1119 }
1120
1121 for (const auto &n_dirichlet : nodal_dirichlet_mat_)
1122 {
1123 for (int i = 0; i < n_dirichlet.rows(); ++i)
1124 {
1125 if (n_dirichlet(i, 0) == node_id)
1126 {
1127 val(0) = n_dirichlet(i, 1);
1128 return;
1129 }
1130 }
1131 }
1132
1133 assert(false);
1134 }
1135
1136 void GenericScalarProblem::neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val) const
1137 {
1138 // TODO implement me;
1139 log_and_throw_error("Nodal neumann not implemented");
1140 }
1141
1142 bool GenericScalarProblem::is_nodal_dirichlet_boundary(const int n_id, const int tag)
1143 {
1144 if (nodal_dirichlet_.find(tag) != nodal_dirichlet_.end())
1145 return true;
1146
1147 for (const auto &n_dirichlet : nodal_dirichlet_mat_)
1148 {
1149 for (int i = 0; i < n_dirichlet.rows(); ++i)
1150 {
1151 if (n_dirichlet(i, 0) == n_id)
1152 return true;
1153 }
1154 }
1155
1156 return false;
1157 }
1158
1159 bool GenericScalarProblem::is_nodal_neumann_boundary(const int n_id, const int tag)
1160 {
1161 return nodal_neumann_.find(tag) != nodal_neumann_.end();
1162 }
1163
1165 {
1166 return nodal_dirichlet_mat_.size() > 0;
1167 }
1168
1170 {
1171 return false; // nodal_neumann_.size() > 0;
1172 }
1173
1174 void GenericScalarProblem::update_nodes(const Eigen::VectorXi &in_node_to_node)
1175 {
1176 for (auto &n_dirichlet : nodal_dirichlet_mat_)
1177 {
1178 for (int n = 0; n < n_dirichlet.rows(); ++n)
1179 {
1180 const int node_id = in_node_to_node[n_dirichlet(n, 0)];
1181 n_dirichlet(n, 0) = node_id;
1182 }
1183 }
1184 }
1185
1187 {
1188 if (is_param_valid(params, "is_time_dependent"))
1189 {
1190 is_time_dept_ = params["is_time_dependent"];
1191 }
1192
1193 if (is_param_valid(params, "rhs"))
1194 {
1195 rhs_.init(params["rhs"]);
1196 }
1197
1198 if (is_param_valid(params, "reference") && is_param_valid(params["reference"], "solution"))
1199 {
1200 has_exact_ = !params["reference"]["solution"].empty();
1201 exact_.init(params["reference"]["solution"]);
1202 }
1203
1204 if (is_param_valid(params, "reference") && is_param_valid(params["reference"], "gradient"))
1205 {
1206 auto ex = params["reference"]["gradient"];
1207 has_exact_grad_ = ex.size() > 0;
1208 if (ex.is_array())
1209 {
1210 for (size_t k = 0; k < ex.size(); ++k)
1211 exact_grad_[k].init(ex[k]);
1212 }
1213 else
1214 {
1215 assert(false);
1216 }
1217 }
1218
1219 if (is_param_valid(params, "dirichlet_boundary"))
1220 {
1221 // boundary_ids_.clear();
1222 const int offset = boundary_ids_.size();
1223 std::vector<json> j_boundary = flatten_ids(params["dirichlet_boundary"]);
1224
1225 boundary_ids_.resize(offset + j_boundary.size());
1226 dirichlet_.resize(offset + j_boundary.size());
1227
1228 for (size_t i = offset; i < boundary_ids_.size(); ++i)
1229 {
1230 if (j_boundary[i - offset].is_string())
1231 {
1232 const std::string path = resolve_path(j_boundary[i - offset], params["root_path"]);
1233 if (!std::filesystem::is_regular_file(path))
1234 log_and_throw_error(fmt::format("unable to open {} file", path));
1235
1236 Eigen::MatrixXd tmp;
1237 io::read_matrix(path, tmp);
1238 nodal_dirichlet_mat_.emplace_back(tmp);
1239
1240 continue;
1241 }
1242
1243 int current_id = -1;
1244
1245 if (j_boundary[i - offset]["id"] == "all")
1246 {
1247 assert(boundary_ids_.size() == 1);
1248
1249 is_all_ = true;
1250 boundary_ids_.clear();
1251 nodal_dirichlet_[current_id] = ScalarBCValue();
1252 }
1253 else
1254 {
1255 boundary_ids_[i] = j_boundary[i - offset]["id"];
1256 current_id = boundary_ids_[i];
1257 nodal_dirichlet_[current_id] = ScalarBCValue();
1258 }
1259
1260 auto ff = j_boundary[i - offset]["value"];
1261 dirichlet_[i].value.init(ff);
1262 nodal_dirichlet_[current_id].value.init(ff);
1263
1264 if (j_boundary[i - offset]["interpolation"].is_array())
1265 {
1266 if (j_boundary[i - offset]["interpolation"].size() == 0)
1267 dirichlet_[i].interpolation = std::make_shared<NoInterpolation>();
1268 else if (j_boundary[i - offset]["interpolation"].size() == 1)
1269 dirichlet_[i].interpolation = Interpolation::build(j_boundary[i - offset]["interpolation"][0]);
1270 else
1271 log_and_throw_error("Only one Dirichlet interpolation supported");
1272 }
1273 else
1274 dirichlet_[i].interpolation = Interpolation::build(j_boundary[i - offset]["interpolation"]);
1275
1276 nodal_dirichlet_[current_id].interpolation = dirichlet_[i].interpolation;
1277 }
1278 }
1279
1280 if (is_param_valid(params, "neumann_boundary"))
1281 {
1282 // neumann_boundary_ids_.clear();
1283 const int offset = neumann_boundary_ids_.size();
1284 auto j_boundary_tmp = params["neumann_boundary"];
1285 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
1286
1287 neumann_boundary_ids_.resize(offset + j_boundary.size());
1288 neumann_.resize(offset + j_boundary.size());
1289
1290 for (size_t i = offset; i < neumann_boundary_ids_.size(); ++i)
1291 {
1292 neumann_boundary_ids_[i] = j_boundary[i - offset]["id"];
1293
1294 auto ff = j_boundary[i - offset]["value"];
1295 neumann_[i].value.init(ff);
1296
1297 if (j_boundary[i - offset]["interpolation"].is_array())
1298 {
1299 if (j_boundary[i - offset]["interpolation"].size() == 0)
1300 neumann_[i].interpolation = std::make_shared<NoInterpolation>();
1301 else if (j_boundary[i - offset]["interpolation"].size() == 1)
1302 neumann_[i].interpolation = Interpolation::build(j_boundary[i - offset]["interpolation"][0]);
1303 else
1304 log_and_throw_error("Only one Neumann interpolation supported");
1305 }
1306 else
1307 neumann_[i].interpolation = Interpolation::build(j_boundary[i - offset]["interpolation"]);
1308 }
1309 }
1310
1311 if (is_param_valid(params, "solution"))
1312 {
1313 auto rr = params["solution"];
1314 initial_solution_.resize(rr.size());
1315 assert(rr.is_array());
1316
1317 for (size_t k = 0; k < rr.size(); ++k)
1318 {
1319 initial_solution_[k].first = rr[k]["id"];
1320 initial_solution_[k].second.init(rr[k]["value"]);
1321 }
1322 }
1323 }
1324
1326 {
1327 neumann_.clear();
1328 dirichlet_.clear();
1329
1330 nodal_dirichlet_.clear();
1331 nodal_neumann_.clear();
1332 nodal_dirichlet_mat_.clear();
1333
1334 rhs_.clear();
1335 exact_.clear();
1336 for (int i = 0; i < exact_grad_.size(); ++i)
1337 exact_grad_[i].clear();
1338 is_all_ = false;
1339 has_exact_ = false;
1340 has_exact_grad_ = false;
1341 is_time_dept_ = false;
1342 }
1343 } // namespace assembler
1344} // namespace polyfem
double val
Definition Assembler.cpp:86
int y
int z
int x
std::string force() const
Definition Units.hpp:29
std::string pressure() const
Definition Units.hpp:30
std::string velocity() const
Definition Units.hpp:27
std::string acceleration() const
Definition Units.hpp:28
const std::string & length() const
Definition Units.hpp:19
virtual bool is_fluid() const
bool is_nodal_neumann_boundary(const int n_id, const int tag) override
void dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
void initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const override
std::vector< std::pair< int, utils::ExpressionValue > > initial_solution_
void set_parameters(const json &params) override
void rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::vector< ScalarBCValue > neumann_
void update_nodes(const Eigen::VectorXi &in_node_to_node) override
bool is_nodal_dirichlet_boundary(const int n_id, const int tag) override
void dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val) const override
std::array< utils::ExpressionValue, 3 > exact_grad_
void exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::map< int, ScalarBCValue > nodal_dirichlet_
void set_units(const assembler::Assembler &assembler, const Units &units) override
GenericScalarProblem(const std::string &name)
std::map< int, ScalarBCValue > nodal_neumann_
void neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val) const override
void neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const override
std::vector< ScalarBCValue > dirichlet_
void exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::vector< Eigen::MatrixXd > nodal_dirichlet_mat_
void update_pressure_boundary(const int id, const int time_step, const double val)
std::map< int, TensorBCValue > nodal_neumann_
std::unordered_map< int, ScalarBCValue > cavity_pressures_
void neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const override
std::vector< std::pair< int, std::array< utils::ExpressionValue, 3 > > > initial_position_
void set_parameters(const json &params) override
void update_nodes(const Eigen::VectorXi &in_node_to_node) override
GenericTensorProblem(const std::string &name)
void initial_velocity(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const override
std::vector< std::pair< int, std::array< utils::ExpressionValue, 3 > > > initial_acceleration_
std::vector< std::pair< int, std::array< utils::ExpressionValue, 3 > > > initial_velocity_
std::vector< TensorBCValue > displacements_
std::vector< ScalarBCValue > normal_aligned_forces_
bool is_nodal_dirichlet_boundary(const int n_id, const int tag) override
void neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val) const override
void initial_acceleration(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const override
void pressure_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const override
bool is_dimension_dirichet(const int tag, const int dim) const override
void exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::map< int, TensorBCValue > nodal_dirichlet_
std::array< utils::ExpressionValue, 3 > rhs_
std::array< utils::ExpressionValue, 9 > exact_grad_
void update_dirichlet_boundary(const int id, const int time_step, const Eigen::VectorXd &val)
double pressure_cavity_bc(const int boundary_id, const double t) const override
void dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val) const override
void dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::vector< ScalarBCValue > pressures_
bool is_nodal_neumann_boundary(const int n_id, const int tag) override
void exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
bool is_nodal_dimension_dirichlet(const int n_id, const int tag, const int dim) const override
void set_units(const assembler::Assembler &assembler, const Units &units) override
void initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val) const override
void rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::array< utils::ExpressionValue, 3 > exact_
std::vector< Eigen::MatrixXd > nodal_dirichlet_mat_
std::vector< int > normal_aligned_neumann_boundary_ids_
Definition Problem.hpp:80
std::vector< int > pressure_boundary_ids_
Definition Problem.hpp:81
std::vector< int > boundary_ids_
Definition Problem.hpp:78
virtual void init(const mesh::Mesh &mesh)
Definition Problem.hpp:22
std::vector< int > neumann_boundary_ids_
Definition Problem.hpp:79
std::vector< int > pressure_cavity_ids_
Definition Problem.hpp:82
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:39
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
Definition Mesh.hpp:501
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
Definition Mesh.hpp:475
int dimension() const
utily for dimension
Definition Mesh.hpp:151
virtual int get_node_id(const int node_id) const
Get the boundary selection of a node.
Definition Mesh.hpp:484
void set_unit_type(const std::string &unit_type)
static std::shared_ptr< Interpolation > build(const json &params)
list tmp
Definition p_bases.py:339
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:18
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
bool is_param_valid(const json &params, const std::string &key)
Determine if a key exists and is non-null in a json object.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
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:71
std::shared_ptr< utils::Interpolation > interpolation
double eval(const RowVectorNd &pts, const double t) const
std::vector< std::shared_ptr< utils::Interpolation > > interpolation
std::array< utils::ExpressionValue, 3 > value
double eval(const RowVectorNd &pts, const int dim, const double t, const int el_id=-1) const