21#define CHECK_USE_CENTRAL_DIFFERENCE 1
27#ifndef B2SOLVER_UTILS_H_
28#define B2SOLVER_UTILS_H_
30#include "b2ppconfig.h"
35#include "utils/b2linear_algebra.H"
37#include <tbb/global_control.h>
45#include "utils/b2threading.H"
50inline uint64_t get_time_stamp() {
52 clock_gettime(CLOCK_REALTIME, &tp);
53 return tp.tv_sec * 1000000000ull + tp.tv_nsec;
56std::list<std::string> locklog;
59#ifdef CHECK_MULTITHREADING
60void foo(uint64_t& a) { a = uint64_t(pthread_self()); }
66 void operator()(
const tbb::blocked_range<size_t>& r)
const {
68 for (
size_t i = r.begin(); i != r.end(); ++i) { foo(a[i]); }
70 ApplyFoo(uint64_t a[]) : my_a(a) {}
73size_t check_parallel_for() {
74 std::vector<uint64_t> v(10000000, 0);
76 tbb::parallel_for(tbb::blocked_range<size_t>(0, v.size()), ApplyFoo(&v[0]));
78 std::set<uint64_t> ids;
79 for (
auto i : v) { ids.insert(i); }
80 std::cerr <<
"solver check_parallel_for: approximate number of threads=" << ids.size()
91class DofFieldFlux :
public Object {
93 virtual void add_flux(
94 b2linalg::Index& index,
const b2linalg::Vector<T, b2linalg::Vdense>& v) = 0;
100 typename T,
typename MATRIX_FORMAT,
typename Args,
bool useRayleighDampening =
false,
101 bool INERTIA =
false>
102struct ElementsTaskLoop {
103 ElementsTaskLoop(Args& args_, b2Mutex& mutex_) : args(args_), mutex(mutex_) {}
108 void operator()(
size_t begin,
size_t end)
const {
109 const bool compute_value_with_h = args.linear && !args.dof.is_null()
110 && !args.d_value_d_dof.is_null() && !args.value.is_null();
111 b2linalg::Index index;
112 b2linalg::Vector<T, b2linalg::Vdense> value;
113 b2linalg::Vector<T, b2linalg::Vdense> d_value_d_time;
114 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_value_d_dof(
115 args.d_value_d_dof_e_flags.size());
116 for (
size_t i = begin; i != end; ++i) {
117 Element* element = args.list_elements[i];
118 GradientContainer* gc =
119 (args.gradient_container != 0
120 && args.gradient_container->set_current_element(*element)
121 ? args.gradient_container
123 if (
auto te =
dynamic_cast<TypedElement<T>*
>(element); te !=
nullptr) {
125 args.model, args.linear, args.equilibrium_solution, args.time,
128 ? b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null
131 gc, args.solver_hints, index,
132 (args.value.is_null() ? b2linalg::Vector<T, b2linalg::Vdense>::null : value),
133 args.d_value_d_dof_e_flags, d_value_d_dof,
134 (args.d_value_d_time.is_null() ? b2linalg::Vector<T, b2linalg::Vdense>::null
137 if (index.empty()) {
continue; }
138 if (compute_value_with_h) {
141 b2linalg::Vector<T> tmp = args.dof[0](index);
142 value += d_value_d_dof[0] * tmp;
144 if constexpr (!useRayleighDampening) {
145 for (
size_t i = 1; i != args.dof.size2(); ++i) {
147 b2linalg::Vector<T> tmp = args.dof[i](index);
148 value += d_value_d_dof[i] * tmp;
152 if constexpr (useRayleighDampening) {
153 if (!value.empty()) {
155 b2linalg::Vector<T> tmp = args.dof[1](index);
156 value += args.d_fe_d_dofdot_elem[i] * tmp;
158 tmp = args.dof[2](index);
159 value += args.d_fe_d_dofdotdot_elem[i] * tmp;
165 << logging::DBName(
"EDOF", element->get_object_name()) << index
166 <<
" of element id " << element->get_object_name()
167 << logging::LOGFLUSH;
168 for (
size_t i = 0; i != args.dof.size2(); ++i) {
169 b2linalg::Vector<T> tmp = args.dof[i](index);
172 << logging::DBName(
"ELDOF", i, element->get_object_name()) << tmp
173 <<
" of element id " << element->get_object_name() << logging::LOGFLUSH;
175 if (!args.value.is_null()) {
178 << logging::DBName(
"ELFV", element->get_object_name()) << value
179 <<
" of element id " << element->get_object_name() << logging::LOGFLUSH;
181 if (!args.d_value_d_dof.is_null()) {
182 for (
size_t i = 0; i != d_value_d_dof.size(); ++i) {
183 b2linalg::Matrix<T> tmp_element(d_value_d_dof[i]);
184 *(args.logger) <<
logging::data <<
"elementary d_value_d_dof "
185 << logging::DBName(
"ELSV", i, element->get_object_name())
186 << tmp_element <<
" of element id "
187 << element->get_object_name() << logging::LOGFLUSH;
190 if (!args.d_value_d_time.is_null()) {
193 << logging::DBName(
"ELTV", element->get_object_name()) << d_value_d_time
194 <<
" of element id " << element->get_object_name() << logging::LOGFLUSH;
197 if (!d_value_d_dof.empty()) {
198 if constexpr (useRayleighDampening) {
199 d_value_d_dof[0] += T(args.d_value_d_dof_coeff[1]) * args.d_fe_d_dofdot_elem[i];
202 T(args.d_value_d_dof_coeff[2]) * args.d_fe_d_dofdotdot_elem[i];
205 if (!args.d_value_d_dof_coeff.is_null() && args.d_value_d_dof_coeff[0] != 1.0) {
206 d_value_d_dof[0] *= args.d_value_d_dof_coeff[0];
208 for (
size_t i = 1; i != d_value_d_dof.size(); ++i) {
209 d_value_d_dof[0] += T(args.d_value_d_dof_coeff[i]) * d_value_d_dof[i];
213 if (!args.d_value_d_time.is_null()) {
214 d_value_d_time += d_value_d_dof[0] * args.d_r_d_time(index);
217 std::ostringstream os;
218 os << get_time_stamp() <<
" thread_id=" << pthread_self()
219 <<
" 2nd var=" << args.d_value_d_dof.is_null() <<
" acquiring" << std::endl;
223 b2Mutex::scoped_lock lock(mutex);
229 os << get_time_stamp() <<
" thread_id=" << pthread_self() <<
" got it" << std::endl;
231 if (!value.empty()) {
232 if (args.dof_field_flux) { args.dof_field_flux->add_flux(index, value); }
233 args.value(index) += value;
235 if (!args.d_value_d_time.is_null()) {
236 args.d_value_d_time(index) += d_value_d_time;
238 if (!args.d_value_d_dof.is_null()) {
239 args.d_value_d_dof += args.trans_d_r_d_dof
240 * StructuredMatrix(args.nb_dof, index, d_value_d_dof[0])
241 * transposed(args.trans_d_r_d_dof);
244 os << get_time_stamp() <<
" thread_id=" << pthread_self() <<
" releasing"
246 locklog.push_back(os.str());
249 if constexpr (useRayleighDampening) {
251 const double el_volume = gc->get_element_volume();
252 const GradientContainer::InternalElementPosition pos = {0, 0, 0, 0};
253 if (el_volume == 0) { gc->set_current_position(pos, el_volume); }
257 const double inv_el_volume = el_volume == 0 ? 0 : 1 / el_volume;
259 b2linalg::Vector<T> v = args.dof[1](index);
260 b2linalg::Vector<T> tmp;
261 tmp = args.d_fe_d_dofdot_elem[i] * v;
262 const double rate_of_dissipated_energie = v * tmp;
263 args.dissipated_energy[i] +=
264 0.5 * args.delta_time
265 * (rate_of_dissipated_energie + args.last_rate_dissipated_energy[i]);
266 args.last_rate_dissipated_energy[i] = rate_of_dissipated_energie;
267 if (INERTIA) { tmp = args.d_fe_d_dofdotdot_elem[i] * v; }
268 const double kinetic_energie = INERTIA ? 0.5 * v * tmp : 0;
270 b2Mutex::scoped_lock lock(mutex);
271 args.energy[0] += kinetic_energie;
272 args.energy[1] += rate_of_dissipated_energie;
276 "RAYLEIGH_ENERGY_DENSITY",
277 "Kinetic.RateDissipated.Dissipated",
278 "kinetic, rate of dissipated energy and dissipated energy, per unit "
279 "volume, in the undeformed configuration",
286 const double e[3] = {
287 kinetic_energie * inv_el_volume,
288 rate_of_dissipated_energie * inv_el_volume,
289 args.dissipated_energy[i] * inv_el_volume};
290 gc->set_field_value(descr_energy, e);
291 }
else if (args.energy) {
292 b2linalg::Vector<T> v = args.dof[1](index);
293 b2linalg::Vector<T> tmp;
294 tmp = args.d_fe_d_dofdot_elem[i] * v;
295 const double rate_of_dissipated_energie = v * tmp;
296 args.dissipated_energy[i] +=
297 0.5 * args.delta_time
298 * (rate_of_dissipated_energie + args.last_rate_dissipated_energy[i]);
299 args.last_rate_dissipated_energy[i] = rate_of_dissipated_energie;
300 if (INERTIA) { tmp = args.d_fe_d_dofdotdot_elem[i] * v; }
301 const double kinetic_energie = INERTIA ? 0.5 * v * tmp : 0;
302 b2Mutex::scoped_lock lock(mutex);
303 args.energy[0] += kinetic_energie;
304 args.energy[1] += rate_of_dissipated_energie;
311template <
typename T,
typename MATRIX_FORMAT>
314 void get_elements_values(
315 const b2linalg::Matrix<T, b2linalg::Mrectangle_constref>& dof,
const double time,
316 const double delta_time,
const EquilibriumSolution equilibrium_solution,
317 const bool linear,
const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof,
318 const b2linalg::Vector<T, b2linalg::Vdense_constref>& d_r_d_time,
319 const b2linalg::Vector<double, b2linalg::Vdense_constref>& d_value_d_dof_coeff,
320 Model& model, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
321 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_value_d_dof,
322 b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time,
323 GradientContainer* gradient_container, SolverHints* solver_hints, logging::Logger& logger,
324 DofFieldFlux<T>* dof_field_flux = 0) {
325 Domain& domain = model.get_domain();
327 if (list_elements.empty()) { compute_tree(domain, trans_d_r_d_dof); }
328 std::vector<bool> d_value_d_dof_e_flags(
329 d_value_d_dof.is_null() && d_value_d_time.is_null()
331 : (d_value_d_dof_coeff.is_null() ? 1 : d_value_d_dof_coeff.size()),
337 equilibrium_solution,
343 domain.get_number_of_dof(),
345 d_value_d_dof_e_flags,
355#ifdef CHECK_MULTITHREADING
356 check_parallel_for();
364 b2RunPossiblyParallel<ElementsTaskLoop<T, MATRIX_FORMAT, Args, false> >(
365 args.tree[0].first, args.tree[0].second, args, mutex);
368 for (
auto s : locklog) { std::cout << s; }
374 const b2linalg::Matrix<T, b2linalg::Mrectangle_constref>& dof;
376 const double delta_time;
377 const EquilibriumSolution equilibrium_solution;
379 const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof;
380 const b2linalg::Vector<T, b2linalg::Vdense_constref>& d_r_d_time;
381 const b2linalg::Vector<double, b2linalg::Vdense_constref>& d_value_d_dof_coeff;
384 b2linalg::Vector<T, b2linalg::Vdense_ref>& value;
385 std::vector<bool>& d_value_d_dof_e_flags;
386 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_value_d_dof;
387 b2linalg::Vector<T, b2linalg::Vdense_ref>& d_value_d_time;
388 GradientContainer* gradient_container;
389 SolverHints* solver_hints;
390 logging::Logger* logger;
391 DofFieldFlux<T>* dof_field_flux;
392 std::vector<Element*>& list_elements;
393 std::vector<std::pair<size_t, size_t> >& tree;
394#ifndef SOLVER_UTILS_USE_RECURSIVE_TREE
400 Domain& domain,
const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof) {
401 element_iterator = domain.get_element_iterator();
402 const size_t nb_element = domain.get_number_of_elements();
403 list_elements.reserve(nb_element);
404#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
406 std::vector<std::vector<size_t> > dof(domain.get_number_of_dof());
407 std::vector<size_t> g_ptr(nb_element + 1);
409 std::vector<size_t> g_ind;
410 g_ind.reserve(nb_element);
411 b2linalg::Index index;
413 Domain::ElementIterator* i = element_iterator.get();
415 for (Element* element = i->next(); element != 0; element = i->next()) {
416 list_elements.push_back(element);
417#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
418 element->get_dof_numbering(index);
420 std::set<size_t> ind(index.begin(), index.end());
421 trans_d_r_d_dof.this_prod_index(index);
422 ind.insert(index.begin(), index.end());
423 for (std::set<size_t>::const_iterator j = ind.begin(); j != ind.end(); ++j) {
424 std::vector<size_t>& d = dof[*j];
425 s.insert(d.begin(), d.end());
428 g_ind.insert(g_ind.end(), s.begin(), s.end());
429 g_ptr[++i_ptr] = g_ind.size();
432#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
434 std::vector<size_t> inv_perm(nb_element);
436 int(std::log(tbb::global_control::active_value(
437 tbb::global_control::max_allowed_parallelism))
439 tree_nlevel = nlevel;
440 tree.resize(
int(std::pow(2.0, nlevel + 1)));
441 mlevel_nested_dissection_with_separator(
442 nb_element, &g_ptr[0], &g_ind[0], nlevel, &inv_perm[0], &tree[0]);
443 std::vector<Element*> list_elements_tmp(nb_element);
444 for (
size_t i = 0; i != nb_element; ++i) {
445 list_elements_tmp[inv_perm[i]] = list_elements[i];
447 list_elements.swap(list_elements_tmp);
449 tree.push_back(std::pair<size_t, size_t>(0, list_elements.size()));
454 std::unique_ptr<Domain::ElementIterator> element_iterator;
455 std::vector<Element*> list_elements;
456 std::vector<std::pair<size_t, size_t> > tree;
460template <
typename T,
typename MATRIX_FORMAT,
bool INERTIA = true>
461class SolverUtilsOrderTwoRayleighDamping {
464 const double rayleigh_damping_alpha_,
const double rayleigh_damping_beta_, Model& model,
465 logging::Logger& logger) {
466 rayleigh_damping_alpha = rayleigh_damping_alpha_;
467 rayleigh_damping_beta = rayleigh_damping_beta_;
468 last_rate_dissipated_energy.assign(last_rate_dissipated_energy.size(), 0);
469 dissipated_energy.assign(dissipated_energy.size(), 0);
470 global_last_rate_dissipated_energy = 0;
471 global_dissipated_energy = 0;
474 void scale_raylay_damping(
double s) {
475 for (
size_t i = 0; i != d_fe_d_dofdot_elem.size(); ++i) { d_fe_d_dofdot_elem[i] *= s; }
478 void get_elements_values(
479 const b2linalg::Matrix<T, b2linalg::Mrectangle_constref>& dof,
const double time,
480 const double delta_time,
const EquilibriumSolution equilibrium_solution,
481 const bool linear,
const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof,
482 const b2linalg::Vector<T, b2linalg::Vdense_constref> d_r_d_time,
483 const b2linalg::Vector<double, b2linalg::Vdense_constref>& d_value_d_dof_coeff,
484 Model& model, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
485 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_value_d_dof,
486 b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time,
487 GradientContainer* gradient_container, SolverHints* solver_hints, logging::Logger& logger,
488 DofFieldFlux<T>* dof_field_flux = 0,
double* energy = 0) {
489 Domain& domain = model.get_domain();
491 if (energy) { std::fill_n(energy, 3, 0.0); }
494 std::vector<bool> d_value_d_dof_e_flags(
495 d_value_d_dof.is_null() && d_value_d_time.is_null() ? 0 : 1, true);
497 if (list_elements.empty()) {
498 compute_tree(domain, trans_d_r_d_dof);
500 std::vector<bool> d_value_d_dof_flags(3);
501 d_value_d_dof_flags[0] = d_value_d_dof_flags[2] =
true;
502 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_fe_d_dof_elem(3);
503 d_fe_d_dofdot_elem.resize(list_elements.size());
504 if (INERTIA) { d_fe_d_dofdotdot_elem.resize(list_elements.size()); }
505 b2linalg::Index index;
506 for (
size_t i = 0; i != list_elements.size(); ++i) {
507 Element* e = list_elements[i];
508 if (
auto te =
dynamic_cast<TypedElement<T>*
>(e); te !=
nullptr) {
515 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
517 solver_hints, index, b2linalg::Vector<T, b2linalg::Vdense>::null,
518 d_value_d_dof_flags, d_fe_d_dof_elem,
519 b2linalg::Vector<T, b2linalg::Vdense>::null);
521 d_fe_d_dofdot_elem[i] = d_fe_d_dof_elem[0];
522 if (INERTIA) { d_fe_d_dofdotdot_elem[i] = d_fe_d_dof_elem[2]; }
523 d_fe_d_dofdot_elem[i] *= rayleigh_damping_beta;
524 d_fe_d_dofdot_elem[i] += rayleigh_damping_alpha * d_fe_d_dof_elem[2];
526 last_rate_dissipated_energy.assign(d_fe_d_dofdot_elem.size(), 0);
527 dissipated_energy.assign(d_fe_d_dofdot_elem.size(), 0);
534 equilibrium_solution,
540 domain.get_number_of_dof(),
542 d_value_d_dof_e_flags,
553 d_fe_d_dofdotdot_elem,
554 last_rate_dissipated_energy,
556 global_last_rate_dissipated_energy,
557 global_dissipated_energy};
560 b2runRecursively<ElementsTaskLoop<T, MATRIX_FORMAT, Args, true, INERTIA> >(
561 0, tree_nlevel, args, mutex);
564 global_dissipated_energy +=
565 0.5 * delta_time * (global_last_rate_dissipated_energy + energy[1]);
566 global_last_rate_dissipated_energy = energy[1];
567 energy[2] = global_dissipated_energy;
573 const b2linalg::Matrix<T, b2linalg::Mrectangle_constref> dof;
575 const double delta_time;
576 const EquilibriumSolution equilibrium_solution;
578 const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof;
579 const b2linalg::Vector<T, b2linalg::Vdense_constref>& d_r_d_time;
580 const b2linalg::Vector<double, b2linalg::Vdense_constref>& d_value_d_dof_coeff;
583 b2linalg::Vector<T, b2linalg::Vdense_ref>& value;
584 const std::vector<bool>& d_value_d_dof_e_flags;
585 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_value_d_dof;
586 b2linalg::Vector<T, b2linalg::Vdense_ref>& d_value_d_time;
587 GradientContainer* gradient_container;
588 SolverHints* solver_hints;
589 logging::Logger* logger;
590 DofFieldFlux<T>* dof_field_flux;
592 std::vector<Element*>& list_elements;
593 std::vector<std::pair<size_t, size_t> >& tree;
594 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> >& d_fe_d_dofdot_elem;
595 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> >& d_fe_d_dofdotdot_elem;
596 std::vector<double>& last_rate_dissipated_energy;
597 std::vector<double>& dissipated_energy;
598 double& global_last_rate_dissipated_energy;
599 double& global_dissipated_energy;
603 Domain& domain,
const b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_d_r_d_dof) {
604 element_iterator = domain.get_element_iterator();
605 const size_t nb_element = domain.get_number_of_elements();
606 list_elements.reserve(nb_element);
607#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
609 std::vector<std::vector<size_t> > dof(domain.get_number_of_dof());
610 std::vector<size_t> g_ptr(nb_element + 1);
612 std::vector<size_t> g_ind;
613 g_ind.reserve(nb_element);
614 b2linalg::Index index;
616 Domain::ElementIterator* i = element_iterator.get();
618 for (Element* element = i->next(); element != 0; element = i->next()) {
619 list_elements.push_back(element);
620#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
621 element->get_dof_numbering(index);
623 std::set<size_t> ind(index.begin(), index.end());
624 trans_d_r_d_dof.this_prod_index(index);
625 ind.insert(index.begin(), index.end());
626 for (std::set<size_t>::const_iterator j = ind.begin(); j != ind.end(); ++j) {
627 std::vector<size_t>& d = dof[*j];
628 s.insert(d.begin(), d.end());
631 g_ind.insert(g_ind.end(), s.begin(), s.end());
632 g_ptr[++i_ptr] = g_ind.size();
635#ifdef SOLVER_UTILS_USE_RECURSIVE_TREE
637 std::vector<size_t> inv_perm(nb_element);
639 int(std::log(tbb::global_control::active_value(
640 tbb::global_control::max_allowed_parallelism))
642 tree_nlevel = nlevel;
643 tree.resize(
int(std::pow(2.0, nlevel + 1)));
644 mlevel_nested_dissection_with_separator(
645 nb_element, &g_ptr[0], &g_ind[0], nlevel, &inv_perm[0], &tree[0]);
646 std::vector<Element*> list_elements_tmp(nb_element);
647 for (
size_t i = 0; i != nb_element; ++i) {
648 list_elements_tmp[inv_perm[i]] = list_elements[i];
650 list_elements.swap(list_elements_tmp);
652 tree.push_back(std::pair<size_t, size_t>(0, list_elements.size()));
657 std::unique_ptr<Domain::ElementIterator> element_iterator;
658 std::vector<Element*> list_elements;
659 std::vector<std::pair<size_t, size_t> > tree;
662 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_fe_d_dofdot_elem;
663 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_fe_d_dofdotdot_elem;
664 std::vector<double> last_rate_dissipated_energy;
665 std::vector<double> dissipated_energy;
666 double global_last_rate_dissipated_energy;
667 double global_dissipated_energy;
668 double rayleigh_damping_alpha;
669 double rayleigh_damping_beta;
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
GenericException< TypeError_name > TypeError
Definition b2exception.H:325
Definition b2solution.H:71