b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2typed_solver.H
1//------------------------------------------------------------------------
2// b2typed_solver.H --
3//
4//
5// written by Neda Ebrahimi Pour <neda.ebrahimipour@dlr.de>
6// Harald Klimach <harald.klimach@dlr.de>
7// Thomas Blome <thomas.blome@dlr.de>
8//
9// (c) 2004-2012 SMR Engineering & Development SA
10// 2502 Bienne, Switzerland
11//
12// (c) 2023 Deutsches Zentrum für Luft- und Raumfahrt (DLR) e.V.
13// Linder Höhe, 51147 Köln
14//
15// All Rights Reserved. Proprietary source code. The contents of
16// this file may not be disclosed to third parties, copied or
17// duplicated in any form, in whole or in part, without the prior
18// written permission of SMR.
19//------------------------------------------------------------------------
20
21#ifndef B2TYPED_SOLVER_H_
22#define B2TYPED_SOLVER_H_
23
24#include <atomic>
25#include <memory>
26#include <type_traits>
27
28#include "b2ppconfig.h"
29// #include "model/b2boundary_condition.H"
30#include "io/b2000_db/b2000_db_v3/b2solution_database.H"
31#include "model/b2solution.H"
32#include "model/b2solver.H"
33#include "model_imp/b2monolithic_boundary_conditions.H"
34#include "time_integration/b2time_integrator.H"
35#include "utils/b2logging.H"
36#include "utils/b2object.H"
37#include "utils/b2timing.H"
38
39#ifdef HAVE_LIB_TBB
40#include "utils/b2threading.H"
41#endif
42
43namespace b2000::solver {
44
45template <typename T, typename MATRIX_FORMAT>
46class TypedSolver : public Solver {
47public:
48 // using mrbc_t = TypedModelReductionBoundaryCondition<T>;
49 using EssentialBoundaryConditionPointer =
50 std::unique_ptr<MonolithicEssentialBoundaryConditions<T>>;
51 using NaturalBoundaryConditionPointer =
52 std::unique_ptr<MonolithicNaturalBoundaryConditions<T, MATRIX_FORMAT>>;
53 using type_t = ObjectTypeIncomplete<TypedSolver, Solver::type_t>;
54
56 using type_scalar = T;
57 using type_matrix = MATRIX_FORMAT;
58
59 void solve() override = 0;
60
61 const auto& GetDof() const { return dof_; }
62
63 const auto& GetKeff() const { return K_eff_; }
64
65 const auto& GetFeff() const { return F_eff_; }
66
67 auto GetTimeIntegrator() const { return time_integrator_; }
68
69 static type_t type;
70
71protected:
75 enum class b2Task {
76 assemble_mass_matrix,
77 assemble_effective_system,
78 assemble_effective_matrix,
79 assemble_effective_vector,
80 compute_gradients,
81 compute_J_integral,
82 update_internal_variables,
83 compute_error,
84 };
85
89 virtual void InitializeSolverOnCase() override;
90
91 bool solve_iteration() override = 0;
92
95 void MainLoopOverElements(const b2Task task);
96
98 void SetSolutionFieldsToZero();
99
101 void SolveEffectiveSystem();
102
104
112 b2linalg::Matrix<T, b2linalg::Mrectangle> dof_{};
113
120 b2linalg::Matrix<T, b2linalg::Mrectangle> dU_{};
121
122 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>
123 K_eff_{};
124 b2linalg::Vector<T, b2linalg::Vdense> F_eff_{};
125
126 EssentialBoundaryConditionPointer essential_boundary_conditions_{};
127 NaturalBoundaryConditionPointer natural_boundary_conditions_{};
128
131 std::shared_ptr<TimeIntegrator<T>> time_integrator_{};
132 std::shared_ptr<TimeIntegrator<T>> corrector_{};
133
138 std::vector<int> fixed_dof_{};
139
140 T reduced_scalar_value{};
141
143 SolutionMonolithic<T>* solution_{nullptr};
144
145private:
147 enum class NewtonMethod { conventional, modified, delayed_modified, modified_postponed };
148
157 void IterateOverElements(auto& elements, auto func, auto timer, std::string_view log);
158
169 void SeriallyIterateOverElements(auto& elements, auto func, auto timer, std::string_view log);
170
183 void IterateOverElementsParallelReduction(
184 auto& elements, auto func, auto reduction, T identity, auto timer, std::string_view log);
185
191 void AllocateAndAssembleEffectiveSystem(std::vector<std::reference_wrapper<Element>>& elements);
192
196 void AssembleEffectiveSystem(TypedElement<T>& element);
197
200 void AssembleEffectiveMatrix(TypedElement<T>& element);
201
204 void AssembleEffectiveVector(TypedElement<T>& element);
205
209 void ComputeGradients(TypedElement<T>& element, GradientContainer* const gradient_container);
210
215 void ComputeError(
216 std::vector<std::reference_wrapper<Element>>& elements, auto timer, std::string_view log);
217};
218
219template <typename T, typename MATRIX_FORMAT>
220void TypedSolver<T, MATRIX_FORMAT>::InitializeSolverOnCase() {
221 // if (case_iterator_.get() == nullptr)
222 // case_iterator_ = model_->get_case_list().get_case_iterator();
223
224 // case_ = case_iterator_->next();
225 // if (case_ == nullptr) return;
226
227 // if (case_->get_number_of_stage() == 0)
228 // Exception() << "The monolithic solver must have a case that contains
229 // at least "
230 // "one stage but the case "
231 // << case_->get_id() << " does not have a stage." << THROW;
232
234
235 solution_ = &dynamic_cast<SolutionMonolithic<T>&>(model_->get_solution());
236
237 // const AttributeList& attribute = *case_;
238 // std::string analysis = case_->get_string("ANALYSIS", "LINEAR");
239
240 essential_boundary_conditions_ = std::make_unique<MonolithicEssentialBoundaryConditions<T>>();
241 natural_boundary_conditions_ =
242 std::make_unique<MonolithicNaturalBoundaryConditions<T, MATRIX_FORMAT>>();
243 // model_->InitializeMonolithicEssentialBoundaryConditions(*case_);
244
245 number_of_fixed_dof_ =
246 essential_boundary_conditions_->InitializeEssentialBoundaryConditions(*model_);
247 natural_boundary_conditions_->InitializeNaturalBoundaryConditions(*model_, *case_);
248
249 // mrbc_t& mrbc = dynamic_cast<mrbc_t&>(
250 // model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
251 // "TypedModelReductionBoundaryConditionListComponent" +
252 // type_name<T>())));
253
254 // b2linalg::Matrix<T, b2linalg::Mrectangle> dof_red(
255 // mrbc.get_size(false, b2linalg::Vector<T, b2linalg::Vdense>::null,
256 // time_), dof_.size2());
257 // mrbc.get_nonlinear_inverse_value(dof_, time_, dof_red);
258
259 // mrbc.InitializeEssentialBoundaryConditions(fixed_dof_, dof_);
260
261 effective_num_dof_ = total_num_dof_ - number_of_fixed_dof_;
262
264 fixed_dof_.resize(total_num_dof_);
265 std::iota(fixed_dof_.begin(), fixed_dof_.end(), 0);
266
268 size_t columns{1};
269 // if (is_dynamic_) {
270 // columns = 3; //!< Displacements & velocities and accelerations.
271 // } else if (is_damped_) {
272 // columns = 2; //!< Displacements & velocities.
273 // }
274
276 F_eff_.reset(effective_num_dof_);
277
278 dof_.resize(total_num_dof_, columns);
279 dU_.resize(total_num_dof_, 2);
280
281 dU_.set_zero();
282 dof_.set_zero();
284 K_eff_.set_zero();
285}
286
287template <typename T, typename MATRIX_FORMAT>
288void TypedSolver<T, MATRIX_FORMAT>::IterateOverElements(
289 auto& elements, auto func, auto timer, std::string_view log) {
291 logging::Logger& logger = logging::get_logger("solver.monolithic");
292
293 logger << logging::info << "Starting to " << log << logging::LOGFLUSH;
294
295 (*timer).second.start();
296#ifdef HAVE_LIB_TBB
297 // tbb::combinable<T> private_value;
298 // T reduced_scalar_value{};
299
300 // Optionally, specify a partitioner as last argument
301 tbb::parallel_for(static_cast<size_t>(0), elements.size(), func);
302#else
303 // std::unique_ptr<Domain::ElementIterator> i =
304 // domain.get_element_iterator(); Func b2task(*this, elements, task);
305
306 // for (Element* element = i->next(); element != 0; element = i->next()) {
307 for (size_t i{}; i < elements.size(); ++i) { func(i); }
308#endif
309 (*timer).second.stop();
310
311 logger << logging::info << "Finished to " << log << logging::LOGFLUSH;
312}
313
314template <typename T, typename MATRIX_FORMAT>
315void TypedSolver<T, MATRIX_FORMAT>::SeriallyIterateOverElements(
316 auto& elements, auto func, auto timer, std::string_view log) {
317 logging::Logger& logger = logging::get_logger("solver.monolithic");
318
319 logger << logging::info << "Serially Starting to " << log << logging::LOGFLUSH;
320
321 (*timer).second.start();
322 for (size_t i{}; i < elements.size(); ++i) { func(i); }
323 (*timer).second.stop();
324
325 logger << logging::info << "Serially Finished to " << log << logging::LOGFLUSH;
326}
327
328#ifdef HAVE_LIB_TBB
329template <typename T, typename MATRIX_FORMAT>
330void TypedSolver<T, MATRIX_FORMAT>::IterateOverElementsParallelReduction(
331 auto& elements, auto func, auto reduction, T identity, auto timer, std::string_view log) {
334 logging::Logger& logger = logging::get_logger("solver.monolithic");
335
336 logger << logging::info << "Starting to " << log << logging::LOGFLUSH;
337
338 (*timer).second.start();
339 reduced_scalar_value = tbb::parallel_reduce(
340 tbb::blocked_range<size_t>(0, elements.size()), identity, func, reduction);
341 (*timer).second.stop();
342
343 logger << logging::info << "Finished to " << log << logging::LOGFLUSH;
344}
345#endif
346
347template <typename T, typename MATRIX_FORMAT>
348void TypedSolver<T, MATRIX_FORMAT>::MainLoopOverElements(const b2Task task) {
349 // domain.set_dof(dof);
350 // b2linalg::Index index;
351 //
352 // Domain& domain = model_->get_domain();
353 auto& elements = model_->get_domain().GetElementContainer();
354
355 // using test = void (TypedSolver<T,
356 // MATRIX_FORMAT>::*methodPtr)(TypedElement<T>&);
357
358 // std::function<void(TypedSolver<T, MATRIX_FORMAT>, TypedElement<T> &
359 // element)> f1{
360 // &TypedSolver<T, MATRIX_FORMAT>::AssembleEffectiveMatrix};
361
362 // void (TypedSolver<T, MATRIX_FORMAT>::*methodPtr)(TypedElement<T>&){
363 // &TypedSolver<T, MATRIX_FORMAT>::AssembleEffectiveMatrix};
364
365 // b2000::b2dbv3::Domain& domain_test =
366 // dynamic_cast<b2dbv3::Domain&>(model->get_domain());
367 // b2000::Domain& b2_domain = dynamic_cast<b2000::Domain&>(domain);
368
374 switch (task) {
375 case (b2Task::assemble_mass_matrix): {
376 auto time_assemble_mass_mat = obtain_timer("solver_assemble_mass_mat");
378 break;
379 }
380 // clang-format off
381 [[likely]] case (b2Task::assemble_effective_system):
383 if (K_eff_.size1() == 0) {
384 AllocateAndAssembleEffectiveSystem(elements);
385 } else {
387 IterateOverElements(
388 elements,
389 [this, &elements](const size_t i) {
390 AssembleEffectiveSystem(dynamic_cast<TypedElement<T>&>(elements[i].get()));
391 },
392 obtain_timer("solver_assemble_eff_sys"), "assemble the effective system");
393 }
394
395 break;
396 // clang-format on
397
398 case (b2Task::assemble_effective_matrix):
399 IterateOverElements(
400 elements,
401 [this, &elements](const size_t i) {
402 AssembleEffectiveMatrix(dynamic_cast<TypedElement<T>&>(elements[i].get()));
403 },
404 obtain_timer("solver_assemble_eff_mat"), "assemble the effective matrix");
405
406 break;
407
408 case (b2Task::assemble_effective_vector):
409 IterateOverElements(
410 elements,
411 [this, &elements](const size_t i) {
412 AssembleEffectiveVector(dynamic_cast<TypedElement<T>&>(elements[i].get()));
413 },
414 obtain_timer("solver_assemble_eff_vec"), "assemble the effective vector");
415
416 break;
417
418 case (b2Task::compute_gradients): // post-processing
419 {
421 auto container = solution_->get_gradient_container();
422 GradientContainer* gradients = container.get();
423
424 IterateOverElements(
425 elements,
426 [this, &elements, gradients](const size_t i) {
427 ComputeGradients(
428 dynamic_cast<TypedElement<T>&>(elements[i].get()), gradients);
429 },
430 obtain_timer("compute_gradients"), "compute the gradients");
431
432 break;
433 }
434
435 case (b2Task::compute_J_integral): {
436 // logger << logging::info << "Starting to compute the J integral
437 // for the solver"
438 // << logging::LOGFLUSH;
439
440 auto time_comp_j_integral = obtain_timer("solver_comp_j_integral");
442 break;
443 }
444
445 case (b2Task::update_internal_variables): {
446 // logger << logging::info << "Starting to update the internal
447 // variables for the solver"
448 // << logging::LOGFLUSH;
449
450 auto time_update_inter_var = obtain_timer("solver_update_inter_var");
452 break;
453 }
454
455 case (b2Task::compute_error):
456 ComputeError(elements, obtain_timer("solver_comp_err"), "update the error");
457 break;
458
459 default:
460 // Hier Error oder Exception;
461 break;
462 }
463}
464
465template <typename T, typename MATRIX_FORMAT>
466void TypedSolver<T, MATRIX_FORMAT>::AllocateAndAssembleEffectiveSystem(
467 std::vector<std::reference_wrapper<Element>>& elements) {
469 K_eff_.resize(effective_num_dof_, model_->get_domain().get_dof_connectivity_type(), *case_);
470
471#ifdef HAVE_LIB_TBB
472 using my_mutex_t = tbb::spin_mutex;
473 std::vector<my_mutex_t> row_blocker(effective_num_dof_);
474#endif
476 std::vector<std::map<size_t, T>> row_contributions(effective_num_dof_);
477
478 logging::Logger& logger = logging::get_logger("solver.monolithic");
479 auto timer = obtain_timer("solver_allocate_eff_sys");
480
481 auto ElementLoop = [&](size_t i) {
482 auto& element{dynamic_cast<TypedElement<T>&>(elements[i].get())};
483
485 b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> k_eff;
486 b2linalg::Vector<T, b2linalg::Vdense> f_eff;
487 b2linalg::Index index;
488
489 element.AssembleElementEffectiveSystem(*this, k_eff, f_eff, index);
490
492 f_eff = -f_eff;
493
495 size_t N{index.size()};
496 bool swapped{};
497 int global_index_i{};
498 int global_index_j{};
499 for (size_t i{}; i < N; ++i) {
500 global_index_i = fixed_dof_[index[i]];
501
503 if (global_index_i < 0) { continue; }
504
506 // size_t j{};
507 // if constexpr (std::is_same_v<MATRIX_FORMAT, b2linalg::Msymmetric>) {
508 // j = i; //!< Fill only "half" of the matrix in case of symmetry.
509 // }
510 for (size_t j{}; j < N; ++j) {
511 global_index_j = fixed_dof_[index[j]];
512
513 if (global_index_j < 0) {
515 if (k_eff(i, j) != T{}) { f_eff[i] -= k_eff(i, j) * dU_(index[j], 0); }
516 } else {
517 if constexpr (std::is_same_v<MATRIX_FORMAT, b2linalg::Msymmetric>) {
518 if (j < i) { continue; }
519
521 if (global_index_j < global_index_i) {
522 std::swap(global_index_i, global_index_j);
523 swapped = true;
524 }
525 }
526
527#ifdef HAVE_LIB_TBB
528 my_mutex_t::scoped_lock row_lock{row_blocker[global_index_i]};
529#endif
530 row_contributions[global_index_i][global_index_j] += k_eff(i, j);
531
533 if constexpr (std::is_same_v<MATRIX_FORMAT, b2linalg::Msymmetric>) {
534 if (swapped) {
535 std::swap(global_index_i, global_index_j);
536 swapped = false;
537 }
538 }
539 }
540 }
541
542#ifdef HAVE_LIB_TBB
543 std::atomic_ref<T> atomic_T{F_eff_[global_index_i]};
544 atomic_T += f_eff[i];
545#else
546 F_eff_[global_index_i] += f_eff[i];
547#endif
548 }
549 };
550
552 logger << logging::info << "Starting to allocate the system matrix" << logging::LOGFLUSH;
553 (*timer).second.start();
554#ifdef HAVE_LIB_TBB
555 tbb::parallel_for(static_cast<size_t>(0), elements.size(), ElementLoop);
556#else
557 for (size_t i{}; i != elements.size(); ++i) { ElementLoop(i); }
558#endif
559 (*timer).second.stop();
560 logger << logging::info << "Finished to allocate the system matrix" << logging::LOGFLUSH;
561
562 timer = obtain_timer("solver_assemble_eff_sys");
563
564 auto RowLoop = [&](size_t row) { K_eff_.InitializeRow(row, row_contributions[row]); };
565
567 logger << logging::info << "Starting to assemble the system matrix" << logging::LOGFLUSH;
568 (*timer).second.start();
569#ifdef HAVE_LIB_TBB
570 tbb::parallel_for(static_cast<size_t>(0), effective_num_dof_, RowLoop);
571#else
572 for (size_t row{}; row < effective_num_dof_; ++row) { RowLoop(row); }
573#endif
574 (*timer).second.stop();
575 logger << logging::info << "Finished to assemble the system matrix" << logging::LOGFLUSH;
576}
577
578template <typename T, typename MATRIX_FORMAT>
579void TypedSolver<T, MATRIX_FORMAT>::AssembleEffectiveSystem(TypedElement<T>& element) {
580 // domain.set_dof(dof);
581
583 b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> k_eff;
584 b2linalg::Vector<T, b2linalg::Vdense> f_eff;
585 b2linalg::Index index;
586
587 element.AssembleElementEffectiveSystem(*this, k_eff, f_eff, index);
588
590 f_eff = -f_eff;
591
593 size_t N{index.size()};
594 int global_index_i{};
595 int global_index_j{};
596 for (size_t i{}; i != N; ++i) {
597 global_index_i = fixed_dof_[index[i]];
598 if (global_index_i < 0) {
599 continue;
600 }
601
603 for (size_t j{}; j < N; ++j) {
604 global_index_j = fixed_dof_[index[j]];
605
606 if (global_index_j < 0) {
607 if (k_eff(i, j) != T{}) { f_eff[i] -= k_eff(i, j) * dU_(index[j], 0); }
608 } else {
609 if constexpr (std::is_same_v<MATRIX_FORMAT, b2linalg::Msymmetric>) {
610 if (j < i) { continue; }
611 }
612
613#ifdef HAVE_LIB_TBB
614 std::atomic_ref<T> atomic_U{K_eff_(global_index_i, global_index_j)};
615 atomic_U += k_eff(i, j);
616#else
618 K_eff_(global_index_i, global_index_j) += k_eff(i, j);
619#endif
620 }
621 }
622
623#ifdef HAVE_LIB_TBB
624 std::atomic_ref<T> atomic_T{F_eff_[global_index_i]};
625 atomic_T += f_eff[i];
626#else
627 F_eff_[global_index_i] += f_eff[i];
628#endif
629 }
630}
631
632template <typename T, typename MATRIX_FORMAT>
633void TypedSolver<T, MATRIX_FORMAT>::AssembleEffectiveMatrix(TypedElement<T>& element) {
634 // domain.set_dof(dof);
635 // b2linalg::Index index;
636
637 b2linalg::Matrix<T, typename MATRIX_FORMAT::dense>
638 k_eff;
639 b2linalg::Index index;
640
641 k_eff = element.AssembleElementEffectiveMatrix(*this, index);
642
643 // K_eff_ += StructuredMatrix(total_num_dof_, index, k_eff); //!< Atomic
644 // operation.
645}
646
647template <typename T, typename MATRIX_FORMAT>
648void TypedSolver<T, MATRIX_FORMAT>::AssembleEffectiveVector(TypedElement<T>& element) {
649 // domain.set_dof(dof);
650 // b2linalg::Index index;
651
652 // Element array to calculate and to store into global array
653 b2linalg::Vector<T, b2linalg::Vdense> f_eff; // or Vdense_ref ??? (TB)
654 b2linalg::Index index;
655
656 f_eff = element.AssembleElementEffectiveVector(*this, index);
657
658 // This method requires some form of atomic operation for TBB, as this will
659 // be a critical section.
660}
661
662template <typename T, typename MATRIX_FORMAT>
663inline void TypedSolver<T, MATRIX_FORMAT>::ComputeGradients(
664 TypedElement<T>& element, GradientContainer* const gradient_container) {
665 gradient_container->set_current_element(element);
666
667 element.ComputeElementGradient(*this, gradient_container);
668}
669
670template <typename T, typename MATRIX_FORMAT>
671inline void TypedSolver<T, MATRIX_FORMAT>::ComputeError(
672 std::vector<std::reference_wrapper<Element>>& elements, auto timer, std::string_view log) {
673#ifdef HAVE_LIB_TBB
674 IterateOverElementsParallelReduction(
675 elements,
679 [this, &elements](const tbb::blocked_range<size_t>& r, T init) -> T {
680 for (size_t i{r.begin()}; i != r.end(); ++i) {
681 init = std::max(
682 init, (dynamic_cast<TypedElement<T>&>(elements[i].get()))
683 .ComputeElementError(*this));
684 }
685
686 return init;
687 },
688 [](T x, T y) { return std::max(x, y); },
689 T{},
690 timer, log);
691#else
693 IterateOverElements(
694 elements,
695 [this, &elements](const size_t i) {
696 reduced_scalar_value = std::max(
697 reduced_scalar_value,
698 dynamic_cast<TypedElement<T>&>(elements[i].get()).ComputeElementError(*this));
699 },
700 timer, log);
701#endif
702}
703
704template <typename T, typename MATRIX_FORMAT>
705inline void TypedSolver<T, MATRIX_FORMAT>::SetSolutionFieldsToZero() {
706 auto SetdUToZero{[&](size_t i) { dU_(i, 0) = 0; }};
707
708#ifdef HAVE_LIB_TBB
709 tbb::parallel_for(static_cast<size_t>(0), dof_.size1(), SetdUToZero);
710#else
711 for (size_t i{}; i < dof_.size1(); ++i) { SetdUToZero(i); }
712#endif
713
714 K_eff_.set_zero_same_struct();
715 F_eff_.set_zero();
716}
717
718template <typename T, typename MATRIX_FORMAT>
719void TypedSolver<T, MATRIX_FORMAT>::SolveEffectiveSystem() {
720 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
721 b2linalg::SingularMatrixError ee;
722 bool is_singular = false;
723
724 const int nbnsv = case_->get_int("COMPUTE_NULL_SPACE_VECTOR", 0);
725
726 K_eff_.remove_zero();
727
728 try {
729 logging::Logger& logger = logging::get_logger("solver.monolithic");
730 logger << logging::info << "Starting to solve the effective system" << logging::LOGFLUSH;
731
734 F_eff_ = inverse(K_eff_, nks_r, nbnsv) * F_eff_;
735
736 logger << logging::info << "Finished to solve the effective system" << logging::LOGFLUSH;
737 } catch (b2linalg::SingularMatrixError& e) {
738 ee = e;
739 is_singular = true;
740
741 if (!e.singular_dofs.empty()) {
742 if (nks_r.size2() == 0) {
743 nks_r.resize(effective_num_dof_, 1);
744 nks_r.set_zero();
745 }
746 for (auto i : e.singular_dofs) {
747 assert(i < nks_r.size1());
748 for (size_t j{}; j != nks_r.size2(); ++j) { nks_r(i, j) = T(1); }
749 }
750 }
751 }
752}
753
754template <typename T, typename MATRIX_FORMAT>
755typename TypedSolver<T, MATRIX_FORMAT>::type_t TypedSolver<T, MATRIX_FORMAT>::type(
756 "TypedSolver", type_name<T, MATRIX_FORMAT>(), StringList("TypedSolver"),
757 b2000::solver::module, &Solver::type);
758
759} // namespace b2000::solver
760
761#endif // B2TYPED_SOLVER_H_
csda< T > log(const csda< T > &a)
Natural logarithm of a csda number.
Definition b2csda.H:366
Interface to C++ representations of FE solvers.
virtual void InitializeSolverOnCase()
Initializes the member variables of class Solver for the case at hand.
Definition b2solver.H:116
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
timer_map_t::iterator obtain_timer(std::string name)
Definition b2timing.H:139