b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2model_reduction_solver.H
1//------------------------------------------------------------------------
2// b2model_reduction_solver.H --
3//
4// written by doreille
5// Thomas Blome <thomas.blome@dlr.de>
6//
7// Copyright (c) 2010 SMR Engineering & Development SA
8// 2502 Bienne, Switzerland
9//
10// Copyright (c) 2023 Deutsches Zentrum für Luft- und Raumfahrt (DLR) e.V.
11// Linder Höhe, 51147 Köln
12//
13// All Rights Reserved. Proprietary source code. The contents of
14// this file may not be disclosed to third parties, copied or
15// duplicated in any form, in whole or in part, without the prior
16// written permission of SMR.
17//------------------------------------------------------------------------
18
19#ifndef B2MODEL_REDUCTION_SOLVER_H_
20#define B2MODEL_REDUCTION_SOLVER_H_
21
22#include <string.h>
23
24#include "b2solver_utils.H"
26#include "model/b2domain.H"
27#include "model/b2element.H"
28#include "model/b2model.H"
29#include "model/b2node.H"
30#include "model/b2solution.H"
31#include "model/b2solver.H"
32#include "utils/b2linear_algebra.H"
33#include "utils/b2logging.H"
34#include "utils/b2object.H"
35
36namespace b2000::solver {
37
38template <typename T, typename MATRIX_FORMAT>
39class ModelReductionSolver : public Solver {
40public:
41 using ebc_t = TypedEssentialBoundaryCondition<T>;
42 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
43 using type_t = ObjectTypeComplete<ModelReductionSolver, Solver::type_t>;
44
45 void solve() override {
46 while (solve_iteration()) { ; }
47 }
48
49 bool solve_iteration() override;
50
51 static type_t type;
52
53private:
54 SolutionStaticNonlinear<T>* solution;
55};
56
57template <typename T, typename MATRIX_FORMAT>
58typename ModelReductionSolver<T, MATRIX_FORMAT>::type_t
59 ModelReductionSolver<T, MATRIX_FORMAT>::type(
60 "ModelReductionSolver", type_name<T, MATRIX_FORMAT>(), StringList("MODEL_REDUCTION"),
61 module, &Solver::type);
62
63template <typename T, typename MATRIX_FORMAT>
64struct eigen_matrix_type {};
65
66template <typename T>
67struct eigen_matrix_type<std::complex<T>, b2linalg::Munsymmetric> {
68 static const char A = 'N';
69 static const char B = 'N';
70};
71
72template <typename T>
73struct eigen_matrix_type<T, b2linalg::Msymmetric> {
74 static const char A = 'P';
75 static const char B = 'S';
76};
77
78template <typename T, typename MATRIX_FORMAT>
79bool b2000::solver::ModelReductionSolver<T, MATRIX_FORMAT>::solve_iteration() {
80 logging::Logger& logger = logging::get_logger("solver.model_reduction");
81
82 if (case_iterator_.get() == nullptr) {
83 case_iterator_ = model_->get_case_list().get_case_iterator();
84 }
85
86 case_ = case_iterator_->next();
87 if (case_ == nullptr) {
88 // all the cases are treated
89 return false;
90 }
91 logger.LOG(logging::info, "Start model reduction solver");
92 model_->set_case(*case_);
93
94 Domain& domain = model_->get_domain();
95 const size_t number_of_dof = domain.get_number_of_dof();
96
97 SolutionModelReduction<T, typename MATRIX_FORMAT::dense>* solution =
98 &dynamic_cast<SolutionModelReduction<T, typename MATRIX_FORMAT::dense>&>(
99 model_->get_solution());
100 if (solution == 0) {
101 TypeError() << "The solver only accepts solutions of type SolutionModelReduction<T>"
102 << THROW;
103 }
104
105 const std::string constraint_string = case_->get_string("CONSTRAINT_METHOD", "REDUCTION");
106
107 const std::string reduction_method = case_->get_string("REDUCTION_METHOD", "CRAIG_BAMPTON");
108
109 // get the dof interface
110 b2linalg::Index interface_dof;
111 solution->get_interface_dof(interface_dof);
112
113 // Assemble the matrix K, D and M
114 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K(number_of_dof);
115 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> D(number_of_dof);
116 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> M(number_of_dof);
117 {
118 logger << logging::info << "Element matrix assembly" << logging::LOGFLUSH;
119 domain.set_dof(b2linalg::Vector<T, b2linalg::Vdense_constref>::null);
120 Domain::element_iterator i = domain.get_element_iterator();
121 b2linalg::Index index;
122 std::vector<bool> d_value_d_dof_flags(3, true);
123 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_value_d_dof(3);
124 bool log_el_flag = logger.is_enabled_for(logging::data);
125 for (Element* e = i->next(); e != nullptr; e = i->next()) {
126 if (auto te = dynamic_cast<TypedElement<T>*>(e); te != nullptr) {
127 te->get_value(
128 *model_,
129 true, // linear
130 true, // equilibrium_solution
131 0, // time
132 0, // delta_time
133 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
134 0, // gradient_container
135 0, // solver_hints
136 index, b2linalg::Vector<T, b2linalg::Vdense>::null, d_value_d_dof_flags,
137 d_value_d_dof, b2linalg::Vector<T, b2linalg::Vdense>::null);
138 }
139 K += b2linalg::StructuredMatrix(number_of_dof, index, d_value_d_dof[0]);
140 D += b2linalg::StructuredMatrix(number_of_dof, index, d_value_d_dof[1]);
141 M += b2linalg::StructuredMatrix(number_of_dof, index, d_value_d_dof[2]);
142 if (log_el_flag) {
143 b2linalg::Matrix<T> tmp_element(d_value_d_dof[0]);
144 logger << logging::data << "elementary second variation "
145 << logging::DBName("ELSV", 0, e->get_object_name()) << tmp_element
146 << " of element id " << e->get_object_name() << logging::LOGFLUSH;
147 tmp_element = d_value_d_dof[1];
148 logger << logging::data << "elementary mass matrix "
149 << logging::DBName("ELSV", 1, e->get_object_name()) << tmp_element
150 << " of element id " << e->get_object_name() << logging::LOGFLUSH;
151 tmp_element = d_value_d_dof[2];
152 logger << logging::data << "elementary mass matrix "
153 << logging::DBName("ELSV", 2, e->get_object_name()) << tmp_element
154 << " of element id " << e->get_object_name() << logging::LOGFLUSH;
155 }
156 }
157 logger << logging::info << "Element matrix assembly finished" << logging::LOGFLUSH;
158 }
159
160 // Get the displacement boundary condition (L * x + l = 0)
161 ebc_t* dbc =
162 &dynamic_cast<ebc_t&>(model_->get_essential_boundary_condition(ebc_t::type.get_subtype(
163 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
164 b2linalg::Vector<T, b2linalg::Vdense> l(dbc->get_size(true));
165 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_L;
166 dbc->get_linear_value(l, trans_L);
167
168 // Get the model reduction (x = R * x_r + r)
169 mrbc_t* mrbc = &dynamic_cast<mrbc_t&>(
170 model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
171 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
172 b2linalg::Vector<T, b2linalg::Vdense> r(number_of_dof);
173 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_R;
174 mrbc->get_linear_value(r, trans_R);
175
176 if (trans_L.size2() > 0) {
177 if (constraint_string == "PENALTY" || constraint_string == "AUGMENTED_LAGRANGE") {
178 const double penalty_factor = case_->get_double(
179 "CONSTRAINT_PENALTY", constraint_string == "PENALTY" ? 1e10 : 1);
180 K += (trans_L * transposed(trans_L)) * penalty_factor;
181 }
182 if (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE") {
184 }
185 }
186
187 b2linalg::Matrix<T, b2linalg::Mrectangle> B;
188
189 if (reduction_method == "CRAIG_BAMPTON" || reduction_method == "GUYAN") {
190 // renumber the reduction to put the interface dof at the beginning
191 {
192 b2linalg::Index row_to_remove;
193 if (!trans_R.get_nonzero_unit_row_for_column(interface_dof, row_to_remove)) {
194 Exception() << "Some boundaries conditions are set on the interface dof." << THROW;
195 }
196 trans_R.remove_row(row_to_remove);
197 }
198
199 // Compute the interface constrain stiffness
200 const size_t K_augm_size =
201 trans_R.size1() + (constraint_string == "PENALTY" ? 0 : trans_L.size2());
202 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm(
203 K_augm_size, domain.get_dof_connectivity_type(), *case_);
204 K_augm += trans_R * K * b2linalg::transposed(trans_R);
205 if (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE") {
206 K_augm(
207 b2linalg::Interval(trans_R.size1(), K_augm_size),
208 b2linalg::Interval(0, trans_R.size1())) +=
209 b2linalg::transposed(trans_L) * b2linalg::transposed(trans_R);
210 }
211
212 // The reduction base
213 const size_t number_of_mode =
214 reduction_method == "GUYAN"
215 ? 0
216 : std::min(
217 size_t(case_->get_int("NMODES", interface_dof.size())), K_augm_size - 1);
218 B.resize(number_of_dof, interface_dof.size() + number_of_mode);
219
220 // compute the Guyan reduction
221 {
222 logger << logging::info << "Compute the " << interface_dof.size() << " Guyan modes"
223 << logging::LOGFLUSH;
224 b2linalg::Matrix<T, b2linalg::Mrectangle> Mtmp;
225 b2linalg::Matrix<T, b2linalg::Mcompressed_col> K1(
226 b2linalg::Matrix<T, b2linalg::Msym_compressed_col_st_constref>(K), interface_dof);
227 Mtmp = trans_R * K1;
228 Mtmp = inverse(K_augm) * Mtmp;
229 b2linalg::Matrix<T, b2linalg::Mrectangle> Mtmp1;
230 Mtmp1 = transposed(trans_R) * Mtmp;
231 B(b2linalg::Interval(0, interface_dof.size())) = -Mtmp1;
232 for (size_t i = 0; i != interface_dof.size(); ++i) { B(interface_dof[i], i) = 1; }
233 }
234
235 // compute the fixed interface dynamic modes
236 if (number_of_mode > 0) {
237 logger << logging::info << "Compute the " << number_of_mode
238 << " fixed interface dynamic modes" << logging::LOGFLUSH;
239 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> M_augm(
240 K_augm_size, domain.get_dof_connectivity_type(), *case_);
241 M_augm += trans_R * M * b2linalg::transposed(trans_R);
242
243 T sigma = case_->get_double("SHIFT", 0);
244 std::string which = case_->get_string("WHICH_EIGENVALUES", "SM");
245
246 typedef eigen_matrix_type<T, MATRIX_FORMAT> eig_matrix_type;
247 b2linalg::Vector<T, b2linalg::Vdense> eigvalue(number_of_mode);
248 b2linalg::Matrix<T, b2linalg::Mrectangle> eigvector_red = eigenvector(
249 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B, eigvalue, which.c_str(),
250 sigma);
251
252 b2linalg::Matrix<T, b2linalg::Mrectangle> eigvector =
253 transposed(trans_R)
254 * eigvector_red(
255 b2linalg::Interval(0, trans_R.size1()),
256 b2linalg::Interval(0, eigvector_red.size2()));
257 B(b2linalg::Interval(interface_dof.size(), B.size2())) += eigvector;
258 }
259
260 } else if (reduction_method == "MODE_DISPLACEMENT" || reduction_method == "MODE_ACCELERATION") {
261 const bool mode_acc = reduction_method == "MODE_ACCELERATION";
262
263 const size_t K_augm_size =
264 trans_R.size1() + (constraint_string == "PENALTY" ? 0 : trans_L.size2());
265 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm(
266 K_augm_size, domain.get_dof_connectivity_type(), *case_);
267 K_augm += trans_R * K * b2linalg::transposed(trans_R);
268 if (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE") {
269 K_augm(
270 b2linalg::Interval(trans_R.size1(), K_augm_size),
271 b2linalg::Interval(0, trans_R.size1())) +=
272 b2linalg::transposed(trans_L) * b2linalg::transposed(trans_R);
273 }
274
275 const size_t number_of_mode =
276 std::min(size_t(case_->get_int("NMODES", interface_dof.size())), K_augm_size - 1);
277 B.resize(number_of_dof, number_of_mode + (mode_acc ? interface_dof.size() : 0));
278
279 // compute the mode displacement vector
280 {
281 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> M_augm(
282 K_augm_size, domain.get_dof_connectivity_type(), *case_);
283 M_augm += trans_R * M * b2linalg::transposed(trans_R);
284
285 typedef eigen_matrix_type<T, MATRIX_FORMAT> eig_matrix_type;
286
287 std::string which_eigenvalues = case_->get_string("WHICH_EIGENVALUES", "SM");
288 b2linalg::Vector<T, b2linalg::Vdense> eigvalue(number_of_mode);
289 b2linalg::Matrix<T, b2linalg::Mrectangle> eigvector_red = b2linalg::eigenvector(
290 K_augm, eig_matrix_type::A, M_augm, eig_matrix_type::B, eigvalue,
291 which_eigenvalues.c_str(), case_->get_double("SHIFT", 0.0));
292
293 B(b2linalg::Interval(0, number_of_mode)) =
294 b2linalg::transposed(trans_R)
295 * eigvector_red(
296 b2linalg::Interval(0, trans_R.size1()),
297 b2linalg::Interval(0, eigvector_red.size2()));
298 }
299
300 // compute the static correction
301 if (mode_acc) {
302 b2linalg::Matrix<T, b2linalg::Mrectangle_ref> f =
303 B(b2linalg::Interval(number_of_mode, B.size2()));
304 for (size_t i = 0; i != interface_dof.size(); ++i) { f(interface_dof[i], i) = 1; }
305 b2linalg::Matrix<T, b2linalg::Mrectangle> f_r(K_augm_size, interface_dof.size());
306 f_r(b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, f_r.size2())) =
307 -trans_R * f;
308 f_r = b2linalg::inverse(K_augm) * f_r;
309 f = b2linalg::transposed(trans_R)
310 * f_r(b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, f_r.size2()));
311 }
312
313 // compute a "better" base vectors of the subspace generated by B
314 const size_t rank = b2linalg::Matrix<T, b2linalg::Mrectangle_increment_ref>(B)
315 .diagonalise_base_vector_on_observation_matrix(interface_dof);
316 B.resize(B.size1(), rank);
317
318 } else {
319 Exception() << "unknown reduction method " << reduction_method << "." << THROW;
320 }
321
322 // Now B contain the reduction basis.
323 // Compute the reduction at the interface dof
324 // and store it in the solution object
325 {
326 logger << logging::info << "Compute the reduced stiffness and mass matrix"
327 << logging::LOGFLUSH;
328 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > RedSys(3);
329 RedSys[0] = b2linalg::transposed(B) * K * B;
330 if (D.get_nb_nonzero()) {
331 RedSys[1] = b2linalg::transposed(B) * D * B;
332 } else {
333 RedSys[1].resize(B.size2(), B.size2());
334 }
335 RedSys[2] = b2linalg::transposed(B) * M * B;
336 solution->set_reduction(interface_dof.size(), B, RedSys);
337 }
338
339 RTable attributes;
340 solution->terminate_case(true, attributes);
341
342 logger.LOG(logging::info, "End of model reduction solver");
343 case_->warn_on_non_used_key();
344 return true;
345}
346
347} // namespace b2000::solver
348
349#endif /* B2MODEL_REDUCTION_SOLVER_H_ */
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
GenericException< TypeError_name > TypeError
Definition b2exception.H:325
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314