21#ifndef B2LINEARIZE_PREBUCKLING_SOLVER_H_
22#define B2LINEARIZE_PREBUCKLING_SOLVER_H_
24#include "b2ppconfig.h"
25#include "b2solver_utils.H"
28#include "model/b2element.H"
32#include "solvers/b2constraint_util.H"
33#include "utils/b2linear_algebra.H"
37namespace b2000::solver {
39template <
typename T,
typename MATRIX_FORMAT>
40class LinearisedPrebucklingSolver :
public Solver {
42 using nbc_t = TypedNaturalBoundaryCondition<T, typename MATRIX_FORMAT::sparse_inversible>;
43 using ebc_t = TypedEssentialBoundaryCondition<T>;
44 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
45 using type_t = ObjectTypeComplete<LinearisedPrebucklingSolver, Solver::type_t>;
47 void solve()
override {
48 while (solve_iteration()) { ; }
51 bool solve_iteration()
override {
53 if (case_iterator_.get() ==
nullptr) {
56 case_ = case_iterator_->next();
61 <<
"The linearised prebuckling solver cannot hand a case with multiple "
62 "stages. The extra stages are ignored."
65 solve_on_case(*
case_);
74 void solve_on_case(Case&
case_);
75 SolverUtils<T, MATRIX_FORMAT> solver_utile;
77 b2linalg::Vector<T, b2linalg::Vdense> f_;
81 b2linalg::Vector<T, b2linalg::Vdense> eigenvalues_;
83 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvectors_;
86template <
typename T,
typename MATRIX_FORMAT>
87typename LinearisedPrebucklingSolver<T, MATRIX_FORMAT>::type_t
88 LinearisedPrebucklingSolver<T, MATRIX_FORMAT>::type(
89 "LinearisedPrebucklingSolver", type_name<T, MATRIX_FORMAT>(),
90 StringList(
"LINEARISED_PREBUCKLING",
"L_BIFURCATION"), module, &Solver::type);
98template <
typename T,
typename MATRIX_FORMAT>
99void b2000::solver::LinearisedPrebucklingSolver<T, MATRIX_FORMAT>::solve_on_case(Case& case_) {
100 logging::Logger& logger = logging::get_logger(
"solver.linearised_prebuckling");
101 logging::Logger& log_el = logging::get_logger(
"elementary_matrix");
103 if (model_ ==
nullptr) { Exception() <<
THROW; }
106 logger << logging::info <<
"Start the linearised prebuckling solver for the case "
107 << case_.get_id() <<
"." << logging::LOGFLUSH;
108 model_->set_case(case_);
110 logger << logging::info <<
"Assemble the linear problem." << logging::LOGFLUSH;
112 Domain& domain = model_->get_domain();
113 size_t number_of_dof = domain.get_number_of_dof();
114 SolutionLinearisedPrebuckling<T>& solution =
115 dynamic_cast<SolutionLinearisedPrebuckling<T>&
>(model_->get_solution());
119 solution.which_modes(nb_eigenmodes_, which, sigma);
120 double h = case_.get_double(
"DLAMBDA", 0.0001);
121 const int finite_difference_method = case_.get_int(
"FINITE_DIFFERENCE_METHOD", 1);
122 if (sigma == 0) { sigma = h; }
123 const std::string constraint_string = case_.get_string(
"CONSTRAINT_METHOD",
"REDUCTION");
124 const bool compute_rcfo =
125 solution.compute_constraint_value() && (constraint_string ==
"REDUCTION");
128 mrbc_t& mrbc =
dynamic_cast<mrbc_t&
>(
129 model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
130 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
131 b2linalg::Vector<T, b2linalg::Vdense> r(number_of_dof);
132 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_R;
133 mrbc.get_linear_value(r, trans_R);
137 dynamic_cast<ebc_t&
>(model_->get_essential_boundary_condition(ebc_t::type.get_subtype(
138 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
139 b2linalg::Vector<T, b2linalg::Vdense> l(ebc.get_size(
true));
140 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_L;
141 ebc.get_linear_value(l, trans_L);
145 b2linalg::Vector<double> trans_L_scale(trans_L.size2());
146 trans_L.scale_col_to_norminf(trans_L_scale);
147 for (
size_t i = 0; i != l.size(); ++i) { l[i] *= trans_L_scale[i]; }
148 trans_L.remove_zero();
151 if (case_.get_bool(
"REMOVE_DEPENDENT_CONSTRAINTS",
true)
152 && (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE")) {
155 get_dependent_columns(trans_L, P);
158 trans_L.remove_col(P);
159 logger << logging::info <<
"Remove " << P.size() <<
" dependent constraints."
160 << logging::LOGFLUSH;
167 dynamic_cast<nbc_t&
>(model_->get_natural_boundary_condition(nbc_t::type.get_subtype(
168 "TypedNaturalBoundaryConditionListComponent"
169 + type_name<T, typename MATRIX_FORMAT::sparse_inversible>())));
171 f_.resize(number_of_dof);
172 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_e;
173 nbc.get_linear_value(f_, K_e);
174 solution.set_natural_boundary_condition(f_);
176 b2linalg::Vector<T, b2linalg::Vdense> f_reac;
177 if (compute_rcfo) { f_reac = -f_; }
182 logger << logging::info <<
"Element matrix assembly" << logging::LOGFLUSH;
183 size_t K_augm_size = trans_R.size1() + (constraint_string ==
"PENALTY" ? 0 : trans_L.size2());
184 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm(
185 K_augm_size, domain.get_dof_connectivity_type(), case_);
188 solver_utile.get_elements_values(
189 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(r), 1, 0,
true,
true, trans_R,
190 b2linalg::Vector<T, b2linalg::Vdense_constref>::null,
191 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model_, f_, K_augm,
192 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0, log_el);
194 if (K_e.size1() != 0) {
195 K_augm += -trans_R * K_e * transposed(trans_R);
199 b2linalg::Vector<T, b2linalg::Vdense> f_r(K_augm_size);
200 f_r(b2linalg::Interval(0, trans_R.size1())) = -trans_R * f_;
202 if (trans_L.size2() > 0) {
203 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
204 trans_LR = trans_R * trans_L;
205 if (constraint_string ==
"PENALTY" || constraint_string ==
"AUGMENTED_LAGRANGE") {
206 const double penalty_factor =
207 case_.get_double(
"CONSTRAINT_PENALTY", constraint_string ==
"PENALTY" ? 1e10 : 1);
208 f_r(b2linalg::Interval(0, trans_R.size1())) += (trans_LR * l) * -penalty_factor;
209 K_augm += (trans_LR * transposed(trans_LR)) * penalty_factor;
211 if (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE") {
212 const double lagrange_mult_scale = case_.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
213 f_r(b2linalg::Interval(trans_R.size1(), K_augm_size)) = transposed(-trans_L) * r;
214 f_r(b2linalg::Interval(trans_R.size1(), K_augm_size)) -= l;
215 f_r(b2linalg::Interval(trans_R.size1(), K_augm_size)) *= lagrange_mult_scale;
216 trans_LR *= lagrange_mult_scale;
217 if (!MATRIX_FORMAT::symmetric) {
219 b2linalg::Interval(0, trans_R.size1()),
220 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
222 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
224 b2linalg::Interval(trans_R.size1(), K_augm_size),
225 b2linalg::Interval(0, trans_R.size1())) += LR;
229 if (logger.is_enabled_for(logging::data)) {
230 logger << logging::data <<
"d_value_d_dof "
231 << logging::DBName(
"D_VALUE_D_DOF.GLOB", 0, 0, case_.get_id()) << K_augm
232 << logging::LOGFLUSH;
233 logger << logging::data <<
"value " << logging::DBName(
"VALUE.GLOB", 0, 0, case_.get_id())
234 << f_r << logging::LOGFLUSH;
238 logger.LOG(logging::info,
"Resolve the linear problem");
239 const int nbnsv = case_.get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
240 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
242 f_r = inverse(K_augm, nks_r, nbnsv) * f_r;
243 }
catch (b2linalg::SingularMatrixError& e) {
244 if (nks_r.size2() != 0) {
245 b2linalg::Matrix<T, b2linalg::Mrectangle> nks;
246 nks = transposed(trans_R)
248 b2linalg::Interval(0, trans_R.size1()),
249 b2linalg::Interval(0, nks_r.size2()));
250 solution.set_system_null_space(nks);
254 if (nks_r.size2() != 0) {
255 b2linalg::Matrix<T, b2linalg::Mrectangle> nks;
256 nks = transposed(trans_R)
257 * nks_r(b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, nks_r.size2()));
258 solution.set_system_null_space(nks);
262 f_ = transposed(trans_R) * f_r(b2linalg::Interval(0, trans_R.size1()));
264 solution.set_dof(f_);
267 if (solution.compute_constraint_value() && !compute_rcfo) {
268 if (constraint_string ==
"PENALTY" || constraint_string ==
"AUGMENTED_LAGRANGE") {
269 l += transposed(trans_L) * f_;
270 const double penalty_factor =
271 case_.get_double(
"CONSTRAINT_PENALTY", constraint_string ==
"PENALTY" ? 1e10 : 1);
272 l *= -penalty_factor;
276 if (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE") {
277 const double lagrange_mult_scale = case_.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
278 l += T(-lagrange_mult_scale) * f_r(b2linalg::Interval(trans_R.size1(), f_r.size()));
280 if (case_.get_bool(
"RCFO_ONLY_SPC",
false)) {
281 for (
size_t j = 0; j != trans_L.size2(); ++j) {
282 if (trans_L.get_nb_nonzero(j) != 1) { l[j] = 0; }
285 f_reac = trans_L * l;
286 solution.set_constraint_value(f_reac);
289 typename SolutionStaticLinear<T>::gradient_container gc = solution.get_gradient_container();
292 if (gc.get() != 0 || compute_rcfo) {
293 logger.LOG(logging::info,
"Compute gradients and reaction forces");
295 domain.set_dof(b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_));
297 Domain::element_iterator ii = domain.get_element_iterator();
298 b2linalg::Index index;
299 solver_utile.get_elements_values(
300 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_), 1, 0,
true,
true,
301 b2linalg::Matrix<T, b2linalg::Mcompressed_col>::null,
302 b2linalg::Vector<T, b2linalg::Vdense_constref>::null,
303 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model_,
304 compute_rcfo ? f_reac : b2linalg::Vector<T, b2linalg::Vdense>::null,
305 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null,
306 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, gc.get(), 0, log_el);
307 if (compute_rcfo) { solution.set_constraint_value(f_reac); }
309 solution.terminate_case(
true, attributes);
312 logger << logging::info <<
"Assemble the stability matrix." << logging::LOGFLUSH;
314 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> KG_augm(
315 K_augm_size, domain.get_dof_connectivity_type(), case_);
317 static const double finite_difference_coefficients[4][4] = {
319 {2.0 / 3, -1.0 / 12},
320 {3.0 / 4, -3.0 / 20, 1.0 / 60},
321 {4.0 / 5, -1.0 / 5, 4.0 / 105, -1.0 / 280}};
322 if (finite_difference_method < 1 || finite_difference_method > 4) {
323 Exception() <<
"Invalid finite difference method" <<
THROW;
326 b2linalg::Vector<double, b2linalg::Vdense> d_value_d_dof_coeff(1);
327 for (
int i = 0; i != finite_difference_method; ++i) {
328 f_ *= i == 0 ? -h : -double(i + 1) / i;
329 for (
int j = 0; j != 2; j += 1) {
330 if (j == 1) { f_ *= -1; }
331 d_value_d_dof_coeff[0] =
332 -finite_difference_coefficients[finite_difference_method - 1][i]
333 * (j == 0 ? -1 : 1) / h;
334 solver_utile.get_elements_values(
335 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_),
336 h * (i + 1) * (j == 0 ? -1 : 1), 0, true, false, trans_R,
337 b2linalg::Vector<T, b2linalg::Vdense_constref>::null, d_value_d_dof_coeff,
338 *model_, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, KG_augm,
339 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0, log_el);
344 if (logger.is_enabled_for(logging::data)) {
345 logger << logging::data <<
"d2_value_d_dof_d_lambda "
346 << logging::DBName(
"D2_VALUE_D_DOF_D_LAMBDA.GLOB", 0, 0, case_.get_id()) << KG_augm
347 << logging::LOGFLUSH;
350 if (trans_L.size2() > 0
351 && (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE")) {
355 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
356 trans_LR = trans_R * trans_L;
357 const double lagrange_mult_scale = case_.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
358 trans_LR *= -lagrange_mult_scale;
359 if (!MATRIX_FORMAT::symmetric) {
361 b2linalg::Interval(0, trans_R.size1()),
362 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
364 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
366 b2linalg::Interval(trans_R.size1(), K_augm_size),
367 b2linalg::Interval(0, trans_R.size1())) += LR;
369 if (!MATRIX_FORMAT::symmetric) {
371 b2linalg::Interval(0, trans_R.size1()),
372 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
376 b2linalg::Interval(trans_R.size1(), K_augm_size),
377 b2linalg::Interval(0, trans_R.size1())) += LR;
380 logger << logging::info <<
"Eigenvalue problem resolution" << logging::LOGFLUSH;
382 eigenvalues_.resize(nb_eigenmodes_);
383 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvector_red(K_augm_size, nb_eigenmodes_);
385 eigenvector_red = eigenvector(K_augm,
'P', KG_augm,
'H', eigenvalues_, which, sigma);
387 eigenvectors_.resize(number_of_dof, nb_eigenmodes_);
388 mrbc.get_linear_value(b2linalg::Vector<T, b2linalg::Vdense>::null, trans_R);
392 b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, nb_eigenmodes_));
394 solution.set_modes(eigenvalues_, eigenvectors_);
396 solution.terminate_case(
true, attributes);
397 case_.warn_on_non_used_key();
398 logger.LOG(logging::info,
"End of linearised prebuckling solver");
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
virtual size_t get_number_of_stage() const =0
virtual CaseList & get_case_list()=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