2#include <unsupported/Eigen/SparseExtra>
4#include <polysolve/linear/FEMSolver.hpp>
6#ifdef POLYFEM_WITH_OPENVDB
7#include <openvdb/openvdb.h>
12 using namespace assembler;
15 const std::vector<basis::ElementBases> &gbases,
16 const std::vector<basis::ElementBases> &bases,
17 const double &density_dx)
22 for (
int d = 0; d <
dim; d++)
33 const int shape,
const int n_el,
34 const std::vector<mesh::LocalBoundary> &local_boundary)
39 const int size = local_boundary.size();
41 for (
int e = 0; e < size; e++)
47 for (
int e = 0; e <
n_el; e++)
49 for (
int i = 0; i <
shape; i++)
55 for (
int i = 0; i <
V.rows(); i++)
57 auto p = mesh.
point(i);
58 for (
int d = 0; d <
dim; d++)
69 Eigen::MatrixXd p0, p1, p;
72 double avg_edge_length = p.rowwise().norm().mean();
74 long total_cell_num = 1;
76 for (
int d = 0; d <
dim; d++)
83 for (
int e = 0; e <
T.rows(); e++)
85 Eigen::VectorXd min_ =
V.row(
T(e, 0));
86 Eigen::VectorXd max_ = min_;
88 for (
int i = 1; i <
T.cols(); i++)
90 Eigen::VectorXd p =
V.row(
T(e, i));
91 min_ = min_.cwiseMin(p);
92 max_ = max_.cwiseMax(p);
95 Eigen::Matrix<long, Eigen::Dynamic, 1, Eigen::ColMajor, 3, 1> min_int(
dim), max_int(
dim);
97 for (
int d = 0; d <
dim; d++)
100 min_int(d) = floor((min_(d) * (1 - 1e-14) -
min_domain(d)) * temp);
101 max_int(d) = ceil((max_(d) * (1 + 1e-14) -
min_domain(d)) * temp);
103 min_int = min_int.cwiseMax(0);
107 for (
long x = min_int(0);
x < max_int(0);
x++)
109 for (
long y = min_int(1);
y < max_int(1);
y++)
118 for (
long z = min_int(2);
z < max_int(2);
z++)
128 float average_intersection_num = 0;
129 int max_intersection_num = 0;
132 average_intersection_num +=
hash_table[i].size();
133 (
hash_table[i].size() > max_intersection_num) ? (max_intersection_num =
hash_table[i].size()) : 1;
135 average_intersection_num /=
hash_table.size();
136 logger().debug(
"average intersection number for hash grid: {}", average_intersection_num);
137 logger().debug(
"max intersection number for hash grid: {}", max_intersection_num);
141 const int shape_,
const int n_el_,
142 const std::vector<mesh::LocalBoundary> &local_boundary,
143 const std::vector<int> &bnd_nodes)
154 const int shape,
const int n_el,
155 const std::vector<mesh::LocalBoundary> &local_boundary,
156 const std::vector<int> &bnd_nodes)
162 const int shape,
const int n_el,
163 const std::vector<mesh::LocalBoundary> &local_boundary,
164 const std::vector<int> &boundary_nodes_,
165 const std::vector<int> &pressure_boundary_nodes,
166 const std::vector<int> &bnd_nodes,
172 const double &viscosity_,
177 logger().info(
"Prefactorization begins...");
183 prefactorize(*
solver_mass, mat1, boundary_nodes_, mat1.rows(),
"");
186 mat_diffusion = mass + viscosity_ * dt * stiffness_viscosity;
195 if (pressure_boundary_nodes.size() == 0)
196 mat_projection.resize(stiffness_velocity.rows() + 1, stiffness_velocity.cols() + 1);
198 mat_projection.resize(stiffness_velocity.rows(), stiffness_velocity.cols());
200 std::vector<Eigen::Triplet<double>> coefficients;
201 coefficients.reserve(stiffness_velocity.nonZeros() + 2 * stiffness_velocity.rows());
203 for (
int i = 0; i < stiffness_velocity.outerSize(); i++)
205 for (StiffnessMatrix::InnerIterator it(stiffness_velocity, i); it; ++it)
207 coefficients.emplace_back(it.row(), it.col(), it.value());
211 if (pressure_boundary_nodes.size() == 0)
222 mat_projection.setFromTriplets(coefficients.begin(), coefficients.end());
228 prefactorize(*
solver_projection, mat2, pressure_boundary_nodes, mat2.rows(),
"");
230 logger().info(
"Prefactorization ends!");
236 int idx = -1, local_idx = -1;
238#ifdef POLYFEM_WITH_TBB
239 tbb::parallel_for(0, size, 1, [&](
int e)
241 for (
int e = 0; e < size; e++)
246 for (
int i = 0; i <
shape; i++)
249 for (
int d = 0; d <
dim; d++)
251 dist_ += pow(pos(d) -
V(
T(elem_idx, i), d), 2);
262#ifdef POLYFEM_WITH_TBB
265 for (
int d = 0; d <
dim; d++)
266 pos(d) =
V(
T(idx, local_idx), d);
271 const std::vector<basis::ElementBases> &bases,
276 Eigen::MatrixXd &local_pos,
277 const Eigen::MatrixXd &sol,
280 pos_2 = pos_1 - vel_1 * dt;
282 return interpolator(gbases, bases, pos_2, vel_2, local_pos, sol);
286 const std::vector<basis::ElementBases> &bases,
289 Eigen::MatrixXd &local_pos,
290 const Eigen::MatrixXd &sol)
292 bool insideDomain =
true;
295 if ((new_elem =
search_cell(gbases, pos, local_pos)) == -1)
297 insideDomain =
false;
304 vel = RowVectorNd::Zero(
dim);
306 vals.
compute(new_elem,
dim == 3, local_pos, bases[new_elem], gbases[new_elem]);
307 for (
int d = 0; d <
dim; d++)
309 for (
int i = 0; i <
vals.basis_values.size(); i++)
311 vel(d) +=
vals.basis_values[i].val(0) * sol(bases[new_elem].bases[i].global()[0].index *
dim + d);
324 Eigen::Matrix<long, Eigen::Dynamic, 1> int_pos(
dim);
325 Eigen::MatrixXd weights(2,
dim);
326 for (
int d = 0; d <
dim; d++)
332 weights(0, d) = 1 - weights(1, d);
335 for (
int d1 = 0; d1 < 2; d1++)
336 for (
int d2 = 0; d2 < 2; d2++)
340 const long idx = (int_pos(0) + d1) + (int_pos(1) + d2) * (
grid_cell_num(0) + 1);
341 val +=
density(idx) * weights(d1, 0) * weights(d2, 1);
345 for (
int d3 = 0; d3 < 2; d3++)
348 val +=
density(idx) * weights(d1, 0) * weights(d2, 1) * weights(d3, 2);
355 const std::vector<basis::ElementBases> &gbases,
356 const std::vector<basis::ElementBases> &bases,
357 Eigen::MatrixXd &sol,
359 const Eigen::MatrixXd &local_pts,
364 Eigen::MatrixXd
new_sol = Eigen::MatrixXd::Zero(sol.size(), 1);
366 const int n_vert = sol.size() /
dim;
367 Eigen::VectorXi traversed = Eigen::VectorXi::Zero(n_vert);
369#ifdef POLYFEM_WITH_TBB
370 tbb::parallel_for(0,
n_el, 1, [&](
int e)
372 for (
int e = 0; e <
n_el; ++e)
376 Eigen::MatrixXd mapped;
377 gbases[e].eval_geom_mapping(local_pts, mapped);
379 for (
int i = 0; i < local_pts.rows(); i++)
382 int global = bases[e].bases[i].global()[0].index;
384 if (traversed(global))
386 traversed(global) = 1;
393 for (
int d = 0; d <
dim; d++)
394 pos_(d) = mapped(i, d) - vel_(d) * dt;
396 Eigen::MatrixXd local_pos;
397 interpolator(gbases, bases, pos_, vel_, local_pos, sol);
402#ifdef POLYFEM_WITH_TBB
409 const std::vector<basis::ElementBases> &bases,
410 const std::shared_ptr<assembler::Problem> problem,
415 Eigen::VectorXd new_density = Eigen::VectorXd::Zero(
density.size());
417#ifdef POLYFEM_WITH_TBB
418 tbb::parallel_for(0, Nx + 1, 1, [&](
int i)
420 for (
int i = 0; i <= Nx; i++)
427 Eigen::MatrixXd pos(1,
dim);
432 Eigen::MatrixXd vel1, pos_;
433 problem->exact(pos, t, vel1);
436 Eigen::MatrixXd vel2, vel3;
437 problem->exact(pos - 0.5 * dt * vel1, t, vel2);
438 problem->exact(pos - 0.75 * dt * vel2, t, vel3);
439 pos_ = pos - (2 * vel1 + 3 * vel2 + 4 * vel3) * dt / 9;
443 pos_ = pos - vel1 * dt;
457 Eigen::MatrixXd vel1, pos_;
458 problem->exact(pos, t, vel1);
461 Eigen::MatrixXd vel2, vel3;
462 problem->exact(pos - 0.5 * dt * vel1, t, vel2);
463 problem->exact(pos - 0.75 * dt * vel2, t, vel3);
464 pos_ = pos - (2 * vel1 + 3 * vel2 + 4 * vel3) * dt / 9;
468 pos_ = pos - vel1 * dt;
475#ifdef POLYFEM_WITH_TBB
482 const std::vector<basis::ElementBases> &bases,
483 const Eigen::MatrixXd &sol,
487 Eigen::VectorXd new_density = Eigen::VectorXd::Zero(
density.size());
489#ifdef POLYFEM_WITH_TBB
490 tbb::parallel_for(0, Nx + 1, 1, [&](
int i)
492 for (
int i = 0; i <= Nx; i++)
497 Eigen::MatrixXd local_pos;
510 interpolator(gbases, bases, pos - 0.5 * dt * vel1, vel2, local_pos, sol);
511 interpolator(gbases, bases, pos - 0.75 * dt * vel2, vel3, local_pos, sol);
512 pos_ = pos - (2 * vel1 + 3 * vel2 + 4 * vel3) * dt / 9;
516 pos_ = pos - vel1 * dt;
535 interpolator(gbases, bases, pos - 0.5 * dt * vel1, vel2, local_pos, sol);
536 interpolator(gbases, bases, pos - 0.75 * dt * vel2, vel3, local_pos, sol);
537 pos_ = pos - (2 * vel1 + 3 * vel2 + 4 * vel3) * dt / 9;
541 pos_ = pos - vel1 * dt;
548#ifdef POLYFEM_WITH_TBB
556 const int ppe =
shape;
557 const double FLIPRatio = 1;
565#ifdef POLYFEM_WITH_TBB
566 tbb::parallel_for(0,
n_el, 1, [&](
int e)
568 for (
int e = 0; e <
n_el; ++e)
572 Eigen::MatrixXd local_pts_particle;
573 local_pts_particle.setRandom(ppe,
dim);
574 local_pts_particle.array() += 1;
575 local_pts_particle.array() /= 2;
576 for (
int ppeI = 0; ppeI < ppe; ++ppeI)
578 if (
shape == 3 &&
dim == 2 && local_pts_particle.row(ppeI).sum() > 1)
580 double x = 1 - local_pts_particle(ppeI, 1);
581 local_pts_particle(ppeI, 1) = 1 - local_pts_particle(ppeI, 0);
582 local_pts_particle(ppeI, 0) = x;
587 for (
int i = 0; i <
shape; ++i)
592 Eigen::MatrixXd mapped;
593 gbases[e].eval_geom_mapping(local_pts_particle, mapped);
596 vals.
compute(e,
dim == 3, local_pts_particle, bases[e], gbases[e]);
597 for (
int j = 0; j < ppe; ++j)
600 for (
int d = 0; d <
dim; d++)
606 for (
int i = 0; i <
vals.basis_values.size(); ++i)
608 velocity_particle[e * ppe + j] +=
vals.basis_values[i].val(j) * sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1).transpose();
612#ifdef POLYFEM_WITH_TBB
620 std::vector<int> counter(
n_el, 0);
621 std::vector<int> redundantPI;
627 redundantPI.emplace_back(pI);
628 isRedundant[pI] =
true;
635 redundantPI.emplace_back(pI);
636 isRedundant[pI] =
true;
641#ifdef POLYFEM_WITH_TBB
647 if (!isRedundant[pI])
650 Eigen::MatrixXd local_pts_particle;
654 vals.
compute(e,
dim == 3, local_pts_particle, bases[e], gbases[e]);
656 FLIPdVel.setZero(1,
dim);
657 PICVel.setZero(1,
dim);
658 for (
int i = 0; i <
vals.basis_values.size(); ++i)
660 FLIPdVel +=
vals.basis_values[i].val(0) * (sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1) -
new_sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1)).transpose();
661 PICVel +=
vals.basis_values[i].val(0) * sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1).transpose();
666#ifdef POLYFEM_WITH_TBB
670 for (
int e = 0; e <
n_el; ++e)
672 if (counter[e] >= ppe)
677 while (counter[e] < ppe)
679 int pI = redundantPI.back();
680 redundantPI.pop_back();
685 Eigen::MatrixXd local_pts_particle;
686 local_pts_particle.setRandom(1,
dim);
687 local_pts_particle.array() += 1;
688 local_pts_particle.array() /= 2;
689 if (
shape == 3 &&
dim == 2 && local_pts_particle.sum() > 1)
691 double x = 1 - local_pts_particle(0, 1);
692 local_pts_particle(0, 1) = 1 - local_pts_particle(0, 0);
693 local_pts_particle(0, 0) =
x;
699 Eigen::MatrixXd mapped;
700 gbases[e].eval_geom_mapping(local_pts_particle, mapped);
701 for (
int d = 0; d <
dim; d++)
706 vals.
compute(e,
dim == 3, local_pts_particle, bases[e], gbases[e]);
708 for (
int i = 0; i <
vals.basis_values.size(); ++i)
710 velocity_particle[pI] +=
vals.basis_values[i].val(0) * sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1).transpose();
719 std::vector<assembler::ElementAssemblyValues> velocity_interpolator(ppe *
n_el);
720#ifdef POLYFEM_WITH_TBB
721 tbb::parallel_for(0, (
int)(ppe *
n_el), 1, [&](
int pI)
723 for (
int pI = 0; pI < ppe *
n_el; ++pI)
728 Eigen::MatrixXd local_pos;
750#ifdef POLYFEM_WITH_TBB
755 new_sol = Eigen::MatrixXd::Zero(sol.size(), 1);
758 for (
int pI = 0; pI < ppe *
n_el; ++pI)
766 for (
int i = 0; i <
vals.basis_values.size(); ++i)
768 new_sol.block(bases[cellI].bases[i].global()[0].index *
dim, 0,
dim, 1) +=
770 new_sol_w(bases[cellI].bases[i].global()[0].index) +=
vals.basis_values[i].val(0);
775#ifdef POLYFEM_WITH_TBB
776 tbb::parallel_for(0, (
int)
new_sol.rows() /
dim, 1, [&](
int i)
778 for (
int i = 0; i <
new_sol.rows() /
dim; ++i)
784#ifdef POLYFEM_WITH_TBB
789 void OperatorSplittingSolver::advection_PIC(
const mesh::Mesh &mesh,
const std::vector<basis::ElementBases> &gbases,
const std::vector<basis::ElementBases> &bases, Eigen::MatrixXd &sol,
const double dt,
const Eigen::MatrixXd &local_pts,
const int order)
792 Eigen::MatrixXd
new_sol = Eigen::MatrixXd::Zero(sol.size(), 1);
793 Eigen::MatrixXd
new_sol_w = Eigen::MatrixXd::Zero(sol.size() /
dim, 1);
796 const int ppe =
shape;
797 std::vector<assembler::ElementAssemblyValues> velocity_interpolator(ppe *
n_el);
801#ifdef POLYFEM_WITH_TBB
802 tbb::parallel_for(0,
n_el, 1, [&](
int e)
804 for (
int e = 0; e <
n_el; ++e)
808 Eigen::MatrixXd local_pts_particle;
809 local_pts_particle.setRandom(ppe,
dim);
810 local_pts_particle.array() += 1;
811 local_pts_particle.array() /= 2;
814 std::vector<RowVectorNd> vert(
shape);
815 for (
int i = 0; i <
shape; ++i)
825 for (
int i = 0; i < ppe; ++i)
828 for (
int j = 0; j <
shape; ++j)
836 vals.
compute(e,
dim == 3, local_pts_particle, bases[e], gbases[e]);
837 for (
int j = 0; j < ppe; ++j)
840 for (
int i = 0; i <
vals.basis_values.size(); ++i)
842 velocity_particle[e * ppe + j] +=
vals.basis_values[i].val(j) * sol.block(bases[e].bases[i].global()[0].index *
dim, 0,
dim, 1).transpose();
847 for (
int j = 0; j < ppe; ++j)
850 Eigen::MatrixXd local_pos;
868 velocity_interpolator[ppe * e + j].compute(
cellI_particle[ppe * e + j],
dim == 3, local_pos,
873#ifdef POLYFEM_WITH_TBB
878 for (
int e = 0; e <
n_el; ++e)
880 for (
int j = 0; j < ppe; ++j)
888 for (
int i = 0; i <
vals.basis_values.size(); ++i)
890 new_sol.block(bases[cellI].bases[i].global()[0].index *
dim, 0,
dim, 1) +=
892 new_sol_w(bases[cellI].bases[i].global()[0].index) +=
vals.basis_values[i].val(0);
898#ifdef POLYFEM_WITH_TBB
899 tbb::parallel_for(0, (
int)
new_sol.rows() /
dim, 1, [&](
int i)
901 for (
int i = 0; i <
new_sol.rows() /
dim; ++i)
906#ifdef POLYFEM_WITH_TBB
916 for (
int d = 0; d <
dim; d++)
918 Eigen::VectorXd
x(sol.size() /
dim);
919 for (
int j = 0; j <
x.size(); j++)
921 x(j) = sol(j *
dim + d);
926 for (
int i = 0; i < bnd_nodes.size(); i++)
928 rhs(bnd_nodes[i]) =
x(bnd_nodes[i]);
940 for (
int j = 0; j <
x.size(); j++)
942 sol(j *
dim + d) =
x(j);
949 const std::vector<basis::ElementBases> &gbases,
950 const std::vector<basis::ElementBases> &bases,
952 Eigen::MatrixXd &sol,
953 const Eigen::MatrixXd &local_pts,
954 const std::shared_ptr<assembler::Problem> problem,
957#ifdef POLYFEM_WITH_TBB
958 tbb::parallel_for(0,
n_el, 1, [&](
int e)
960 for (
int e = 0; e <
n_el; e++)
963 Eigen::MatrixXd mapped;
964 gbases[e].eval_geom_mapping(local_pts, mapped);
966 for (
int local_idx = 0; local_idx < bases[e].bases.size(); local_idx++)
968 int global_idx = bases[e].bases[local_idx].global()[0].index;
970 Eigen::MatrixXd pos = Eigen::MatrixXd::Zero(1,
dim);
971 for (
int d = 0; d <
dim; d++)
972 pos(0, d) = mapped(local_idx, d);
975 problem->rhs(assembler, pos, time,
val);
977 for (
int d = 0; d <
dim; d++)
979 sol(global_idx *
dim + d) +=
val(d) * dt;
983#ifdef POLYFEM_WITH_TBB
991 if (pressure_boundary_nodes.size() == 0)
992 rhs = Eigen::VectorXd::Zero(mixed_stiffness.rows() + 1);
994 rhs = Eigen::VectorXd::Zero(mixed_stiffness.rows());
996 Eigen::VectorXd temp = mixed_stiffness * sol;
997 for (
int i = 0; i < temp.rows(); i++)
1002 Eigen::VectorXd
x = Eigen::VectorXd::Zero(rhs.size());
1003 for (
int i = 0; i < pressure.size(); i++)
1008 for (
int i = 0; i < pressure_boundary_nodes.size(); i++)
1010 rhs(pressure_boundary_nodes[i]) = 0;
1011 x(pressure_boundary_nodes[i]) = 0;
1022 if (pressure_boundary_nodes.size() == 0)
1023 pressure =
x.head(
x.size() - 1);
1030 Eigen::VectorXd rhs = mixed_stiffness.transpose() * pressure;
1031 Eigen::VectorXd dx = Eigen::VectorXd::Zero(sol.size());
1033 for (
int i = 0; i < boundary_nodes_.size(); i++)
1035 rhs(boundary_nodes_[i]) = 0;
1040 dirichlet_solve_prefactorized(*
solver_mass, velocity_mass, rhs, boundary_nodes_, dx);
1044 auto mat = velocity_mass;
1045 dirichlet_solve(*
solver_mass, mat, rhs, boundary_nodes_, dx, velocity_mass.rows(),
"",
false,
false,
false);
1052 const std::vector<basis::ElementBases> &gbases,
1053 const std::vector<basis::ElementBases> &bases,
1054 const std::vector<basis::ElementBases> &pressure_bases,
1055 const Eigen::MatrixXd &local_pts,
1056 Eigen::MatrixXd &pressure,
1057 Eigen::MatrixXd &sol)
1059 Eigen::VectorXd grad_pressure = Eigen::VectorXd::Zero(n_bases *
dim);
1060 Eigen::VectorXi traversed = Eigen::VectorXi::Zero(n_bases);
1063 for (
int e = 0; e <
n_el; ++e)
1065 vals.
compute(e,
dim == 3, local_pts, pressure_bases[e], gbases[e]);
1066 for (
int j = 0; j < local_pts.rows(); j++)
1068 int global_ = bases[e].bases[j].global()[0].index;
1069 for (
int i = 0; i <
vals.basis_values.size(); i++)
1071 for (
int d = 0; d <
dim; d++)
1073 assert(pressure_bases[e].bases[i].global().size() == 1);
1074 grad_pressure(global_ *
dim + d) +=
vals.basis_values[i].grad_t_m(j, d) * pressure(pressure_bases[e].bases[i].global()[0].index);
1077 traversed(global_)++;
1080 for (
int i = 0; i < traversed.size(); i++)
1082 for (
int d = 0; d <
dim; d++)
1084 sol(i *
dim + d) -= grad_pressure(i *
dim + d) / traversed(i);
1091 Eigen::MatrixXd pts(1,
dim);
1092 Eigen::MatrixXd tmp;
1102 problem->initial_density(pts, tmp);
1111 problem->initial_density(pts, tmp);
1121 Eigen::Matrix<long, Eigen::Dynamic, 1> pos_int(
dim);
1122 for (
int d = 0; d <
dim; d++)
1131 long idx = 0, dim_num = 1;
1132 for (
int d = 0; d <
dim; d++)
1134 idx += pos_int(d) * dim_num;
1138 const std::vector<long> &list =
hash_table[idx];
1139 for (
auto it = list.begin(); it != list.end(); it++)
1145 if (local_pts.minCoeff() > -1e-13 && local_pts.sum() < 1 + 1e-13)
1150 if (local_pts.minCoeff() > -1e-13 && local_pts.maxCoeff() < 1 + 1e-13)
1159 double a = (vert[1](0) - vert[0](0)) * (pos(1) - vert[0](1)) - (vert[1](1) - vert[0](1)) * (pos(0) - vert[0](0));
1160 double b = (vert[2](0) - vert[1](0)) * (pos(1) - vert[1](1)) - (vert[2](1) - vert[1](1)) * (pos(0) - vert[1](0));
1161 double c = (vert[3](0) - vert[2](0)) * (pos(1) - vert[2](1)) - (vert[3](1) - vert[2](1)) * (pos(0) - vert[2](0));
1162 double d = (vert[0](0) - vert[3](0)) * (pos(1) - vert[3](1)) - (vert[0](1) - vert[3](1)) * (pos(0) - vert[3](0));
1164 if ((a > 0 && b > 0 && c > 0 && d > 0) || (a < 0 && b < 0 && c < 0 && d < 0))
1171 pos = Eigen::MatrixXd::Zero(1,
dim);
1172 Eigen::VectorXd weights(
shape);
1173 const double x = local_pos(0);
1174 const double y = local_pos(1);
1179 weights << 1 -
x -
y,
x,
y;
1183 weights << (1 -
x) * (1 -
y),
x * (1 -
y),
1189 const double z = local_pos(2);
1192 weights << 1 -
x -
y -
z,
x,
y,
z;
1196 weights << (1 -
x) * (1 -
y) * (1 -
z),
1197 x * (1 -
y) * (1 -
z),
1199 (1 -
x) *
y * (1 -
z),
1200 (1 -
x) * (1 -
y) *
z,
1207 for (
int d = 0; d <
dim; d++)
1209 for (
int j = 0; j <
shape; j++)
1211 pos(d) +=
V(
T(elem_idx, j), d) * weights(j);
1218 jacobi = Eigen::MatrixXd::Zero(
dim,
dim);
1219 Eigen::MatrixXd weights(
shape,
dim);
1220 const double x = local_pos(0);
1221 const double y = local_pos(1);
1232 weights <<
y - 1,
x - 1,
1240 const double z = local_pos(2);
1243 weights << -1, -1, -1,
1250 weights << -(1 -
y) * (1 -
z), -(1 -
x) * (1 -
z), -(1 -
x) * (1 -
y),
1251 (1 -
y) * (1 -
z), -
x * (1 -
z), -
x * (1 -
y),
1252 y * (1 -
z),
x * (1 -
z), -
x *
y,
1253 -
y * (1 -
z), (1 -
x) * (1 -
z), -(1 -
x) *
y,
1254 -(1 -
y) *
z, -(1 -
x) *
z, (1 -
x) * (1 -
y),
1255 (1 -
y) *
z, -
x *
z,
x * (1 -
y),
1257 -
y *
z, (1 -
x) *
z, (1 -
x) *
y;
1261 for (
int d1 = 0; d1 <
dim; d1++)
1263 for (
int d2 = 0; d2 <
dim; d2++)
1265 for (
int i = 0; i <
shape; i++)
1267 jacobi(d1, d2) += weights(i, d2) *
V(
T(elem_idx, i), d1);
1276 Eigen::MatrixXd &local_pos)
1278 local_pos = Eigen::MatrixXd::Zero(1,
dim);
1285 Eigen::MatrixXd res;
1292 Eigen::MatrixXd mapped;
1294 for (
int d = 0; d <
dim; d++)
1295 res(d) += mapped(0, d);
1297 std::vector<Eigen::MatrixXd> grads;
1299 Eigen::MatrixXd jacobi = grads[0].transpose();
1301 Eigen::VectorXd delta = jacobi.colPivHouseholderQr().solve(res.transpose());
1302 for (
int d = 0; d <
dim; d++)
1304 local_pos(d) -= delta(d);
1309 }
while (res.norm() > 1e-12 && iter_times < max_iter);
1311 if (iter_times >= max_iter)
1313 for (
int d = 0; d <
dim; d++)
1320#ifdef POLYFEM_WITH_OPENVDB
1321 openvdb::initialize();
1322 openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create();
1323 openvdb::FloatGrid::Accessor accessor = grid->getAccessor();
1332 openvdb::Coord xyz(i, j, 0);
1334 accessor.setValue(xyz,
density(idx));
1341 openvdb::Coord xyz(i, j, k);
1343 accessor.setValue(xyz,
density(idx));
1348 grid->setName(
"density_smoke");
1349 grid->setGridClass(openvdb::GRID_FOG_VOLUME);
1351 static int num_frame = 0;
1352 const std::string filename =
"density" + std::to_string(num_frame) +
".vdb";
1353 openvdb::io::File file(filename.c_str());
1356 openvdb::GridPtrVec(grids);
1357 grids.push_back(grid);
1361 static int num_frame = 0;
1362 std::string name =
"density" + std::to_string(num_frame) +
".txt";
1363 std::ofstream file(name.c_str());
1374 file << i <<
" " << j <<
" " <<
density(idx) << std::endl;
1383 file << i <<
" " << j <<
" " << k <<
" " <<
density(idx) << std::endl;
ElementAssemblyValues vals
assembler::ElementAssemblyValues gvals
stores per element basis values at given quadrature points and geometric mapping
std::vector< AssemblyValues > basis_values
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
void eval_geom_mapping(const Eigen::MatrixXd &samples, Eigen::MatrixXd &mapped) const
Map the sample positions in the parametric domain to the object domain (if the element has no paramet...
void eval_geom_mapping_grads(const Eigen::MatrixXd &samples, std::vector< Eigen::MatrixXd > &grads) const
Evaluate the gradients of the geometric mapping defined above.
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
virtual int n_vertices() const =0
number of vertices
virtual void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const =0
Get all the edges.
virtual void bounding_box(RowVectorNd &min, RowVectorNd &max) const =0
computes the bbox of the mesh
virtual RowVectorNd point(const int global_index) const =0
point coordinates
int dimension() const
utily for dimension
virtual int cell_vertex(const int f_id, const int lv_id) const =0
id of the vertex of a cell
void initialize_mesh(const mesh::Mesh &mesh, const int shape, const int n_el, const std::vector< mesh::LocalBoundary > &local_boundary)
Eigen::MatrixXd new_sol_w
OperatorSplittingSolver()
std::vector< int > cellI_particle
void solve_pressure(const StiffnessMatrix &mixed_stiffness, const std::vector< int > &pressure_boundary_nodes, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
StiffnessMatrix mat_projection
void projection(const StiffnessMatrix &velocity_mass, const StiffnessMatrix &mixed_stiffness, const std::vector< int > &boundary_nodes_, Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
int interpolator(const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const RowVectorNd &pos, RowVectorNd &vel, Eigen::MatrixXd &local_pos, const Eigen::MatrixXd &sol)
void compute_gbase_val(const int elem_idx, const Eigen::MatrixXd &local_pos, Eigen::MatrixXd &pos)
void external_force(const mesh::Mesh &mesh, const assembler::Assembler &assembler, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const double dt, Eigen::MatrixXd &sol, const Eigen::MatrixXd &local_pts, const std::shared_ptr< assembler::Problem > problem, const double time)
std::unique_ptr< polysolve::linear::Solver > solver_diffusion
void advection(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, Eigen::MatrixXd &sol, const double dt, const Eigen::MatrixXd &local_pts, const int order=1, const int RK=1)
void initialize_density(const std::shared_ptr< assembler::Problem > &problem)
void advection_PIC(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, Eigen::MatrixXd &sol, const double dt, const Eigen::MatrixXd &local_pts, const int order=1)
std::vector< Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > > position_particle
long search_cell(const std::vector< basis::ElementBases > &gbases, const RowVectorNd &pos, Eigen::MatrixXd &local_pts)
std::vector< int > boundary_elem_id
std::vector< std::vector< long > > hash_table
int trace_back(const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const RowVectorNd &pos_1, const RowVectorNd &vel_1, RowVectorNd &pos_2, RowVectorNd &vel_2, Eigen::MatrixXd &local_pos, const Eigen::MatrixXd &sol, const double dt)
void advect_density(const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const Eigen::MatrixXd &sol, const double dt, const int RK=3)
void advection_FLIP(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, Eigen::MatrixXd &sol, const double dt, const Eigen::MatrixXd &local_pts, const int order=1)
std::vector< int > boundary_nodes
bool outside_quad(const std::vector< RowVectorNd > &vert, const RowVectorNd &pos)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > grid_cell_num
Eigen::Matrix< long, Eigen::Dynamic, 1, Eigen::ColMajor, 3, 1 > hash_table_cell_num
StiffnessMatrix mat_diffusion
std::unique_ptr< polysolve::linear::Solver > solver_projection
std::vector< Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > > velocity_particle
void calculate_local_pts(const basis::ElementBases &gbase, const int elem_idx, const RowVectorNd &pos, Eigen::MatrixXd &local_pos)
std::unique_ptr< polysolve::linear::Solver > solver_mass
int handle_boundary_advection(RowVectorNd &pos)
void compute_gbase_jacobi(const int elem_idx, const Eigen::MatrixXd &local_pos, Eigen::MatrixXd &jacobi)
void advect_density_exact(const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const std::shared_ptr< assembler::Problem > problem, const double t, const double dt, const int RK=3)
void initialize_solver(const mesh::Mesh &mesh, const int shape_, const int n_el_, const std::vector< mesh::LocalBoundary > &local_boundary, const std::vector< int > &bnd_nodes)
void solve_diffusion_1st(const StiffnessMatrix &mass, const std::vector< int > &bnd_nodes, Eigen::MatrixXd &sol)
void initialize_grid(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const double &density_dx)
void initialize_hashtable(const mesh::Mesh &mesh)
spdlog::logger & logger()
Retrieves the current logger.
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix