b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2linearised_prebuckling_solver.H
1//------------------------------------------------------------------------
2// b2linearised_prebuckling_solver.H --
3//
4//
5// written by Mathias Doreille
6// Neda Ebrahimi Pour <neda.ebrahimipour@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 B2LINEARIZE_PREBUCKLING_SOLVER_H_
22#define B2LINEARIZE_PREBUCKLING_SOLVER_H_
23
24#include "b2ppconfig.h"
25#include "b2solver_utils.H"
27#include "model/b2domain.H"
28#include "model/b2element.H"
29#include "model/b2model.H"
30#include "model/b2solution.H"
31#include "model/b2solver.H"
32#include "solvers/b2constraint_util.H"
33#include "utils/b2linear_algebra.H"
34#include "utils/b2logging.H"
35#include "utils/b2object.H"
36
37namespace b2000::solver {
38
39template <typename T, typename MATRIX_FORMAT>
40class LinearisedPrebucklingSolver : public Solver {
41public:
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>;
46
47 void solve() override {
48 while (solve_iteration()) { ; }
49 }
50
51 bool solve_iteration() override {
52 if (model_ == nullptr) { Exception() << THROW; }
53 if (case_iterator_.get() == nullptr) {
54 case_iterator_ = model_->get_case_list().get_case_iterator();
55 }
56 case_ = case_iterator_->next();
57 if (case_) {
58 if (case_->get_number_of_stage() != 1) {
59 logging::get_logger("solver.linearised_prebuckling")
61 << "The linearised prebuckling solver cannot hand a case with multiple "
62 "stages. The extra stages are ignored."
63 << logging::LOGFLUSH;
64 }
65 solve_on_case(*case_);
66 return true;
67 }
68 return false;
69 }
70
71 static type_t type;
72
73protected:
74 void solve_on_case(Case& case_);
75 SolverUtils<T, MATRIX_FORMAT> solver_utile;
76 // Contains dof solution. Size: ndofs
77 b2linalg::Vector<T, b2linalg::Vdense> f_;
78 // Number of eigen modes
79 int nb_eigenmodes_;
80 // Contains eigen value for each mode. Size: nModes
81 b2linalg::Vector<T, b2linalg::Vdense> eigenvalues_;
82 // Contains eigen vector for each mode. Size: nDofs, nModes
83 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvectors_;
84};
85
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);
91
92} // namespace b2000::solver
93
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");
102
103 if (model_ == nullptr) { Exception() << THROW; }
104
105 // Compute the static linear solution
106 logger << logging::info << "Start the linearised prebuckling solver for the case "
107 << case_.get_id() << "." << logging::LOGFLUSH;
108 model_->set_case(case_);
109
110 logger << logging::info << "Assemble the linear problem." << logging::LOGFLUSH;
111
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());
116
117 double sigma;
118 char which[3];
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");
126
127 // Get the model reduction (x = R * x_r + r)
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);
134
135 // Get the essential boundary condition (L * x + l = 0)
136 ebc_t& ebc =
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);
142
143 if (!l.empty()) {
144 // scale the ebc constraint
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();
149
150 // procedure to remove dependency on the Lagrange multiplier
151 if (case_.get_bool("REMOVE_DEPENDENT_CONSTRAINTS", true)
152 && (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE")) {
153 b2linalg::Index P;
154 // trans_L.get_dep_columns(P, 3e-13, 1.5);
155 get_dependent_columns(trans_L, P);
156 if (!P.empty()) {
157 l.remove(P);
158 trans_L.remove_col(P);
159 logger << logging::info << "Remove " << P.size() << " dependent constraints."
160 << logging::LOGFLUSH;
161 }
162 }
163 }
164
165 // Get the natural boundary condition (K_e * x + f)
166 nbc_t& nbc =
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>())));
170
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_);
175
176 b2linalg::Vector<T, b2linalg::Vdense> f_reac;
177 if (compute_rcfo) { f_reac = -f_; }
178
179 // Assembly the matrix K by computing
180 // (trans(R) * K * R) = K_augm = sum (trans(R) * K_element * R)
181 // K * r = K_prod_r = sum (K_element * r)
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_);
186
187 f_ *= -1;
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);
193
194 if (K_e.size1() != 0) {
195 K_augm += -trans_R * K_e * transposed(trans_R);
196 f_ += -K_e * r;
197 }
198
199 b2linalg::Vector<T, b2linalg::Vdense> f_r(K_augm_size);
200 f_r(b2linalg::Interval(0, trans_R.size1())) = -trans_R * f_;
201
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;
210 }
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) {
218 K_augm(
219 b2linalg::Interval(0, trans_R.size1()),
220 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
221 }
222 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
223 K_augm(
224 b2linalg::Interval(trans_R.size1(), K_augm_size),
225 b2linalg::Interval(0, trans_R.size1())) += LR;
226 }
227 }
228
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;
235 }
236
237 // system resolution
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;
241 try {
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)
247 * nks_r(
248 b2linalg::Interval(0, trans_R.size1()),
249 b2linalg::Interval(0, nks_r.size2()));
250 solution.set_system_null_space(nks);
251 }
252 throw;
253 }
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);
259 }
260
261 // store the dof solution
262 f_ = transposed(trans_R) * f_r(b2linalg::Interval(0, trans_R.size1()));
263 f_ += r;
264 solution.set_dof(f_);
265
266 // computation of the constraint value solution using the solution
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;
273 } else {
274 l.set_zero();
275 }
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()));
279 }
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; }
283 }
284 }
285 f_reac = trans_L * l;
286 solution.set_constraint_value(f_reac);
287 }
288
289 typename SolutionStaticLinear<T>::gradient_container gc = solution.get_gradient_container();
290
291 // computation of the stress and the constraint value solution
292 if (gc.get() != 0 || compute_rcfo) {
293 logger.LOG(logging::info, "Compute gradients and reaction forces");
294
295 domain.set_dof(b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_));
296
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); }
308 RTable attributes;
309 solution.terminate_case(true, attributes);
310 }
311
312 logger << logging::info << "Assemble the stability matrix." << logging::LOGFLUSH;
313
314 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> KG_augm(
315 K_augm_size, domain.get_dof_connectivity_type(), case_);
316 {
317 static const double finite_difference_coefficients[4][4] = {
318 {1.0 / 2},
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;
324 }
325
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);
340 }
341 }
342 }
343
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;
348 }
349
350 if (trans_L.size2() > 0
351 && (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE")) {
352 // We move the Lagrange multiplier on the KG_augm matrix
353 // to have a positive semi definit K_augm matrix
354 // for the Buckling spectral shift transformation
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) {
360 K_augm(
361 b2linalg::Interval(0, trans_R.size1()),
362 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
363 }
364 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
365 K_augm(
366 b2linalg::Interval(trans_R.size1(), K_augm_size),
367 b2linalg::Interval(0, trans_R.size1())) += LR;
368 trans_LR *= sigma;
369 if (!MATRIX_FORMAT::symmetric) {
370 K_augm(
371 b2linalg::Interval(0, trans_R.size1()),
372 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
373 }
374 LR *= sigma;
375 K_augm(
376 b2linalg::Interval(trans_R.size1(), K_augm_size),
377 b2linalg::Interval(0, trans_R.size1())) += LR;
378 }
379
380 logger << logging::info << "Eigenvalue problem resolution" << logging::LOGFLUSH;
381
382 eigenvalues_.resize(nb_eigenmodes_);
383 b2linalg::Matrix<T, b2linalg::Mrectangle> eigenvector_red(K_augm_size, nb_eigenmodes_);
384
385 eigenvector_red = eigenvector(K_augm, 'P', KG_augm, 'H', eigenvalues_, which, sigma);
386
387 eigenvectors_.resize(number_of_dof, nb_eigenmodes_);
388 mrbc.get_linear_value(b2linalg::Vector<T, b2linalg::Vdense>::null, trans_R);
389 eigenvectors_ =
390 transposed(trans_R)
391 * eigenvector_red(
392 b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, nb_eigenmodes_));
393
394 solution.set_modes(eigenvalues_, eigenvectors_);
395 RTable attributes;
396 solution.terminate_case(true, attributes);
397 case_.warn_on_non_used_key();
398 logger.LOG(logging::info, "End of linearised prebuckling solver");
399}
400
401#endif // B2LINEARIZE_PREBUCKLING_SOLVER_H_
#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