21#ifndef B2FREQUENCY_DEPENDENT_FREE_VIBRATION_SOLVER_H_
22#define B2FREQUENCY_DEPENDENT_FREE_VIBRATION_SOLVER_H_
24#include "b2ppconfig.h"
27#include "model/b2element.H"
30#include "solvers/b2free_vibration_solver.H"
36namespace b2000::solver {
38template <
typename T,
typename MATRIX_FORMAT>
39class FrequencyDependentFreeVibrationSolver :
public Solver {
41 using eig_matrix_type = eigen_matrix_type<T, MATRIX_FORMAT>;
42 using ebc_t = TypedEssentialBoundaryCondition<T>;
43 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
44 using type_t = ObjectTypeComplete<FrequencyDependentFreeVibrationSolver, Solver::type_t>;
46 void solve()
override {
47 while (solve_iteration()) { ; }
50 bool solve_iteration()
override {
52 if (case_iterator_.get() ==
nullptr) {
55 case_ = case_iterator_->next();
61 <<
" but the free vibration solver only handle a case with one stage of size "
62 "equal to one. The specified stage size is ignored."
69 <<
" but the free vibration solver only handle a case with one stage of size "
70 "equal to one. The extra stages are ignored."
73 solve_on_case(*
case_);
82 void solve_on_case(Case&
case_);
87 b2linalg::Vector<T, b2linalg::Vdense> eigenvalues_;
89 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvectors_;
92 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
93 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& M_augm,
94 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R,
95 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_L) {
99 K_augm.set_zero_same_struct();
100 M_augm.set_zero_same_struct();
102 Domain::element_iterator i = domain.get_element_iterator();
103 b2linalg::Index index;
104 std::vector<bool> d_value_d_dof_flags(3);
105 d_value_d_dof_flags[0] = d_value_d_dof_flags[2] =
true;
106 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_value_d_dof(3);
108 for (Element* e = i->next(); e !=
nullptr; e = i->next()) {
109 d_value_d_dof[0].resize(index.size(), index.size());
110 d_value_d_dof[2].resize(index.size(), index.size());
111 if (
auto te =
dynamic_cast<TypedElement<T>*
>(e); te !=
nullptr) {
118 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
121 index, b2linalg::Vector<T, b2linalg::Vdense>::null, d_value_d_dof_flags,
122 d_value_d_dof, b2linalg::Vector<T, b2linalg::Vdense>::null);
124 K_augm += trans_R * StructuredMatrix(number_of_dof, index, d_value_d_dof[0])
125 * transposed(trans_R);
126 M_augm += trans_R * StructuredMatrix(number_of_dof, index, d_value_d_dof[2])
127 * transposed(trans_R);
129 b2linalg::Matrix<T> tmp_element(d_value_d_dof[0]);
131 << logging::DBName(
"ELSV", 0, e->get_object_name()) << tmp_element
132 <<
" of element id " << e->get_object_name() << logging::LOGFLUSH;
133 tmp_element = d_value_d_dof[2];
135 << logging::DBName(
"ELSV", 2, e->get_object_name()) << tmp_element
136 <<
" of element id " << e->get_object_name() << logging::LOGFLUSH;
141 b2linalg::Interval(trans_R.size1(), K_augm.size1()),
142 b2linalg::Interval(0, trans_R.size1())) +=
143 b2linalg::transposed(trans_L) * b2linalg::transposed(trans_R);
147template <
typename T,
typename MATRIX_FORMAT>
148typename FrequencyDependentFreeVibrationSolver<T, MATRIX_FORMAT>::type_t
149 FrequencyDependentFreeVibrationSolver<T, MATRIX_FORMAT>::type(
150 "FrequencyDependentFreeVibrationSolver", type_name<T, MATRIX_FORMAT>(),
151 StringList(
"FREQUENCY_DEPENDENT_FREE_VIBRATION"), module, &Solver::type);
207template <
typename T,
typename MATRIX_FORMAT>
208void b2000::solver::FrequencyDependentFreeVibrationSolver<T, MATRIX_FORMAT>::solve_on_case(
210 logger << logging::info <<
"Start the frequency dependent free vibration solver"
211 << logging::LOGFLUSH;
213 model_->set_case(case_);
215 Domain& domain = model_->get_domain();
216 SolutionFreeVibration<T>* solution =
217 &
dynamic_cast<SolutionFreeVibration<T>&
>(model_->get_solution());
219 TypeError() <<
"The solver only accepts solutions of type "
220 "SolutionFreeVibration<T>"
227 solution->which_modes(nb_eigenmodes_, which, sigma, sigma_max);
229 double tol_exact_value = case_.get_double(
"TOL", 0.0000001);
230 double tol_predictor_value = case_.get_double(
"TOL_PREDICTOR", 0.01);
233 size_t number_of_dof = domain.get_number_of_dof();
236 mrbc_t* mrbc = &
dynamic_cast<mrbc_t&
>(
237 model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
238 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
240 b2linalg::Vector<T, b2linalg::Vdense> r(number_of_dof);
241 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_R;
242 mrbc->get_linear_value(r, trans_R);
246 &
dynamic_cast<ebc_t&
>(model_->get_essential_boundary_condition(ebc_t::type.get_subtype(
247 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
248 b2linalg::Vector<T, b2linalg::Vdense> l(dbc->get_size(
true));
249 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_L;
250 dbc->get_linear_value(l, trans_L);
252 size_t K_augm_size = trans_R.size1() + trans_L.size2();
253 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm(
254 K_augm_size, domain.get_dof_connectivity_type(), case_);
255 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> M_augm(
256 K_augm_size, domain.get_dof_connectivity_type(), case_);
258 logger << logging::info
259 <<
"Compute an approximation of all the required modes with spectral shift value = "
260 <<
sqrt(sigma) / T(2 * M_PIl) <<
"." << logging::LOGFLUSH;
267 compute_K_and_M(K_augm, M_augm, trans_R, trans_L);
269 eigenvalues_.resize(nb_eigenmodes_);
270 eigenvectors_.resize(number_of_dof, nb_eigenmodes_);
271 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvectors_red;
272 eigenvectors_red = eigenvector(
273 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B, eigenvalues_, which, sigma);
277 while (mode != nb_eigenmodes_) {
278 T local_sigma = eigenvalues_[mode];
280 logger << logging::info <<
"Start to compute the exact (frequency dependent) mode " << mode
281 <<
" with the spectral shift value " <<
sqrt(local_sigma) / T(2 * M_PIl) <<
"."
282 << logging::LOGFLUSH;
284 T previous_eigenvalue;
285 b2linalg::Vector<T, b2linalg::Vdense> current_eigenvalue(1);
286 current_eigenvalue[0] = eigenvalues_[mode];
287 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvector_red;
289 b2linalg::Vector<T, b2linalg::Vdense> restart_eigenvector;
290 restart_eigenvector = eigenvectors_red[mode];
298 logger << logging::info <<
"Update the domain frequency to "
299 <<
sqrt(current_eigenvalue[0]) / T(2 * M_PIl) << logging::LOGFLUSH;
302 case_.set(
"FREQ_INIT",
sqrt(current_eigenvalue[0]) / T(2 * M_PIl));
303 domain.set_case(case_);
306 compute_K_and_M(K_augm, M_augm, trans_R, trans_L);
308 previous_eigenvalue = current_eigenvalue[0];
312 eigenvector_red = eigenvector(
313 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B,
314 current_eigenvalue,
"SM", local_sigma, ncv, -1, -1, restart_eigenvector);
315 restart_eigenvector = eigenvector_red[0];
316 local_sigma = current_eigenvalue[0];
318 }
catch (Exception& e) {
319 ncv = std::min(32, ncv * 2);
320 logger << logging::info <<
"The current_eigenvalue solver cannot converge ("
322 <<
"). Retry by increasing the number of Lanczos basis vectors (ncv="
323 << ncv <<
"." << logging::LOGFLUSH;
327 logger << logging::info <<
"Frequency residue = "
328 << std::abs(current_eigenvalue[0] - previous_eigenvalue)
329 / std::abs(current_eigenvalue[0])
330 << logging::LOGFLUSH;
331 }
while (std::abs(current_eigenvalue[0]) > tol_exact_value
332 && (std::abs(current_eigenvalue[0] - previous_eigenvalue)
333 / std::abs(current_eigenvalue[0])
336 if (std::abs(eigenvalues_[mode] - current_eigenvalue[0]) / std::abs(current_eigenvalue[0])
337 > tol_predictor_value) {
338 logger << logging::info
339 <<
"The approximation of all the required modes is too far from the exact "
340 "computed mode, update the approximation with the domain frequency equal to "
341 <<
sqrt(current_eigenvalue[0]) / T(2 * M_PIl) << logging::LOGFLUSH;
343 eigenvectors_red = eigenvector(
344 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B, eigenvalues_, which,
347 if (std::abs(eigenvalues_[mode] - current_eigenvalue[0])
348 / std::abs(current_eigenvalue[0])
350 logger << logging::info
351 <<
"The exact computed mode is a jump to an other mode, restart the "
352 "computation from the mode "
353 << mode <<
"." << logging::LOGFLUSH;
358 logger << logging::info <<
"End of computation of the mode " << mode
359 <<
". Eigenfrequency = " <<
sqrt(current_eigenvalue[0]) / T(2 * M_PIl) <<
"."
360 << logging::LOGFLUSH;
363 eigenvectors_[mode] = transposed(trans_R) * eigenvector_red[0];
366 solution->set_mode(mode, current_eigenvalue[0], eigenvectors_[mode]);
373 solution->terminate_case(
true, attributes);
374 case_.warn_on_non_used_key();
376 logger << logging::info <<
"End of frequency dependent free vibration solver"
377 << logging::LOGFLUSH;
csda< T > sqrt(const csda< T > &a)
Square root of a csda number.
Definition b2csda.H:396
#define THROW
Definition b2exception.H:198
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
virtual size_t get_number_of_dof() const =0
virtual CaseList & get_case_list()=0
virtual Domain & get_domain()=0
Case * case_
This also.
Definition b2solver.H:93
Model * model_
Definition b2solver.H:91
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
GenericException< TypeError_name > TypeError
Definition b2exception.H:325