b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2solver_system.H
1//------------------------------------------------------------------------
2// b2solver_system.H --
3//
4// written by Mathias Doreille
5// Neda Ebrahimi Pour <neda.ebrahimipour@dlr.de>
6//
7// (c) 2004-2012,2016,2017 SMR Engineering & Development SA
8// 2502 Bienne, Switzerland
9//
10// (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 B2SOLVER_SYSTEM_H_
20#define B2SOLVER_SYSTEM_H_
21
22#include "b2constraint_util.H"
23#include "b2ppconfig.h"
24#include "b2solver_utils.H"
26#include "model/b2case.H"
27#include "model/b2domain.H"
28#include "model/b2model.H"
29#include "model/b2solution.H"
30#include "utils/b2logging.H"
31#include "utils/b2timing.H"
32#include "utils/b2util.H"
33
34namespace b2000::solver {
35
36template <typename T, typename MATRIX_FORMAT>
37class SolverSystem {
38public:
39 void assemble(
40 Model* const model, Case const& case_, SolverUtils<T, MATRIX_FORMAT>& solver_utile,
41 RTable& solution_attr, b2linalg::Matrix<T, b2linalg::Mrectangle>& f_,
42 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_reac);
43
44 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_augm;
45 b2linalg::Matrix<T, b2linalg::Mrectangle> f_r;
46 b2linalg::Vector<T, b2linalg::Vdense> l;
47 b2linalg::Vector<T, b2linalg::Vdense> r;
48 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_L;
49 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_R;
50 b2000::b2linalg::Vector<T, b2000::b2linalg::Vdense> f_nbc_0;
51};
52
54template <typename T>
55void bc_elimination(
56 Model* const model, Case const& case_, b2linalg::Vector<T, b2linalg::Vdense>& r,
57 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R,
58 b2linalg::Vector<T, b2linalg::Vdense>& l,
59 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_L) {
60 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
61 using ebc_t = TypedEssentialBoundaryCondition<T>;
62
63 logging::Logger& logger = logging::get_logger("solver.static_linear");
64
65 size_t number_of_dof = model->get_domain().get_number_of_dof();
66
67 // Get the model reduction (x = R * x_r + r)
68 mrbc_t& mrbc = dynamic_cast<mrbc_t&>(
69 model->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
70 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
71 r = b2linalg::Vector<T, b2linalg::Vdense>(number_of_dof);
72 mrbc.get_linear_value(r, trans_R);
73
74 // Get the essential boundary condition (L * x + l = 0)
75 ebc_t& ebc =
76 dynamic_cast<ebc_t&>(model->get_essential_boundary_condition(ebc_t::type.get_subtype(
77 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
78 l = b2linalg::Vector<T, b2linalg::Vdense>(ebc.get_size(true));
79 ebc.get_linear_value(l, trans_L);
80
81 if (!l.empty()) {
82 const std::string constraint_string = case_.get_string("CONSTRAINT_METHOD", "REDUCTION");
83 // scale the ebc constraint
84 b2linalg::Vector<double> trans_L_scale(trans_L.size2());
85 trans_L.scale_col_to_norminf(trans_L_scale);
86 for (size_t i = 0; i != l.size(); ++i) { l[i] *= trans_L_scale[i]; }
87 trans_L.remove_zero();
88
89 // procedure to remove dependency on the Lagrange multiplier
90 if (case_.get_bool("REMOVE_DEPENDENT_CONSTRAINTS", true)
91 && (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE")) {
92 b2linalg::Index P;
93 // trans_L.get_dep_columns(P, 3e-13, 1.5);
94 get_dependent_columns(trans_L, P);
95 if (!P.empty()) {
96 l.remove(P);
97 trans_L.remove_col(P);
98 logger << logging::info << "Removed " << P.size() << " dependent constraints."
99 << logging::LOGFLUSH;
100 }
101 }
102 }
103
104} // bc_elimination
105
109template <typename T, typename MATRIX_FORMAT>
110void apply_nbcs(
111 Model* const model, b2linalg::Matrix<T, b2linalg::Mrectangle>& f_,
112 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_reac,
113 b2linalg::Vector<T, b2linalg::Vdense>& f_nbc_0,
114 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_nbc_0) {
115 using nbc_t = TypedNaturalBoundaryCondition<T, typename MATRIX_FORMAT::sparse_inversible>;
116
117 logging::Logger& logger = logging::get_logger("solver.static_linear");
118
119 std::set<int> subcase_id_set;
120 model->get_subcase_ids(subcase_id_set);
121 std::vector<int> subcase_ids(subcase_id_set.begin(), subcase_id_set.end());
122 size_t number_of_dof = model->get_domain().get_number_of_dof();
123 SolutionStaticLinear<T>& solution =
124 dynamic_cast<SolutionStaticLinear<T>&>(model->get_solution());
125
126 logger << logging::info << "Assemble the natural boundary conditions" << logging::LOGFLUSH;
127 nbc_t& nbc = dynamic_cast<nbc_t&>(model->get_natural_boundary_condition(nbc_t::type.get_subtype(
128 "TypedNaturalBoundaryConditionListComponent"
129 + type_name<T, typename MATRIX_FORMAT::sparse_inversible>())));
130
131 // Calculate the natural bc's that are valid for all subcases.
132 f_nbc_0 = b2linalg::Vector<T, b2linalg::Vdense>(number_of_dof);
133 nbc.get_linear_value(f_nbc_0, K_nbc_0);
134
135 // Loop over the subcases and add the subcase-specific nbc's to
136 // the vector of forces.
137 for (size_t i = 0; i != subcase_ids.size(); ++i) {
138 model->set_subcase_id(subcase_ids[i]);
139 if (subcase_ids[i] != 0) {
140 // Missing: add check whether nbc gives a second variation,
141 // in this case, an exception must be thrown.
142 nbc.get_linear_value(
143 f_[i], b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null);
144 }
145 f_[i] += f_nbc_0;
146 solution.set_natural_boundary_condition(f_[i]);
147 }
148 model->set_subcase_id(0);
149 f_reac = -f_;
150 f_ *= -1;
151} // apply_nbcs
152
154template <typename T, typename MATRIX_FORMAT>
155void assemble_from_elems(
156 Model* const model, SolverUtils<T, MATRIX_FORMAT>& solver_utile,
157 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> const& K_nbc_0,
158 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
159 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_, b2linalg::Matrix<T, b2linalg::Mrectangle>& f_r,
160 b2linalg::Vector<T, b2linalg::Vdense>& r,
161 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R) {
162 logging::Logger& log_el = logging::get_logger("elementary_matrix");
163
164 Domain& domain = model->get_domain();
165 std::set<int> subcase_id_set;
166 model->get_subcase_ids(subcase_id_set);
167 std::vector<int> subcase_ids(subcase_id_set.begin(), subcase_id_set.end());
168 const size_t number_of_subcases = subcase_ids.size();
169 size_t number_of_dof = model->get_domain().get_number_of_dof();
170
171 b2linalg::Vector<T, b2linalg::Vdense> f_add_to_all(number_of_dof);
172 f_add_to_all.set_zero();
173 solver_utile.get_elements_values(
174 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(r), 1, 0, true, true, trans_R,
175 b2linalg::Vector<T, b2linalg::Vdense_constref>::null,
176 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model, f_add_to_all, K_augm,
177 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0, log_el);
178
179 if (K_nbc_0.size1() != 0) {
180 K_augm += -trans_R * K_nbc_0 * transposed(trans_R);
181 f_add_to_all += -K_nbc_0 * r;
182 }
183 for (size_t i = 0; i != subcase_ids.size(); ++i) {
184 model->set_subcase_id(subcase_ids[i]);
185 if (subcase_ids[i] != 0 && domain.have_temperature()) {
186 // Calculate the element 1st variation for this subcase.
187 b2linalg::Vector<T, b2linalg::Vdense> f_add_to_subcase(number_of_dof);
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,
192 f_add_to_subcase,
193 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null,
194 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0, log_el);
195 if (K_nbc_0.size1() != 0) { f_add_to_subcase += -K_nbc_0 * r; }
196 f_[i] += f_add_to_subcase;
197 } else {
198 f_[i] += f_add_to_all;
199 }
200 }
201 model->set_subcase_id(0);
202 f_r(b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, number_of_subcases)) =
203 -trans_R * f_;
204} // assemble_from_elems
205
207template <typename T, typename MATRIX_FORMAT>
208void apply_constraints(
209 Model* const model, Case const& case_,
210 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
211 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_r, b2linalg::Vector<T, b2linalg::Vdense>& l,
212 b2linalg::Vector<T, b2linalg::Vdense>& r,
213 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_L,
214 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R) {
215 const std::string constraint_string = case_.get_string("CONSTRAINT_METHOD", "REDUCTION");
216 size_t K_augm_size = trans_R.size1() + (constraint_string == "PENALTY" ? 0 : trans_L.size2());
217 std::set<int> subcase_id_set;
218 model->get_subcase_ids(subcase_id_set);
219 std::vector<int> subcase_ids(subcase_id_set.begin(), subcase_id_set.end());
220 const size_t number_of_subcases = subcase_ids.size();
221
222 if (trans_L.size2() > 0) {
223 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
224 trans_LR = trans_R * trans_L;
225 if (constraint_string == "PENALTY" || constraint_string == "AUGMENTED_LAGRANGE") {
226 const double penalty_factor =
227 case_.get_double("CONSTRAINT_PENALTY", constraint_string == "PENALTY" ? 1e10 : 1);
228 for (size_t i = 0; i != number_of_subcases; ++i) {
229 f_r[i](b2linalg::Interval(0, trans_R.size1())) += (trans_LR * l) * -penalty_factor;
230 }
231 K_augm += (trans_LR * transposed(trans_LR)) * penalty_factor;
232 }
233 if (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE") {
234 const double lagrange_mult_scale = case_.get_double("LAGRANGE_MULT_SCALE_PENALTY", 1.0);
235 for (size_t i = 0; i != number_of_subcases; ++i) {
236 f_r[i](b2linalg::Interval(trans_R.size1(), K_augm_size)) = transposed(-trans_L) * r;
237 f_r[i](b2linalg::Interval(trans_R.size1(), K_augm_size)) -= l;
238 }
239 f_r(b2linalg::Interval(trans_R.size1(), K_augm_size),
240 b2linalg::Interval(0, number_of_subcases)) *= lagrange_mult_scale;
241 trans_LR *= lagrange_mult_scale;
242 if (!MATRIX_FORMAT::symmetric) {
243 K_augm(
244 b2linalg::Interval(0, trans_R.size1()),
245 b2linalg::Interval(trans_R.size1(), K_augm_size)) += trans_LR;
246 }
247 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
248 K_augm(
249 b2linalg::Interval(trans_R.size1(), K_augm_size),
250 b2linalg::Interval(0, trans_R.size1())) += LR;
251 }
252 }
253} // apply_constraints
254
257template <typename T, typename MATRIX_FORMAT>
258void handle_singularities(
259 Model* const model, Case const& case_,
260 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
261 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R) {
262 SolutionStaticLinear<T>& solution =
263 dynamic_cast<SolutionStaticLinear<T>&>(model->get_solution());
264 const bool autospc = case_.get_bool("AUTOSPC", false);
265
266 std::set<size_t> zero_columns_r;
267 for (size_t i = 0; i != K_augm.size1(); ++i) {
268 if (K_augm(i, i) == T(0)) {
269 bool all_zero = true;
270 for (size_t j = 0; all_zero && j != K_augm.size2(); ++j) {
271 if (K_augm(i, j) != T(0)) { all_zero = false; }
272 }
273 if (all_zero) {
274 zero_columns_r.insert(i);
275 if (autospc) { K_augm(i, i) = 1.; }
276 }
277 }
278 }
279
280 if (!zero_columns_r.empty()) {
281 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
282 nks_r.resize(trans_R.size1(), 1);
283 nks_r.set_zero();
284 for (auto i : zero_columns_r) { nks_r(i, 0) = T(1); }
285 b2linalg::Matrix<T, b2linalg::Mrectangle> nks;
286 nks = transposed(trans_R)
287 * nks_r(b2linalg::Interval(0, trans_R.size1()), b2linalg::Interval(0, nks_r.size2()));
288 for (size_t i = 0; i != nks.size1(); ++i) { nks(i, 0) = (nks(i, 0) != T(0) ? T(1) : T(0)); }
289 solution.set_system_null_space(nks, false, "NS_STRUCTURE");
290 }
291} // handle_singularities
292
293// Assemble the system for a static linear problem
294template <typename T, typename MATRIX_FORMAT>
295void assemble_system(
296 Model* const model, Case const& case_, SolverUtils<T, MATRIX_FORMAT>& solver_utile,
297 RTable& solution_attr, b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K_augm,
298 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_, b2linalg::Matrix<T, b2linalg::Mrectangle>& f_r,
299 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_reac, b2linalg::Vector<T, b2linalg::Vdense>& l,
300 b2linalg::Vector<T, b2linalg::Vdense>& r, b2linalg::Vector<T, b2linalg::Vdense>& f_nbc_0,
301 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_L,
302 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& trans_R) {
303 logging::Logger& logger = logging::get_logger("solver.static_linear");
304 auto time_nbc = obtain_timer("static_linear_analysis.nbc");
305 auto time_elements = obtain_timer("static_linear_analysis.elements");
306
307 const std::string constraint_string = case_.get_string("CONSTRAINT_METHOD", "REDUCTION");
308 Domain& domain = model->get_domain();
309 std::set<int> subcase_id_set;
310 model->get_subcase_ids(subcase_id_set);
311 std::vector<int> subcase_ids(subcase_id_set.begin(), subcase_id_set.end());
312 const size_t number_of_subcases = subcase_ids.size();
313
314 bc_elimination<T>(model, case_, r, trans_R, l, trans_L);
315
316 // Assembly the matrix K by computing
317 // (trans(R) * K * R) = K_augm = sum (trans(R) * K_element * R)
318 // K * r = K_prod_r = sum (K_element * r)
319
320 // Apply natural boundary conditions
321 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> K_nbc_0;
322 (*time_nbc).second.start();
323 apply_nbcs<T, MATRIX_FORMAT>(model, f_, f_reac, f_nbc_0, K_nbc_0);
324 (*time_nbc).second.stop();
325 solution_attr.set("ELAPSED_TIME_NBC", (*time_nbc).second.duration());
326
327 // Add the element contribution and the dof-dependent nbc.
328 logger << logging::info << "Element matrix assembly" << logging::LOGFLUSH;
329 (*time_elements).second.start();
330
331 size_t K_augm_size = trans_R.size1() + (constraint_string == "PENALTY" ? 0 : trans_L.size2());
332 K_augm = b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>(
333 K_augm_size, domain.get_dof_connectivity_type(), case_);
334 f_r = b2linalg::Matrix<T, b2linalg::Mrectangle>(K_augm_size, number_of_subcases);
335 assemble_from_elems<T, MATRIX_FORMAT>(
336 model, solver_utile, K_nbc_0, K_augm, f_, f_r, r, trans_R);
337
338 // Apply the constraints to the system
339 apply_constraints<T, MATRIX_FORMAT>(model, case_, K_augm, f_r, l, r, trans_L, trans_R);
340
341 if (logger.is_enabled_for(logging::data)) {
342 logger << logging::data << "d_value_d_dof "
343 << logging::DBName("D_VALUE_D_DOF.GLOB", 0, 0, case_.get_id()) << K_augm
344 << logging::LOGFLUSH;
345 logger << logging::data << "value " << logging::DBName("VALUE.GLOB", 0, 0, case_.get_id())
346 << f_r << logging::LOGFLUSH;
347 }
348 (*time_elements).second.stop();
349 solution_attr.set("ELAPSED_TIME_ELEMENTS", (*time_elements).second.duration());
350
351} // assemble_system
352
353template <typename T, typename MATRIX_FORMAT>
354void SolverSystem<T, MATRIX_FORMAT>::assemble(
355 Model* const model, Case const& case_, SolverUtils<T, MATRIX_FORMAT>& solver_utile,
356 RTable& solution_attr, b2linalg::Matrix<T, b2linalg::Mrectangle>& f_,
357 b2linalg::Matrix<T, b2linalg::Mrectangle>& f_reac) {
358 assemble_system<T, MATRIX_FORMAT>(
359 model, case_, solver_utile, solution_attr, K_augm, f_, f_r, f_reac, l, r, f_nbc_0,
360 trans_L, trans_R);
361}
362
363} // namespace b2000::solver
364
365#endif // B2SOLVER_SYSTEM_H_
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
timer_map_t::iterator obtain_timer(std::string name)
Definition b2timing.H:139