9#include <ipc/utils/eigen_ext.hpp>
16 using namespace basis;
18 using namespace utils;
22 class LocalThreadMatStorage
25 std::unique_ptr<MatrixCache>
cache =
nullptr;
26 ElementAssemblyValues
vals;
29 LocalThreadMatStorage() =
delete;
31 LocalThreadMatStorage(
const int buffer_size,
const int rows,
const int cols)
33 init(buffer_size, rows, cols);
36 LocalThreadMatStorage(
const int buffer_size,
const MatrixCache &c)
41 LocalThreadMatStorage(
const LocalThreadMatStorage &other)
46 LocalThreadMatStorage &operator=(
const LocalThreadMatStorage &other)
48 assert(other.cache !=
nullptr);
49 cache = other.cache->copy();
55 void init(
const int buffer_size,
const int rows,
const int cols)
59 cache = std::make_unique<SparseMatrixCache>();
60 cache->reserve(buffer_size);
61 cache->init(rows, cols);
64 void init(
const int buffer_size,
const MatrixCache &c)
68 cache->reserve(buffer_size);
73 class LocalThreadVecStorage
77 ElementAssemblyValues
vals;
80 LocalThreadVecStorage(
const int size)
87 class LocalThreadScalarStorage
91 ElementAssemblyValues
vals;
94 LocalThreadScalarStorage()
100 void split_mixed_solution(
102 const Eigen::MatrixXd &
x,
105 Eigen::MatrixXd &x_phi,
106 Eigen::MatrixXd &x_psi)
108 assert(split_solution);
110 split_solution(
x, x_phi, x_psi);
112 assert(x_phi.rows() == phi_ndof);
113 assert(x_phi.cols() == 1);
114 assert(x_psi.rows() == psi_ndof);
115 assert(x_psi.cols() == 1);
118 void split_mixed_previous_solution(
120 const Eigen::MatrixXd &
x,
123 Eigen::MatrixXd &x_phi,
124 Eigen::MatrixXd &x_psi)
133 split_mixed_solution(split_solution,
x, phi_ndof, psi_ndof, x_phi, x_psi);
136 void compute_mixed_element_values(
138 const bool is_volume,
139 const ElementBases &psi_basis,
140 const ElementBases &phi_basis,
141 const ElementBases &gbasis,
142 const AssemblyValsCache &psi_cache,
143 const AssemblyValsCache &phi_cache,
144 ElementAssemblyValues &psi_vals,
145 ElementAssemblyValues &phi_vals)
147 psi_cache.compute(el_index, is_volume, psi_basis, gbasis, psi_vals);
148 phi_cache.compute(el_index, is_volume, phi_basis, gbasis, phi_vals);
150 const auto same_quadrature = [&]() {
151 if (psi_vals.quadrature.weights.size() != phi_vals.quadrature.weights.size())
153 if (psi_vals.quadrature.points.rows() != phi_vals.quadrature.points.rows()
154 || psi_vals.quadrature.points.cols() != phi_vals.quadrature.points.cols())
156 return (psi_vals.quadrature.points - phi_vals.quadrature.points).cwiseAbs().maxCoeff() < 1
e-14;
159 if (same_quadrature())
162 if (phi_vals.quadrature.weights.size() >= psi_vals.quadrature.weights.size())
164 const Quadrature
quadrature = phi_vals.quadrature;
165 psi_vals.compute(el_index, is_volume,
quadrature.
points, psi_basis, gbasis);
170 const Quadrature
quadrature = psi_vals.quadrature;
171 phi_vals.compute(el_index, is_volume,
quadrature.
points, phi_basis, gbasis);
175 assert(psi_vals.quadrature.weights.size() == phi_vals.quadrature.weights.size());
176 assert(psi_vals.quadrature.points.rows() == phi_vals.quadrature.points.rows());
182 if (!body_params.is_array())
188 std::map<int, json> materials;
189 for (
int i = 0; i < body_params.size(); ++i)
191 json mat = body_params[i];
195 for (
int j = 0; j <
id.size(); ++j)
196 materials[
id[j]] = mat;
201 materials[mid] = mat;
205 std::set<int> missing;
207 std::map<int, int> body_element_count;
208 std::vector<int> eid_to_eid_in_body(body_ids.size());
209 for (
int e = 0; e < body_ids.size(); ++e)
211 const int bid = body_ids[e];
212 body_element_count.try_emplace(bid, 0);
213 eid_to_eid_in_body[e] = body_element_count[bid]++;
216 for (
int e = 0; e < body_ids.size(); ++e)
218 const int bid = body_ids[e];
219 const auto it = materials.find(bid);
220 if (it == materials.end())
226 json tmp = it->second;
231 for (
int bid : missing)
233 logger().warn(
"Missing material parameters for body {}", bid);
242 const bool is_volume,
244 const std::vector<ElementBases> &bases,
245 const std::vector<ElementBases> &gbases,
249 const bool is_mass)
const
253 const long int max_triplets_size = long(1e7);
254 const long int buffer_size = std::min(
long(max_triplets_size),
long(n_basis) *
size());
261 stiffness.resize(n_basis *
size(), n_basis *
size());
264 auto storage =
create_thread_storage(LocalThreadMatStorage(buffer_size, stiffness.rows(), stiffness.cols()));
266 const int n_bases = int(bases.size());
269 assert(
cache.is_mass() == is_mass);
277 for (
int e = start; e < end; ++e)
285 cache.compute(e, is_volume, bases[e], gbases[e],
vals);
289 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
291 const int n_loc_bases = int(
vals.basis_values.size());
293 for (
int i = 0; i < n_loc_bases; ++i)
297 const auto &global_i =
vals.basis_values[i].global;
300 for (
int j = 0; j <= i; ++j)
304 const auto &global_j =
vals.basis_values[j].global;
308 assert(stiffness_val.size() ==
size() *
size());
312 for (
int n = 0; n <
size(); ++n)
314 for (
int m = 0; m <
size(); ++m)
316 const double local_value = stiffness_val(n *
size() + m);
319 for (
size_t ii = 0; ii < global_i.size(); ++ii)
321 const auto gi = global_i[ii].index *
size() + m;
322 const auto wi = global_i[ii].val;
324 for (
size_t jj = 0; jj < global_j.size(); ++jj)
326 const auto gj = global_j[jj].index *
size() + n;
327 const auto wj = global_j[jj].val;
330 local_storage.cache->add_value(e, gi, gj, local_value * wi * wj);
333 local_storage.cache->add_value(e, gj, gi, local_value * wj * wi);
336 if (local_storage.cache->entries_size() >= max_triplets_size)
338 local_storage.cache->prune();
339 logger().trace(
"cleaning memory. Current storage: {}. mat nnz: {}", local_storage.cache->capacity(), local_storage.cache->non_zeros());
357 logger().trace(
"done separate assembly {}s...", timer.getElapsedTime());
362 std::vector<LocalThreadMatStorage *> storages(storage.size());
364 for (
auto &local_storage : storage)
366 storages[index++] = &local_storage;
371 storages[i]->cache->prune();
374 logger().trace(
"done pruning triplets {}s...", timer.getElapsedTime());
377 std::vector<long int> offsets(storage.size());
380 long int triplet_count = 0;
381 for (
auto &local_storage : storage)
383 offsets[index++] = triplet_count;
384 triplet_count += local_storage.cache->triplet_count();
387 std::vector<Eigen::Triplet<double>> triplets;
389 assert(storages.size() >= 1);
390 if (storages[0]->
cache->is_dense())
394 Eigen::MatrixXd tmp(stiffness);
395 for (
const LocalThreadMatStorage &local_storage : storage)
397 stiffness = tmp.sparseView();
398 stiffness.makeCompressed();
401 logger().trace(
"Serial assembly time: {}s...", timer.getElapsedTime());
403 else if (triplet_count >= triplets.max_size())
407 logger().warn(
"Cannot allocate space for triplets, switching to serial assembly.");
411 for (LocalThreadMatStorage &local_storage : storage)
412 stiffness += local_storage.
cache->get_matrix(false);
413 stiffness.makeCompressed();
416 logger().trace(
"Serial assembly time: {}s...", timer.getElapsedTime());
421 triplets.resize(triplet_count);
424 logger().trace(
"done allocate triplets {}s...", timer.getElapsedTime());
425 logger().trace(
"Triplets Count: {}", triplet_count);
430 const SparseMatrixCache &cache = dynamic_cast<const SparseMatrixCache &>(*storages[i]->cache);
431 long int offset = offsets[i];
433 std::copy(cache.entries().begin(), cache.entries().end(), triplets.begin() + offset);
434 offset += cache.entries().size();
436 if (cache.mat().nonZeros() > 0)
439 for (int k = 0; k < cache.mat().outerSize(); ++k)
441 for (Eigen::SparseMatrix<double>::InnerIterator it(cache.mat(), k); it; ++it)
443 assert(count < cache.mat().nonZeros());
444 triplets[offset + count++] = Eigen::Triplet<double>(it.row(), it.col(), it.value());
451 logger().trace(
"done concatenate triplets {}s...", timer.getElapsedTime());
455 stiffness.setFromTriplets(triplets.begin(), triplets.end());
458 logger().trace(
"done setFromTriplets assembly {}s...", timer.getElapsedTime());
461 catch (std::bad_alloc &ba)
475 const bool is_volume,
476 const int n_psi_basis,
477 const int n_phi_basis,
478 const std::vector<ElementBases> &psi_bases,
479 const std::vector<ElementBases> &phi_bases,
480 const std::vector<ElementBases> &gbases,
487 assert(phi_bases.size() == psi_bases.size());
489 const int max_triplets_size = int(1e7);
490 const int buffer_size = std::min(
long(max_triplets_size),
long(std::max(n_psi_basis, n_phi_basis)) * std::max(
rows(),
cols()));
493 stiffness.resize(n_phi_basis *
rows(), n_psi_basis *
cols());
496 auto storage =
create_thread_storage(LocalThreadMatStorage(buffer_size, stiffness.rows(), stiffness.cols()));
498 const int n_bases = int(phi_bases.size());
506 for (
int e = start; e < end; ++e)
510 psi_cache.
compute(e, is_volume, psi_bases[e], gbases[e], psi_vals);
511 phi_cache.
compute(e, is_volume, phi_bases[e], gbases[e], phi_vals);
515 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
516 local_storage.da = phi_vals.
det.array() *
quadrature.weights.array();
517 const int n_phi_loc_bases = int(phi_vals.
basis_values.size());
518 const int n_psi_loc_bases = int(psi_vals.
basis_values.size());
520 for (
int i = 0; i < n_psi_loc_bases; ++i)
524 for (
int j = 0; j < n_phi_loc_bases; ++j)
529 assert(stiffness_val.size() ==
rows() *
cols());
532 for (
int n = 0; n <
rows(); ++n)
534 for (
int m = 0; m <
cols(); ++m)
536 const double local_value = stiffness_val(n *
cols() + m);
538 for (
size_t ii = 0; ii < global_i.size(); ++ii)
540 const auto gi = global_i[ii].index *
cols() + m;
541 const auto wi = global_i[ii].val;
543 for (
size_t jj = 0; jj < global_j.size(); ++jj)
545 const auto gj = global_j[jj].index *
rows() + n;
546 const auto wj = global_j[jj].val;
548 local_storage.cache->add_value(e, gj, gi, local_value * wi * wj);
550 if (local_storage.cache->entries_size() >= max_triplets_size)
552 local_storage.cache->prune();
553 logger().debug(
"cleaning memory...");
565 logger().trace(
"done separate assembly {}s...", timer.getElapsedTime());
569 for (LocalThreadMatStorage &local_storage : storage)
570 stiffness += local_storage.
cache->get_matrix(false);
571 stiffness.makeCompressed();
573 logger().trace(
"done merge assembly {}s...", timer.getElapsedTime());
580 const bool is_volume,
581 const int n_psi_basis,
582 const int n_phi_basis,
583 const std::vector<ElementBases> &psi_bases,
584 const std::vector<ElementBases> &phi_bases,
585 const std::vector<ElementBases> &gbases,
590 const Eigen::MatrixXd &
x,
591 const Eigen::MatrixXd &x_prev,
597 assert(phi_bases.size() == psi_bases.size());
598 assert(phi_bases.size() == gbases.size());
600 const int phi_ndof = n_phi_basis *
rows();
601 const int psi_ndof = n_psi_basis *
cols();
602 Eigen::MatrixXd x_phi, x_psi;
603 Eigen::MatrixXd x_phi_prev, x_psi_prev;
604 split_mixed_solution(split_solution,
x, phi_ndof, psi_ndof, x_phi, x_psi);
605 split_mixed_previous_solution(split_solution, x_prev, phi_ndof, psi_ndof, x_phi_prev, x_psi_prev);
608 const int n_bases = int(phi_bases.size());
615 for (
int e = start; e < end; ++e)
617 compute_mixed_element_values(
619 psi_bases[e], phi_bases[e], gbases[e],
620 psi_cache, phi_cache,
625 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
626 local_storage.da = phi_vals.
det.array() *
quadrature.weights.array();
634 for (
const LocalThreadScalarStorage &local_storage : storage)
635 res += local_storage.val;
640 const bool is_volume,
641 const int n_psi_basis,
642 const int n_phi_basis,
643 const std::vector<ElementBases> &psi_bases,
644 const std::vector<ElementBases> &phi_bases,
645 const std::vector<ElementBases> &gbases,
650 const Eigen::MatrixXd &
x,
651 const Eigen::MatrixXd &x_prev,
657 assert(phi_bases.size() == psi_bases.size());
658 assert(phi_bases.size() == gbases.size());
660 const int phi_ndof = n_phi_basis *
rows();
661 const int psi_ndof = n_psi_basis *
cols();
662 Eigen::MatrixXd x_phi, x_psi;
663 Eigen::MatrixXd x_phi_prev, x_psi_prev;
664 split_mixed_solution(split_solution,
x, phi_ndof, psi_ndof, x_phi, x_psi);
665 split_mixed_previous_solution(split_solution, x_prev, phi_ndof, psi_ndof, x_phi_prev, x_psi_prev);
668 const int n_bases = int(phi_bases.size());
669 Eigen::VectorXd out(phi_bases.size());
676 for (
int e = start; e < end; ++e)
678 compute_mixed_element_values(
680 psi_bases[e], phi_bases[e], gbases[e],
681 psi_cache, phi_cache,
686 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
687 local_storage.da = phi_vals.
det.array() *
quadrature.weights.array();
696 is_volume, n_psi_basis, n_phi_basis,
697 psi_bases, phi_bases, gbases,
698 psi_cache, phi_cache, t, dt,
x, x_prev, split_solution);
699 assert(std::abs(assemble_val - out.sum()) < std::max(1e-10 * std::abs(assemble_val), 1e-10));
706 const bool is_volume,
707 const int n_psi_basis,
708 const int n_phi_basis,
709 const std::vector<ElementBases> &psi_bases,
710 const std::vector<ElementBases> &phi_bases,
711 const std::vector<ElementBases> &gbases,
716 const Eigen::MatrixXd &
x,
717 const Eigen::MatrixXd &x_prev,
719 Eigen::MatrixXd &grad)
const
724 assert(phi_bases.size() == psi_bases.size());
725 assert(phi_bases.size() == gbases.size());
727 const int phi_ndof = n_phi_basis *
rows();
728 const int psi_ndof = n_psi_basis *
cols();
729 Eigen::MatrixXd x_phi, x_psi;
730 Eigen::MatrixXd x_phi_prev, x_psi_prev;
731 split_mixed_solution(split_solution,
x, phi_ndof, psi_ndof, x_phi, x_psi);
732 split_mixed_previous_solution(split_solution, x_prev, phi_ndof, psi_ndof, x_phi_prev, x_psi_prev);
734 grad.resize(phi_ndof + psi_ndof, 1);
738 const int n_bases = int(phi_bases.size());
745 for (
int e = start; e < end; ++e)
747 compute_mixed_element_values(
749 psi_bases[e], phi_bases[e], gbases[e],
750 psi_cache, phi_cache,
755 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
756 local_storage.da = phi_vals.
det.array() *
quadrature.weights.array();
761 const int n_phi_loc_bases = int(phi_vals.
basis_values.size());
762 const int n_psi_loc_bases = int(psi_vals.
basis_values.size());
763 assert(local_grad.size() == n_phi_loc_bases *
rows() + n_psi_loc_bases *
cols());
765 for (
int i = 0; i < n_phi_loc_bases; ++i)
768 for (
int d = 0; d <
rows(); ++d)
770 const double local_value = local_grad(i *
rows() + d);
771 for (
const auto &global : global_i)
772 local_storage.vec(global.index *
rows() + d) += local_value * global.val;
776 const int local_psi_offset = n_phi_loc_bases *
rows();
777 for (
int i = 0; i < n_psi_loc_bases; ++i)
780 for (
int d = 0; d <
cols(); ++d)
782 const double local_value = local_grad(local_psi_offset + i *
cols() + d);
783 for (
const auto &global : global_i)
784 local_storage.vec(phi_ndof + global.index *
cols() + d) += local_value * global.val;
790 for (
const LocalThreadVecStorage &local_storage : storage)
791 grad += local_storage.vec;
795 const bool is_volume,
796 const int n_psi_basis,
797 const int n_phi_basis,
798 const bool project_to_psd,
799 const std::vector<ElementBases> &psi_bases,
800 const std::vector<ElementBases> &phi_bases,
801 const std::vector<ElementBases> &gbases,
806 const Eigen::MatrixXd &
x,
807 const Eigen::MatrixXd &x_prev,
815 assert(phi_bases.size() == psi_bases.size());
816 assert(phi_bases.size() == gbases.size());
818 const int phi_ndof = n_phi_basis *
rows();
819 const int psi_ndof = n_psi_basis *
cols();
820 const int total_ndof = phi_ndof + psi_ndof;
821 Eigen::MatrixXd x_phi, x_psi;
822 Eigen::MatrixXd x_phi_prev, x_psi_prev;
823 split_mixed_solution(split_solution,
x, phi_ndof, psi_ndof, x_phi, x_psi);
824 split_mixed_previous_solution(split_solution, x_prev, phi_ndof, psi_ndof, x_phi_prev, x_psi_prev);
826 const int max_triplets_size = int(1e7);
827 const int buffer_size = std::min(max_triplets_size, total_ndof);
829 mat_cache.
init(total_ndof);
833 const int n_bases = int(phi_bases.size());
840 for (
int e = start; e < end; ++e)
842 compute_mixed_element_values(
844 psi_bases[e], phi_bases[e], gbases[e],
845 psi_cache, phi_cache,
850 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
851 local_storage.da = phi_vals.
det.array() *
quadrature.weights.array();
856 const int n_phi_loc_bases = int(phi_vals.
basis_values.size());
857 const int n_psi_loc_bases = int(psi_vals.
basis_values.size());
858 const int local_size = n_phi_loc_bases *
rows() + n_psi_loc_bases *
cols();
859 assert(local_hessian.rows() == local_size);
860 assert(local_hessian.cols() == local_size);
863 local_hessian = ipc::project_to_psd(local_hessian);
865 const auto local_index_data = [&](
866 const int local_index,
867 const std::vector<basis::Local2Global> *&global,
869 int &component_count,
870 int &global_offset) {
871 assert(local_index >= 0);
872 assert(local_index < local_size);
874 const int phi_local_size = n_phi_loc_bases *
rows();
875 if (local_index < phi_local_size)
877 const int basis_index = local_index /
rows();
879 component = local_index %
rows();
880 component_count =
rows();
885 const int psi_local_index = local_index - phi_local_size;
886 const int basis_index = psi_local_index /
cols();
888 component = psi_local_index %
cols();
889 component_count =
cols();
890 global_offset = phi_ndof;
893 for (
int i = 0; i < local_size; ++i)
895 const std::vector<basis::Local2Global> *global_i =
nullptr;
896 int component_i = -1;
897 int component_count_i = -1;
898 int global_offset_i = -1;
899 local_index_data(i, global_i, component_i, component_count_i, global_offset_i);
901 for (
int j = 0; j < local_size; ++j)
903 const double local_value = local_hessian(i, j);
904 if (local_value == 0)
907 const std::vector<basis::Local2Global> *global_j =
nullptr;
908 int component_j = -1;
909 int component_count_j = -1;
910 int global_offset_j = -1;
911 local_index_data(j, global_j, component_j, component_count_j, global_offset_j);
913 for (
const auto &gi : *global_i)
915 const int row = global_offset_i + gi.index * component_count_i + component_i;
916 for (
const auto &gj : *global_j)
918 const int col = global_offset_j + gj.index * component_count_j + component_j;
919 local_storage.cache->add_value(e, row, col, local_value * gi.val * gj.val);
923 if (local_storage.cache->entries_size() >= max_triplets_size)
925 local_storage.cache->prune();
926 logger().debug(
"cleaning memory...");
933 for (LocalThreadMatStorage &local_storage : storage)
935 local_storage.cache->prune();
936 mat_cache += *local_storage.cache;
942 const bool is_volume,
943 const std::vector<ElementBases> &bases,
944 const std::vector<ElementBases> &gbases,
948 const Eigen::MatrixXd &displacement,
949 const Eigen::MatrixXd &displacement_prev)
const
952 const int n_bases = int(bases.size());
958 for (
int e = start; e < end; ++e)
960 cache.compute(e, is_volume, bases[e], gbases[e],
vals);
964 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
968 local_storage.val +=
val;
974 for (
const LocalThreadScalarStorage &local_storage : storage)
975 res += local_storage.val;
980 const bool is_volume,
981 const std::vector<ElementBases> &bases,
982 const std::vector<ElementBases> &gbases,
986 const Eigen::MatrixXd &displacement,
987 const Eigen::MatrixXd &displacement_prev)
const
990 const int n_bases = int(bases.size());
991 Eigen::VectorXd out(bases.size());
997 for (
int e = start; e < end; ++e)
999 cache.compute(e, is_volume, bases[e], gbases[e],
vals);
1003 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
1004 local_storage.da =
vals.det.array() *
quadrature.weights.array();
1013 is_volume, bases, gbases,
cache, t, dt, displacement, displacement_prev);
1014 assert(std::abs(assemble_val - out.sum()) < std::max(1e-10 * assemble_val, 1e-10));
1021 const bool is_volume,
1023 const std::vector<ElementBases> &bases,
1024 const std::vector<ElementBases> &gbases,
1028 const Eigen::MatrixXd &displacement,
1029 const Eigen::MatrixXd &displacement_prev,
1030 Eigen::MatrixXd &rhs)
const
1032 rhs.resize(n_basis *
size(), 1);
1037 const int n_bases = int(bases.size());
1042 for (
int e = start; e < end; ++e)
1048 cache.compute(e, is_volume, bases[e], gbases[e],
vals);
1052 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
1053 local_storage.da =
vals.det.array() *
quadrature.weights.array();
1054 const int n_loc_bases = int(
vals.basis_values.size());
1057 assert(
val.size() == n_loc_bases *
size());
1059 for (
int j = 0; j < n_loc_bases; ++j)
1061 const auto &global_j =
vals.basis_values[j].global;
1064 for (
int m = 0; m <
size(); ++m)
1066 const double local_value =
val(j *
size() + m);
1068 for (
size_t jj = 0; jj < global_j.size(); ++jj)
1070 const auto gj = global_j[jj].index *
size() + m;
1071 const auto wj = global_j[jj].val;
1073 local_storage.vec(gj) += local_value * wj;
1087 for (
const LocalThreadVecStorage &local_storage : storage)
1088 rhs += local_storage.
vec;
1092 const bool is_volume,
1094 const bool project_to_psd,
1095 const std::vector<ElementBases> &bases,
1096 const std::vector<ElementBases> &gbases,
1097 const AssemblyValsCache &
cache,
1100 const Eigen::MatrixXd &displacement,
1101 const Eigen::MatrixXd &displacement_prev,
1102 MatrixCache &mat_cache,
1105 const int max_triplets_size = int(1e7);
1106 const int buffer_size = std::min(
long(max_triplets_size),
long(n_basis) *
size());
1112 mat_cache.init(n_basis *
size());
1113 mat_cache.set_zero();
1117 const int n_bases = int(bases.size());
1124 for (
int e = start;
e < end; ++
e)
1134 ElementAssemblyValues
vals;
1136 cache.compute(e, is_volume, bases[e], gbases[e],
vals);
1140 assert(MAX_QUAD_POINTS == -1 ||
quadrature.weights.size() < MAX_QUAD_POINTS);
1142 const int n_loc_bases = int(
vals.basis_values.size());
1144 auto stiffness_val =
assemble_hessian(NonLinearAssemblerData(
vals, t, dt, displacement, displacement_prev,
da));
1145 assert(stiffness_val.rows() == n_loc_bases *
size());
1146 assert(stiffness_val.cols() == n_loc_bases *
size());
1149 stiffness_val = ipc::project_to_psd(stiffness_val);
1167 for (
int i = 0; i < n_loc_bases; ++i)
1169 const auto &global_i =
vals.basis_values[i].global;
1171 for (
int j = 0; j < n_loc_bases; ++j)
1174 const auto &global_j =
vals.basis_values[j].global;
1176 for (
int n = 0; n <
size(); ++n)
1178 for (
int m = 0; m <
size(); ++m)
1180 const double local_value = stiffness_val(i *
size() + m, j *
size() + n);
1182 for (
size_t ii = 0; ii < global_i.size(); ++ii)
1184 const auto gi = global_i[ii].index *
size() + m;
1185 const auto wi = global_i[ii].val;
1187 for (
size_t jj = 0; jj < global_j.size(); ++jj)
1189 const auto gj = global_j[jj].index *
size() + n;
1190 const auto wj = global_j[jj].val;
1192 local_storage.cache->add_value(e, gi, gj, local_value * wi * wj);
1197 if (local_storage.cache->entries_size() >= max_triplets_size)
1199 local_storage.cache->prune();
1200 logger().debug(
"cleaning memory...");
1212 logger().trace(
"done separate assembly {}s...", timer.getElapsedTime());
1217 for (LocalThreadMatStorage &local_storage : storage)
1219 local_storage.cache->prune();
1220 mat_cache += *local_storage.cache;
1222 hess = mat_cache.get_matrix();
1225 logger().trace(
"done merge assembly {}s...", timer.getElapsedTime());
1230#ifdef POLYFEM_WITH_MISO
1233 logger().error(
"Enable Bezier library to use the robust Jacobian check!");
std::unique_ptr< MatrixCache > cache
ElementAssemblyValues vals
void set_materials(const std::vector< int > &body_ids, const json &body_params, const Units &units, const std::string &root_path)
virtual void add_multimaterial(const int index, const json ¶ms, const Units &units, const std::string &root_path)
Caches basis evaluation and geometric mapping at every element.
void compute(const int el_index, const bool is_volume, const basis::ElementBases &basis, const basis::ElementBases &gbasis, ElementAssemblyValues &vals) const
retrieves cached basis evaluation and geometric for the given element if it doesn't exist,...
void set_use_robust_jacobian()
stores per element basis values at given quadrature points and geometric mapping
std::vector< AssemblyValues > basis_values
quadrature::Quadrature quadrature
void assemble(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, StiffnessMatrix &stiffness, const bool is_mass=false) const override
assembles the stiffness matrix for the given basis the bilinear form (local assembler) is encoded by ...
virtual int rows() const =0
void assemble(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, StiffnessMatrix &stiffness) const
virtual int cols() const =0
void assemble_gradient(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, const double dt, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const SolutionSplitter &split_solution, Eigen::MatrixXd &grad) const
virtual int rows() const =0
virtual double compute_energy(const MixedNonLinearAssemblerData &data) const =0
void assemble_hessian(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const bool project_to_psd, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, const double dt, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const SolutionSplitter &split_solution, utils::MatrixCache &mat_cache, StiffnessMatrix &hessian) const
Eigen::VectorXd assemble_energy_per_element(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, const double dt, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const SolutionSplitter &split_solution) const
virtual Eigen::VectorXd compute_gradient(const MixedNonLinearAssemblerData &data) const =0
virtual Eigen::MatrixXd compute_hessian(const MixedNonLinearAssemblerData &data) const =0
std::function< void(const Eigen::MatrixXd &x, Eigen::MatrixXd &x_phi, Eigen::MatrixXd &x_psi)> SolutionSplitter
double assemble_energy(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, const double dt, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const SolutionSplitter &split_solution) const
virtual int cols() const =0
double assemble_energy(const bool is_volume, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, const double dt, const Eigen::MatrixXd &displacement, const Eigen::MatrixXd &displacement_prev) const override
Eigen::VectorXd assemble_energy_per_element(const bool is_volume, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, const double dt, const Eigen::MatrixXd &displacement, const Eigen::MatrixXd &displacement_prev) const override
virtual double compute_energy(const NonLinearAssemblerData &data) const =0
void assemble_gradient(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, const double dt, const Eigen::MatrixXd &displacement, const Eigen::MatrixXd &displacement_prev, Eigen::MatrixXd &rhs) const override
void assemble_hessian(const bool is_volume, const int n_basis, const bool project_to_psd, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, const double dt, const Eigen::MatrixXd &displacement, const Eigen::MatrixXd &displacement_prev, utils::MatrixCache &mat_cache, StiffnessMatrix &grad) const override
abstract class used for caching
virtual void set_zero()=0
virtual StiffnessMatrix get_matrix(const bool compute_mapping=true)=0
virtual void init(const size_t size)=0
constexpr const char * MATERIAL_ELEMENT_INDEX
auto & get_local_thread_storage(Storages &storage, int thread_id)
auto create_thread_storage(const LocalStorage &initial_local_storage)
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
spdlog::logger & logger()
Retrieves the current logger.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix