PolyFEM
Loading...
Searching...
No Matches
Assembler.cpp
Go to the documentation of this file.
1#include "Assembler.hpp"
2
5
6#include <igl/Timer.h>
7
8#include <ipc/utils/eigen_ext.hpp>
9
10namespace polyfem::assembler
11{
12 using namespace basis;
13 using namespace quadrature;
14 using namespace utils;
15
16 namespace
17 {
18 class LocalThreadMatStorage
19 {
20 public:
21 std::unique_ptr<MatrixCache> cache = nullptr;
22 ElementAssemblyValues vals;
24
25 LocalThreadMatStorage() = delete;
26
27 LocalThreadMatStorage(const int buffer_size, const int rows, const int cols)
28 {
29 init(buffer_size, rows, cols);
30 }
31
32 LocalThreadMatStorage(const int buffer_size, const MatrixCache &c)
33 {
34 init(buffer_size, c);
35 }
36
37 LocalThreadMatStorage(const LocalThreadMatStorage &other)
38 : cache(other.cache->copy()), vals(other.vals), da(other.da)
39 {
40 }
41
42 LocalThreadMatStorage &operator=(const LocalThreadMatStorage &other)
43 {
44 assert(other.cache != nullptr);
45 cache = other.cache->copy();
46 vals = other.vals;
47 da = other.da;
48 return *this;
49 }
50
51 void init(const int buffer_size, const int rows, const int cols)
52 {
53 // assert(rows == cols);
54 // cache = std::make_unique<DenseMatrixCache>();
55 cache = std::make_unique<SparseMatrixCache>();
56 cache->reserve(buffer_size);
57 cache->init(rows, cols);
58 }
59
60 void init(const int buffer_size, const MatrixCache &c)
61 {
62 if (cache == nullptr)
63 cache = c.copy();
64 cache->reserve(buffer_size);
65 cache->init(c);
66 }
67 };
68
69 class LocalThreadVecStorage
70 {
71 public:
72 Eigen::MatrixXd vec;
73 ElementAssemblyValues vals;
75
76 LocalThreadVecStorage(const int size)
77 {
78 vec.resize(size, 1);
79 vec.setZero();
80 }
81 };
82
83 class LocalThreadScalarStorage
84 {
85 public:
86 double val;
87 ElementAssemblyValues vals;
89
90 LocalThreadScalarStorage()
91 {
92 val = 0;
93 }
94 };
95 } // namespace
96
97 void Assembler::set_materials(const std::vector<int> &body_ids, const json &body_params, const Units &units)
98 {
99 if (!body_params.is_array())
100 {
101 this->add_multimaterial(0, body_params, units);
102 return;
103 }
104
105 std::map<int, json> materials;
106 for (int i = 0; i < body_params.size(); ++i)
107 {
108 json mat = body_params[i];
109 json id = mat["id"];
110 if (id.is_array())
111 {
112 for (int j = 0; j < id.size(); ++j)
113 materials[id[j]] = mat;
114 }
115 else
116 {
117 const int mid = id;
118 materials[mid] = mat;
119 }
120 }
121
122 std::set<int> missing;
123
124 std::map<int, int> body_element_count;
125 std::vector<int> eid_to_eid_in_body(body_ids.size());
126 for (int e = 0; e < body_ids.size(); ++e)
127 {
128 const int bid = body_ids[e];
129 body_element_count.try_emplace(bid, 0);
130 eid_to_eid_in_body[e] = body_element_count[bid]++;
131 }
132
133 for (int e = 0; e < body_ids.size(); ++e)
134 {
135 const int bid = body_ids[e];
136 const auto it = materials.find(bid);
137 if (it == materials.end())
138 {
139 missing.insert(bid);
140 continue;
141 }
142
143 const json &tmp = it->second;
144 this->add_multimaterial(e, tmp, units);
145 }
146
147 for (int bid : missing)
148 {
149 logger().warn("Missing material parameters for body {}", bid);
150 }
151 }
152
156
158 const bool is_volume,
159 const int n_basis,
160 const std::vector<ElementBases> &bases,
161 const std::vector<ElementBases> &gbases,
163 const double t,
164 StiffnessMatrix &stiffness,
165 const bool is_mass) const
166 {
167 assert(size() > 0);
168
169 const long int max_triplets_size = long(1e7);
170 const long int buffer_size = std::min(long(max_triplets_size), long(n_basis) * size());
171 // #ifdef POLYFEM_WITH_TBB
172 // buffer_size /= tbb::task_scheduler_init::default_num_threads();
173 // #endif
174 // logger().trace("buffer_size {}", buffer_size);
175 try
176 {
177 stiffness.resize(n_basis * size(), n_basis * size());
178 stiffness.setZero();
179
180 auto storage = create_thread_storage(LocalThreadMatStorage(buffer_size, stiffness.rows(), stiffness.cols()));
181
182 const int n_bases = int(bases.size());
183 igl::Timer timer;
184 timer.start();
185 assert(cache.is_mass() == is_mass);
186
187 // (potentially parallel) loop over elements
188 // Note that n_bases is the number of elements since ach ElementBases object stores
189 // all local basis functions on a given element
190 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
191 LocalThreadMatStorage &local_storage = get_local_thread_storage(storage, thread_id);
192
193 for (int e = start; e < end; ++e)
194 {
195 ElementAssemblyValues &vals = local_storage.vals;
196 // igl::Timer timer; timer.start();
197 // vals.compute(e, is_volume, bases[e], gbases[e]);
198
199 // compute geometric mapping
200 // evaluate and store basis functions/their gradients at quadrature points
201 cache.compute(e, is_volume, bases[e], gbases[e], vals);
202
203 const Quadrature &quadrature = vals.quadrature;
204
205 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
206 local_storage.da = vals.det.array() * quadrature.weights.array();
207 const int n_loc_bases = int(vals.basis_values.size());
208
209 for (int i = 0; i < n_loc_bases; ++i)
210 {
211 // const AssemblyValues &values_i = vals.basis_values[i];
212 // const Eigen::MatrixXd &gradi = values_i.grad_t_m;
213 const auto &global_i = vals.basis_values[i].global;
214
215 // loop over other bases up to the current one, taking advantage of symmetry
216 for (int j = 0; j <= i; ++j)
217 {
218 // const AssemblyValues &values_j = vals.basis_values[j];
219 // const Eigen::MatrixXd &gradj = values_j.grad_t_m;
220 const auto &global_j = vals.basis_values[j].global;
221
222 // compute local entry in stiffness matrix
223 const auto stiffness_val = assemble(LinearAssemblerData(vals, t, i, j, local_storage.da));
224 assert(stiffness_val.size() == size() * size());
225
226 // igl::Timer t1; t1.start();
227 // loop over dimensions of the problem
228 for (int n = 0; n < size(); ++n)
229 {
230 for (int m = 0; m < size(); ++m)
231 {
232 const double local_value = stiffness_val(n * size() + m);
233
234 // loop over the global nodes corresponding to local element (useful for non-conforming cases)
235 for (size_t ii = 0; ii < global_i.size(); ++ii)
236 {
237 const auto gi = global_i[ii].index * size() + m;
238 const auto wi = global_i[ii].val;
239
240 for (size_t jj = 0; jj < global_j.size(); ++jj)
241 {
242 const auto gj = global_j[jj].index * size() + n;
243 const auto wj = global_j[jj].val;
245 // add local value to the global matrix (weighted by corresponding nodes)
246 local_storage.cache->add_value(e, gi, gj, local_value * wi * wj);
247 if (j < i)
248 {
249 local_storage.cache->add_value(e, gj, gi, local_value * wj * wi);
250 }
251
252 if (local_storage.cache->entries_size() >= max_triplets_size)
253 {
254 local_storage.cache->prune();
255 logger().trace("cleaning memory. Current storage: {}. mat nnz: {}", local_storage.cache->capacity(), local_storage.cache->non_zeros());
256 }
257 }
258 }
259 }
260 }
261
262 // t1.stop();
263 // if (!vals.has_parameterization) { std::cout << "-- t1: " << t1.getElapsedTime() << std::endl; }
264 }
265 }
266
267 // timer.stop();
268 // if (!vals.has_parameterization) { std::cout << "-- Timer: " << timer.getElapsedTime() << std::endl; }
269 }
270 });
271
272 timer.stop();
273 logger().trace("done separate assembly {}s...", timer.getElapsedTime());
274
275 // Assemble the stiffness matrix by concatenating the tuples in each local storage
276
277 // Collect thread storages
278 std::vector<LocalThreadMatStorage *> storages(storage.size());
279 long int index = 0;
280 for (auto &local_storage : storage)
281 {
282 storages[index++] = &local_storage;
283 }
284
285 timer.start();
286 maybe_parallel_for(storages.size(), [&](int i) {
287 storages[i]->cache->prune();
288 });
289 timer.stop();
290 logger().trace("done pruning triplets {}s...", timer.getElapsedTime());
291
292 // Prepares for parallel concatenation
293 std::vector<long int> offsets(storage.size());
294
295 index = 0;
296 long int triplet_count = 0;
297 for (auto &local_storage : storage)
298 {
299 offsets[index++] = triplet_count;
300 triplet_count += local_storage.cache->triplet_count();
301 }
302
303 std::vector<Eigen::Triplet<double>> triplets;
304
305 assert(storages.size() >= 1);
306 if (storages[0]->cache->is_dense())
307 {
308 timer.start();
309 // Serially merge local storages
310 Eigen::MatrixXd tmp(stiffness);
311 for (const LocalThreadMatStorage &local_storage : storage)
312 tmp += dynamic_cast<const DenseMatrixCache &>(*local_storage.cache).mat();
313 stiffness = tmp.sparseView();
314 stiffness.makeCompressed();
315 timer.stop();
316
317 logger().trace("Serial assembly time: {}s...", timer.getElapsedTime());
318 }
319 else if (triplet_count >= triplets.max_size())
320 {
321 // Serial fallback version in case the vector of triplets cannot be allocated
322
323 logger().warn("Cannot allocate space for triplets, switching to serial assembly.");
324
325 timer.start();
326 // Serially merge local storages
327 for (LocalThreadMatStorage &local_storage : storage)
328 stiffness += local_storage.cache->get_matrix(false); // will also prune
329 stiffness.makeCompressed();
330 timer.stop();
331
332 logger().trace("Serial assembly time: {}s...", timer.getElapsedTime());
333 }
334 else
335 {
336 timer.start();
337 triplets.resize(triplet_count);
338 timer.stop();
339
340 logger().trace("done allocate triplets {}s...", timer.getElapsedTime());
341 logger().trace("Triplets Count: {}", triplet_count);
342
343 timer.start();
344 // Parallel copy into triplets
345 maybe_parallel_for(storages.size(), [&](int i) {
346 const SparseMatrixCache &cache = dynamic_cast<const SparseMatrixCache &>(*storages[i]->cache);
347 long int offset = offsets[i];
348
349 std::copy(cache.entries().begin(), cache.entries().end(), triplets.begin() + offset);
350 offset += cache.entries().size();
351
352 if (cache.mat().nonZeros() > 0)
353 {
354 long int count = 0;
355 for (int k = 0; k < cache.mat().outerSize(); ++k)
356 {
357 for (Eigen::SparseMatrix<double>::InnerIterator it(cache.mat(), k); it; ++it)
358 {
359 assert(count < cache.mat().nonZeros());
360 triplets[offset + count++] = Eigen::Triplet<double>(it.row(), it.col(), it.value());
361 }
362 }
363 }
364 });
365
366 timer.stop();
367 logger().trace("done concatenate triplets {}s...", timer.getElapsedTime());
368
369 timer.start();
370 // Sort and assemble
371 stiffness.setFromTriplets(triplets.begin(), triplets.end());
372 timer.stop();
373
374 logger().trace("done setFromTriplets assembly {}s...", timer.getElapsedTime());
375 }
376 }
377 catch (std::bad_alloc &ba)
378 {
379 log_and_throw_error("bad alloc {}", ba.what());
380 }
381
382 // stiffness.resize(n_basis*size(), n_basis*size());
383 // stiffness.setFromTriplets(entries.begin(), entries.end());
384 }
385
389
391 const bool is_volume,
392 const int n_psi_basis,
393 const int n_phi_basis,
394 const std::vector<ElementBases> &psi_bases,
395 const std::vector<ElementBases> &phi_bases,
396 const std::vector<ElementBases> &gbases,
397 const AssemblyValsCache &psi_cache,
398 const AssemblyValsCache &phi_cache,
399 const double t,
400 StiffnessMatrix &stiffness) const
401 {
402 assert(size() > 0);
403 assert(phi_bases.size() == psi_bases.size());
404
405 const int max_triplets_size = int(1e7);
406 const int buffer_size = std::min(long(max_triplets_size), long(std::max(n_psi_basis, n_phi_basis)) * std::max(rows(), cols()));
407 // logger().debug("buffer_size {}", buffer_size);
408
409 stiffness.resize(n_phi_basis * rows(), n_psi_basis * cols());
410 stiffness.setZero();
411
412 auto storage = create_thread_storage(LocalThreadMatStorage(buffer_size, stiffness.rows(), stiffness.cols()));
413
414 const int n_bases = int(phi_bases.size());
415 igl::Timer timer;
416 timer.start();
417
418 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
419 LocalThreadMatStorage &local_storage = get_local_thread_storage(storage, thread_id);
420 ElementAssemblyValues psi_vals, phi_vals;
421
422 for (int e = start; e < end; ++e)
423 {
424 // psi_vals.compute(e, is_volume, psi_bases[e], gbases[e]);
425 // phi_vals.compute(e, is_volume, phi_bases[e], gbases[e]);
426 psi_cache.compute(e, is_volume, psi_bases[e], gbases[e], psi_vals);
427 phi_cache.compute(e, is_volume, phi_bases[e], gbases[e], phi_vals);
428
429 const Quadrature &quadrature = phi_vals.quadrature;
430
431 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
432 local_storage.da = phi_vals.det.array() * quadrature.weights.array();
433 const int n_phi_loc_bases = int(phi_vals.basis_values.size());
434 const int n_psi_loc_bases = int(psi_vals.basis_values.size());
435
436 for (int i = 0; i < n_psi_loc_bases; ++i)
437 {
438 const auto &global_i = psi_vals.basis_values[i].global;
439
440 for (int j = 0; j < n_phi_loc_bases; ++j)
441 {
442 const auto &global_j = phi_vals.basis_values[j].global;
443
444 const auto stiffness_val = assemble(MixedAssemblerData(psi_vals, phi_vals, t, i, j, local_storage.da));
445 assert(stiffness_val.size() == rows() * cols());
446
447 // igl::Timer t1; t1.start();
448 for (int n = 0; n < rows(); ++n)
449 {
450 for (int m = 0; m < cols(); ++m)
451 {
452 const double local_value = stiffness_val(n * cols() + m);
453
454 for (size_t ii = 0; ii < global_i.size(); ++ii)
455 {
456 const auto gi = global_i[ii].index * cols() + m;
457 const auto wi = global_i[ii].val;
458
459 for (size_t jj = 0; jj < global_j.size(); ++jj)
460 {
461 const auto gj = global_j[jj].index * rows() + n;
462 const auto wj = global_j[jj].val;
463
464 local_storage.cache->add_value(e, gj, gi, local_value * wi * wj);
465
466 if (local_storage.cache->entries_size() >= max_triplets_size)
467 {
468 local_storage.cache->prune();
469 logger().debug("cleaning memory...");
470 }
471 }
472 }
473 }
474 }
475 }
476 }
477 }
478 });
479
480 timer.stop();
481 logger().trace("done separate assembly {}s...", timer.getElapsedTime());
482
483 timer.start();
484 // Serially merge local storages
485 for (LocalThreadMatStorage &local_storage : storage)
486 stiffness += local_storage.cache->get_matrix(false); // will also prune
487 stiffness.makeCompressed();
488 timer.stop();
489 logger().trace("done merge assembly {}s...", timer.getElapsedTime());
490
491 // stiffness.resize(n_basis*size(), n_basis*size());
492 // stiffness.setFromTriplets(entries.begin(), entries.end());
493 }
494
496 const bool is_volume,
497 const std::vector<ElementBases> &bases,
498 const std::vector<ElementBases> &gbases,
500 const double t,
501 const double dt,
502 const Eigen::MatrixXd &displacement,
503 const Eigen::MatrixXd &displacement_prev) const
504 {
505 auto storage = create_thread_storage(LocalThreadScalarStorage());
506 const int n_bases = int(bases.size());
507
508 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
509 LocalThreadScalarStorage &local_storage = get_local_thread_storage(storage, thread_id);
510 ElementAssemblyValues &vals = local_storage.vals;
511
512 for (int e = start; e < end; ++e)
513 {
514 cache.compute(e, is_volume, bases[e], gbases[e], vals);
515
516 const Quadrature &quadrature = vals.quadrature;
517
518 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
519 local_storage.da = vals.det.array() * quadrature.weights.array();
520
521 const double val = compute_energy(NonLinearAssemblerData(vals, t, dt, displacement, displacement_prev, local_storage.da));
522 local_storage.val += val;
523 }
524 });
525
526 double res = 0;
527 // Serially merge local storages
528 for (const LocalThreadScalarStorage &local_storage : storage)
529 res += local_storage.val;
530 return res;
531 }
532
534 const bool is_volume,
535 const std::vector<ElementBases> &bases,
536 const std::vector<ElementBases> &gbases,
538 const double t,
539 const double dt,
540 const Eigen::MatrixXd &displacement,
541 const Eigen::MatrixXd &displacement_prev) const
542 {
543 auto storage = create_thread_storage(LocalThreadScalarStorage());
544 const int n_bases = int(bases.size());
545 Eigen::VectorXd out(bases.size());
546
547 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
548 LocalThreadScalarStorage &local_storage = get_local_thread_storage(storage, thread_id);
549 ElementAssemblyValues &vals = local_storage.vals;
550
551 for (int e = start; e < end; ++e)
552 {
553 cache.compute(e, is_volume, bases[e], gbases[e], vals);
554
555 const Quadrature &quadrature = vals.quadrature;
556
557 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
558 local_storage.da = vals.det.array() * quadrature.weights.array();
559
560 const double val = compute_energy(NonLinearAssemblerData(vals, t, dt, displacement, displacement_prev, local_storage.da));
561 out[e] = val;
562 }
563 });
564
565#ifndef NDEBUG
566 const double assemble_val = assemble_energy(
567 is_volume, bases, gbases, cache, t, dt, displacement, displacement_prev);
568 assert(std::abs(assemble_val - out.sum()) < std::max(1e-10 * assemble_val, 1e-10));
569#endif
570
571 return out;
572 }
573
575 const bool is_volume,
576 const int n_basis,
577 const std::vector<ElementBases> &bases,
578 const std::vector<ElementBases> &gbases,
580 const double t,
581 const double dt,
582 const Eigen::MatrixXd &displacement,
583 const Eigen::MatrixXd &displacement_prev,
584 Eigen::MatrixXd &rhs) const
585 {
586 rhs.resize(n_basis * size(), 1);
587 rhs.setZero();
588
589 auto storage = create_thread_storage(LocalThreadVecStorage(rhs.size()));
590
591 const int n_bases = int(bases.size());
592
593 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
594 LocalThreadVecStorage &local_storage = get_local_thread_storage(storage, thread_id);
595
596 for (int e = start; e < end; ++e)
597 {
598 // igl::Timer timer; timer.start();
599
600 ElementAssemblyValues &vals = local_storage.vals;
601 // vals.compute(e, is_volume, bases[e], gbases[e]);
602 cache.compute(e, is_volume, bases[e], gbases[e], vals);
603
604 const Quadrature &quadrature = vals.quadrature;
605
606 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
607 local_storage.da = vals.det.array() * quadrature.weights.array();
608 const int n_loc_bases = int(vals.basis_values.size());
609
610 const auto val = assemble_gradient(NonLinearAssemblerData(vals, t, dt, displacement, displacement_prev, local_storage.da));
611 assert(val.size() == n_loc_bases * size());
612
613 for (int j = 0; j < n_loc_bases; ++j)
614 {
615 const auto &global_j = vals.basis_values[j].global;
616
617 // igl::Timer t1; t1.start();
618 for (int m = 0; m < size(); ++m)
619 {
620 const double local_value = val(j * size() + m);
621
622 for (size_t jj = 0; jj < global_j.size(); ++jj)
623 {
624 const auto gj = global_j[jj].index * size() + m;
625 const auto wj = global_j[jj].val;
626
627 local_storage.vec(gj) += local_value * wj;
628 }
629 }
630
631 // t1.stop();
632 // if (!vals.has_parameterization) { std::cout << "-- t1: " << t1.getElapsedTime() << std::endl; }
633 }
634
635 // timer.stop();
636 // if (!vals.has_parameterization) { std::cout << "-- Timer: " << timer.getElapsedTime() << std::endl; }
637 }
638 });
639
640 // Serially merge local storages
641 for (const LocalThreadVecStorage &local_storage : storage)
642 rhs += local_storage.vec;
643 }
644
646 const bool is_volume,
647 const int n_basis,
648 const bool project_to_psd,
649 const std::vector<ElementBases> &bases,
650 const std::vector<ElementBases> &gbases,
651 const AssemblyValsCache &cache,
652 const double t,
653 const double dt,
654 const Eigen::MatrixXd &displacement,
655 const Eigen::MatrixXd &displacement_prev,
656 MatrixCache &mat_cache,
657 StiffnessMatrix &hess) const
658 {
659 const int max_triplets_size = int(1e7);
660 const int buffer_size = std::min(long(max_triplets_size), long(n_basis) * size());
661 // std::cout<<"buffer_size "<<buffer_size<<std::endl;
662
663 // hess.resize(n_basis * size(), n_basis * size());
664 // hess.setZero();
665
666 mat_cache.init(n_basis * size());
667 mat_cache.set_zero();
668
669 auto storage = create_thread_storage(LocalThreadMatStorage(buffer_size, mat_cache));
670
671 const int n_bases = int(bases.size());
672 igl::Timer timer;
673 timer.start();
674
675 maybe_parallel_for(n_bases, [&](int start, int end, int thread_id) {
676 LocalThreadMatStorage &local_storage = get_local_thread_storage(storage, thread_id);
677
678 for (int e = start; e < end; ++e)
679 {
680 ElementAssemblyValues &vals = local_storage.vals;
681 cache.compute(e, is_volume, bases[e], gbases[e], vals);
682
683 const Quadrature &quadrature = vals.quadrature;
684
685 assert(MAX_QUAD_POINTS == -1 || quadrature.weights.size() < MAX_QUAD_POINTS);
686 local_storage.da = vals.det.array() * quadrature.weights.array();
687 const int n_loc_bases = int(vals.basis_values.size());
688
689 auto stiffness_val = assemble_hessian(NonLinearAssemblerData(vals, t, dt, displacement, displacement_prev, local_storage.da));
690 assert(stiffness_val.rows() == n_loc_bases * size());
691 assert(stiffness_val.cols() == n_loc_bases * size());
692
693 if (project_to_psd)
694 stiffness_val = ipc::project_to_psd(stiffness_val);
695
696 // bool has_nan = false;
697 // for(int k = 0; k < stiffness_val.size(); ++k)
698 // {
699 // if(std::isnan(stiffness_val(k)))
700 // {
701 // has_nan = true;
702 // break;
703 // }
704 // }
705
706 // if(has_nan)
707 // {
708 // local_storage.entries.emplace_back(0, 0, std::nan(""));
709 // break;
710 // }
711
712 for (int i = 0; i < n_loc_bases; ++i)
713 {
714 const auto &global_i = vals.basis_values[i].global;
715
716 for (int j = 0; j < n_loc_bases; ++j)
717 // for(int j = 0; j <= i; ++j)
718 {
719 const auto &global_j = vals.basis_values[j].global;
720
721 for (int n = 0; n < size(); ++n)
722 {
723 for (int m = 0; m < size(); ++m)
724 {
725 const double local_value = stiffness_val(i * size() + m, j * size() + n);
726
727 for (size_t ii = 0; ii < global_i.size(); ++ii)
728 {
729 const auto gi = global_i[ii].index * size() + m;
730 const auto wi = global_i[ii].val;
731
732 for (size_t jj = 0; jj < global_j.size(); ++jj)
733 {
734 const auto gj = global_j[jj].index * size() + n;
735 const auto wj = global_j[jj].val;
736
737 local_storage.cache->add_value(e, gi, gj, local_value * wi * wj);
738 // if (j < i) {
739 // local_storage.entries.emplace_back(gj, gi, local_value * wj * wi);
740 // }
741
742 if (local_storage.cache->entries_size() >= max_triplets_size)
743 {
744 local_storage.cache->prune();
745 logger().debug("cleaning memory...");
746 }
747 }
748 }
749 }
750 }
751 }
752 }
753 }
754 });
755
756 timer.stop();
757 logger().trace("done separate assembly {}s...", timer.getElapsedTime());
758
759 timer.start();
760
761 // Serially merge local storages
762 for (LocalThreadMatStorage &local_storage : storage)
763 {
764 local_storage.cache->prune();
765 mat_cache += *local_storage.cache;
766 }
767 hess = mat_cache.get_matrix();
768
769 timer.stop();
770 logger().trace("done merge assembly {}s...", timer.getElapsedTime());
771 }
772
773} // namespace polyfem::assembler
Eigen::MatrixXd vec
Definition Assembler.cpp:72
double val
Definition Assembler.cpp:86
QuadratureVector da
Definition Assembler.cpp:23
std::unique_ptr< MatrixCache > cache
Definition Assembler.cpp:21
ElementAssemblyValues vals
Definition Assembler.cpp:22
Quadrature quadrature
Eigen::MatrixXd mat
void set_materials(const std::vector< int > &body_ids, const json &body_params, const Units &units)
Definition Assembler.cpp:97
virtual void add_multimaterial(const int index, const json &params, const Units &units)
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,...
stores per element basis values at given quadrature points and geometric mapping
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
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
list tmp
Definition p_bases.py:339
Used for test only.
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.
Definition Logger.cpp:42
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
Definition Types.hpp:15
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:20