21#ifndef B2FREE_VIBRATION_SOLVER_H_
22#define B2FREE_VIBRATION_SOLVER_H_
26#include "b2ppconfig.h"
29#include "model/b2element.H"
38namespace b2000::solver {
40template <
typename T,
typename MATRIX_FORMAT>
41struct EigenDecompDense {
43 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
44 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& M_augm,
45 const std::string& which, b2linalg::Vector<T, b2linalg::Vdense>& eigenvalue,
46 b2linalg::Matrix<T, b2linalg::Mrectangle>& eigenvector) {
51template <
typename MATRIX_FORMAT>
52struct EigenDecompDense<double, MATRIX_FORMAT> {
54 b2linalg::Matrix<double, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
55 b2linalg::Matrix<double, typename MATRIX_FORMAT::sparse_inversible>& M_augm,
56 const std::string& which, b2linalg::Vector<double, b2linalg::Vdense>& eigenvalue,
57 b2linalg::Matrix<double, b2linalg::Mrectangle>& eigenvector) {
58 assert(eigenvalue.size() <= K_augm.size1());
61 b2linalg::Matrix<double, b2linalg::Mrectangle> K(K_augm.size1(), K_augm.size2());
62 for (
size_t i = 0; i != K.size1(); ++i) {
63 for (
size_t j = 0; j != K.size2(); ++j) { K(i, j) = K_augm(i, j); }
66 b2linalg::Matrix<double, b2linalg::Mrectangle> M(M_augm.size1(), M_augm.size2());
67 for (
size_t i = 0; i != M.size1(); ++i) {
68 for (
size_t j = 0; j != M.size2(); ++j) { M(i, j) = M_augm(i, j); }
71 const int n = int(K.size1());
72 b2linalg::Vector<double, b2linalg::Vdense> eigvalue_all(n);
73 eigvalue_all.set_zero();
75 std::vector<double> work(2 * (1 + 6 * n + 2 * n * n));
76 std::vector<int> iwork(2 * (3 + 5 * n));
79 1,
'V',
'U', n, &K(0, 0), n, &M(0, 0), n, &eigvalue_all[0], &work[0],
80 int(work.size()), &iwork[0],
int(iwork.size()), info);
83 if (info > 0 && info <= n) {
84 Exception() <<
"Eigendecomposition with lapack routine dsygvd "
87 <<
" off-diagonal elements of an "
88 "intermediate tridiagonal form did not converge to zero."
92 Exception() <<
"Eigendecomposition with lapack routine dsygvd "
95 <<
". leading minor of the "
97 << M.size1() <<
"x" << M.size2()
98 <<
") mass matrix is "
99 "not positive-definite."
103 const size_t o = (which ==
"SM" ? 0 : eigvalue_all.size() - eigenvalue.size());
104 eigenvector.resize(K.size1(), eigenvalue.size());
105 for (
size_t i = 0; i != eigenvalue.size(); ++i) {
106 eigenvalue[i] = eigvalue_all[o + i];
107 eigenvector[i] = K[o + i];
112template <
typename T,
typename MATRIX_FORMAT>
113void eigen_decomposition_dense(
114 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
115 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& M_augm,
116 const std::string& which, b2linalg::Vector<T, b2linalg::Vdense>& eigenvalue,
117 b2linalg::Matrix<T, b2linalg::Mrectangle>& eigenvector) {
118 EigenDecompDense<T, MATRIX_FORMAT> ed;
119 ed.resolve(K_augm, M_augm, which, eigenvalue, eigenvector);
122template <
typename T,
typename MATRIX_FORMAT>
123struct eigen_matrix_type {};
126struct eigen_matrix_type<std::complex<T>, b2linalg::Munsymmetric> {
127 static const char A =
'N';
128 static const char B =
'N';
132struct eigen_matrix_type<T, b2linalg::Msymmetric> {
133 static const char A =
'P';
134 static const char B =
'S';
145template <
typename T,
typename MATRIX_FORMAT>
148 using eig_matrix_type = eigen_matrix_type<T, MATRIX_FORMAT>;
159 if (case_iterator_.get() ==
nullptr) {
162 case_ = case_iterator_->next();
168 <<
" but the free vibration solver only handle a case with"
169 " one stage of size equal to one."
170 " The specified stage size is ignored."
171 << logging::LOGFLUSH;
177 <<
" but the free vibration solver only handle a case with"
178 " one stage of size equal to one. The extra stages are"
180 << logging::LOGFLUSH;
182 solve_on_case(*
case_);
193 size_t nb_eigenmodes_;
195 b2linalg::Vector<T, b2linalg::Vdense> eigenvalues_;
197 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvectors_;
200template <
typename T,
typename MATRIX_FORMAT>
201typename FreeVibrationSolver<T, MATRIX_FORMAT>::type_t FreeVibrationSolver<T, MATRIX_FORMAT>::type(
202 "FreeVibrationSolver", type_name<T, MATRIX_FORMAT>(),
203 StringList(
"FREE_VIBRATION",
"VIBRATION"), module, &Solver::type);
251template <
typename T,
typename MATRIX_FORMAT>
253 logging::Logger& logger = logging::get_logger(
"solver.free_vibration");
255 logger << logging::info <<
"Start the free vibration solver" << logging::LOGFLUSH;
257 model_->set_case(case_);
259 Domain& domain = model_->get_domain();
260 SolutionFreeVibration<T>* solution =
261 &
dynamic_cast<SolutionFreeVibration<T>&
>(model_->get_solution());
263 TypeError() <<
"The solver only accepts a solution of type"
264 <<
" SolutionFreeVibration<T>" <<
THROW;
272 solution->which_modes(n, which, sigma, sigma_max);
274 nb_eigenmodes_ = size_t(n);
276 const std::string constraint_string = case_.get_string(
"CONSTRAINT_METHOD",
"REDUCTION");
278 const std::string matrices_dir = case_.get_string(
"MATRICES_DIR",
"");
279 const bool export_sys_matrices = (matrices_dir !=
"");
281 const size_t number_of_dof = domain.get_number_of_dof();
283 b2linalg::Vector<T, b2linalg::Vdense> dof;
286 std::string domain_state_id;
287 const bool nonline = !model_->get_initial_condition().is_zero();
289 dof.resize(number_of_dof);
290 dynamic_cast<TypedInitialCondition<T>&
>(model_->get_initial_condition())
291 .get_static_initial_condition_value(dof, time, stage, domain_state_id);
292 if (stage != 0) { case_.set_stage(stage); }
293 if (!domain_state_id.empty()) { model_->get_domain().load_state(domain_state_id); }
295 EquilibriumSolution esf(
false);
298 mrbc_t* mrbc = &
dynamic_cast<mrbc_t&
>(
299 model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
300 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
302 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_R;
303 mrbc->get_linear_value(b2linalg::Vector<T, b2linalg::Vdense_ref>::null, trans_R);
307 &
dynamic_cast<ebc_t&
>(model_->get_essential_boundary_condition(ebc_t::type.get_subtype(
308 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
309 b2linalg::Vector<T, b2linalg::Vdense> l(dbc->get_size(
true));
310 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_L;
312 dbc->get_nonlinear_value(
313 dof, time, esf, l, trans_L, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0);
315 dbc->get_linear_value(l, trans_L);
320 b2linalg::Vector<double> trans_L_scale(trans_L.size2());
321 trans_L.scale_col_to_norminf(trans_L_scale);
322 for (
size_t i = 0; i != l.size(); ++i) { l[i] *= trans_L_scale[i]; }
323 trans_L.remove_zero();
326 if (case_.get_bool(
"REMOVE_DEPENDENT_CONSTRAINTS",
true)
327 && (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE")) {
329 trans_L.get_dep_columns(P, 3e-13, 1.5);
332 trans_L.remove_col(P);
333 logger << logging::info <<
"Remove " << P.size() <<
" dependent constraints."
334 << logging::LOGFLUSH;
342 logger << logging::info <<
"Element matrix assembly" << logging::LOGFLUSH;
343 size_t K_augm_size = trans_R.size1() + (constraint_string ==
"PENALTY" ? 0 : trans_L.size2());
344 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm(
345 K_augm_size, domain.get_dof_connectivity_type(), case_);
346 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> M_augm(
347 K_augm_size, domain.get_dof_connectivity_type(), case_);
349 auto Kgg = export_sys_matrices
350 ? b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>(
351 number_of_dof, domain.get_dof_connectivity_type(), case_)
352 : b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>();
353 auto Mgg = export_sys_matrices
354 ? b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>(
355 number_of_dof, domain.get_dof_connectivity_type(), case_)
356 : b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>();
358 domain.set_dof(b2linalg::Vector<T, b2linalg::Vdense_constref>::null);
360 Domain::element_iterator i = domain.get_element_iterator();
361 b2linalg::Index index;
362 std::vector<bool> d_value_d_dof_flags(3);
363 d_value_d_dof_flags[0] = d_value_d_dof_flags[2] =
true;
364 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_value_d_dof(3);
365 const bool log_el_flag = logger.is_enabled_for(logging::data);
366 for (Element* e = i->next(); e !=
nullptr; e = i->next()) {
367 if (
auto te =
dynamic_cast<TypedElement<T>*
>(e); te !=
nullptr) {
373 nonline ? b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(dof)
374 : b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
377 index, b2linalg::Vector<T, b2linalg::Vdense>::null, d_value_d_dof_flags,
378 d_value_d_dof, b2linalg::Vector<T, b2linalg::Vdense>::null);
380 K_augm += trans_R * StructuredMatrix(number_of_dof, index, d_value_d_dof[0])
381 * transposed(trans_R);
382 M_augm += trans_R * StructuredMatrix(number_of_dof, index, d_value_d_dof[2])
383 * transposed(trans_R);
385 if (export_sys_matrices) {
386 Kgg += StructuredMatrix(number_of_dof, index, d_value_d_dof[0]);
387 Mgg += StructuredMatrix(number_of_dof, index, d_value_d_dof[2]);
391 b2linalg::Matrix<T> tmp_element(d_value_d_dof[0]);
392 logger << logging::data <<
"elementary second variation "
393 << logging::DBName(
"ELSV", 0, e->get_object_name()) << tmp_element
394 <<
" of element id " << e->get_object_name() << logging::LOGFLUSH;
395 tmp_element = d_value_d_dof[2];
396 logger << logging::data <<
"elementary mass matrix "
397 << logging::DBName(
"ELSV", 2, e->get_object_name()) << tmp_element
398 <<
" of element id " << e->get_object_name() << logging::LOGFLUSH;
402 logger << logging::info <<
"Element matrix assembly finished" << logging::LOGFLUSH;
404 if (trans_L.size2() > 0) {
405 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
406 trans_LR = trans_R * trans_L;
407 if (constraint_string ==
"PENALTY" || constraint_string ==
"AUGMENTED_LAGRANGE") {
408 const double penalty_factor =
409 case_.get_double(
"CONSTRAINT_PENALTY", constraint_string ==
"PENALTY" ? 1e10 : 1);
410 K_augm += (trans_LR * transposed(trans_LR)) * penalty_factor;
412 if (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE") {
413 const double lagrange_mult_scale = case_.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
414 trans_LR *= lagrange_mult_scale;
415 if (!MATRIX_FORMAT::symmetric) {
417 b2linalg::Interval(0, trans_R.size1()),
418 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
420 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
422 b2linalg::Interval(trans_R.size1(), K_augm_size),
423 b2linalg::Interval(0, trans_R.size1())) += LR;
427 if (logger.is_enabled_for(logging::data)) {
428 logger << logging::data <<
"d_value_d_dof "
429 << logging::DBName(
"D_VALUE_D_DOF.GLOB", 0, 0, case_.get_id()) << K_augm
430 << logging::LOGFLUSH;
431 logger << logging::data <<
"d_value_d_dofdotdot "
432 << logging::DBName(
"D_VALUE_D_ACCELERATION.GLOB", 0, 0, case_.get_id()) << M_augm
433 << logging::LOGFLUSH;
436 if (export_sys_matrices) {
442 std::filesystem::path out_path(matrices_dir);
443 if (std::filesystem::create_directories(out_path)) {
444 logger << logging::info <<
"Created new directory " << matrices_dir
445 << logging::LOGFLUSH;
448 logger << logging::info <<
"Writing system matrices as CSV file(s) to " << out_path
449 << logging::LOGFLUSH;
452 logger << logging::info <<
" - writing "
454 <<
" with (" << K_augm.size1() <<
" x " << K_augm.size2() <<
") DoF"
455 << logging::LOGFLUSH;
456 export_csv(K_augm,
"Kaa", out_path /
"Kaa.csv");
459 logger << logging::info <<
" - writing "
461 <<
" with (" << M_augm.size1() <<
" x " << M_augm.size2() <<
") DoF"
462 << logging::LOGFLUSH;
463 export_csv(M_augm,
"Maa", out_path /
"Maa.csv");
466 logger << logging::info <<
" - writing "
468 <<
" with (" << trans_R.size1() <<
" x " << trans_R.size2() <<
") DoF"
469 << logging::LOGFLUSH;
470 export_csv(trans_R,
"Rtrans", out_path /
"Rtrans.csv");
473 if (trans_L.size2() > 0) {
474 logger << logging::info <<
" - writing "
476 <<
" with (" << trans_L.size1() <<
" x " << trans_L.size2() <<
") DoF"
477 << logging::LOGFLUSH;
478 export_csv(trans_L,
"Ltrans", out_path /
"Ltrans.csv");
480 logger << logging::info <<
" - skipping "
482 <<
" with (" << trans_L.size1() <<
" x " << trans_L.size2() <<
") DoF"
483 << logging::LOGFLUSH;
487 logger << logging::info <<
" - writing "
489 <<
" with (" << Kgg.size1() <<
" x " << Kgg.size2() <<
") DoF" << logging::LOGFLUSH;
490 export_csv(Kgg,
"Kgg", out_path /
"Kgg.csv");
493 logger << logging::info <<
" - writing "
495 <<
" with (" << Mgg.size1() <<
" x " << Mgg.size2() <<
") DoF" << logging::LOGFLUSH;
496 export_csv(Mgg,
"Mgg", out_path /
"Mgg.csv");
499 logger << logging::info <<
"Eigenvalue problem resolution" << logging::LOGFLUSH;
501 if (nb_eigenmodes_ > K_augm.size1()) {
502 Exception() <<
"The number of requested free-vibration modes "
505 <<
") is greater than the size of the "
506 "reduced system of equations ("
507 << K_augm.size1() <<
")." <<
THROW;
509 eigenvalues_.resize(nb_eigenmodes_);
510 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvector_red;
511 if (nb_eigenmodes_ == K_augm.size1() && K_augm.size1() < 100 &&
typeid(T) ==
typeid(
double)
512 && eig_matrix_type::A ==
'P' && eig_matrix_type::B ==
'S' && sigma == T(0)
513 && constraint_string !=
"LAGRANGE" && constraint_string !=
"AUGMENTED_LAGRANGE") {
514 eigen_decomposition_dense<T, MATRIX_FORMAT>(
515 K_augm, M_augm, which, eigenvalues_, eigenvector_red);
517 eigenvector_red = eigenvector(
518 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B, eigenvalues_, which, sigma);
521 eigenvectors_.resize(number_of_dof, nb_eigenmodes_);
522 eigenvectors_ = transposed(trans_R)
524 b2linalg::Interval(0, trans_R.size1()),
525 b2linalg::Interval(0, eigenvector_red.size2()));
527 solution->set_modes(eigenvalues_(b2linalg::Interval(0, eigenvectors_.size2())), eigenvectors_);
529 solution->terminate_case(
true, attributes);
531 case_.warn_on_non_used_key();
533 logger << logging::info <<
"End of free vibration solver" << logging::LOGFLUSH;
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
virtual double get_stage_size(int stage=-1) const =0
virtual std::string get_id() const =0
virtual size_t get_number_of_stage() const =0
Definition b2exception.H:131
virtual CaseList & get_case_list()=0
Definition b2object.H:415
A Solver instance executes an FE analysis. It is created and initialized by the Model instance and,...
Definition b2solver.H:50
Case * case_
This also.
Definition b2solver.H:93
Model * model_
Definition b2solver.H:91
Definition b2boundary_condition.H:198
Definition b2boundary_condition.H:302
A solver to find free vibrations of a system.
Definition b2free_vibration_solver.H:146
void solve() override
This function is usually called by the Model instance.
Definition b2free_vibration_solver.H:153
bool solve_iteration() override
This function is called by the Solver instance itself.
Definition b2free_vibration_solver.H:157
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314