b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2static_linear_solver.H
1//------------------------------------------------------------------------
2// b2static_linear_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,2016,2017 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 B2STATIC_LINEAR_SOLVER_H_
22#define B2STATIC_LINEAR_SOLVER_H_
23
24#include "b2constraint_util.H"
25#include "b2ppconfig.h"
26#include "b2solver_system.H"
27#include "b2solver_utils.H"
29#include "model/b2domain.H"
30#include "model/b2element.H"
31#include "model/b2model.H"
32#include "model/b2solution.H"
33#include "utils/b2logging.H"
34#include "utils/b2object.H"
35#include "utils/b2timing.H"
36#include "utils/b2util.H"
37
38namespace b2000::solver {
39
69template <typename T, typename MATRIX_FORMAT>
70class StaticLinearSolver : public Solver {
71public:
76
77 void solve() override {
78 CaseList& case_list = model_->get_case_list();
79 if (case_list.get_number_of_case() == 1) {
80 case_iterator_ = case_list.get_case_iterator();
81 solve_on_case(*case_iterator_->next());
82 } else if (1) {
83 // Solving for each case separately is much
84 // faster than solve_cases_optimization().
85 case_iterator_ = case_list.get_case_iterator();
86 for (;;) {
87 auto c = case_iterator_->next();
88 if (c == nullptr) { break; }
89 solve_on_case(*c);
90 }
91 }
92 }
93
94 bool solve_iteration() override {
95 solve();
96 return false;
97 }
98
99 static type_t type;
100
101protected:
102 SolverUtils<T, MATRIX_FORMAT> solver_utile;
103 b2linalg::Matrix<T, b2linalg::Mrectangle> f_; // Contains dof solution. Size: ndofs, nsubcases
104 b2linalg::Matrix<T, b2linalg::Mrectangle> f_reac_;
105 SolverSystem<T, MATRIX_FORMAT> static_lin_sys;
106 void solve_on_case(Case& case_);
107};
108
109template <typename T, typename MATRIX_FORMAT>
110typename StaticLinearSolver<T, MATRIX_FORMAT>::type_t StaticLinearSolver<T, MATRIX_FORMAT>::type(
111 "StaticLinearSolver", type_name<T, MATRIX_FORMAT>(), StringList("LINEAR"), module,
112 &Solver::type);
113
114} // namespace b2000::solver
115
116/* Solve the static linear problems using the Lagrange Multiplier
117 Adjunction method.
118
119minimize the function E(x) on the variables x (the potential energy
120function in a displacement based formulation) defined by:
121
122 d_E / d_x (x) = K_i * x + f_i - K_e * x - f_e
123
124with the linear constraint on x:
125
126 x = R * x_r + r
127 L * x + l = 0
128
129Where:
130 - x (vector) is the degree of freedom (the displacement in a
131 displacement based formulation).
132 - K_i (matrix) and f_i (vector) define the linear value of the
133 elements (the internal force in a displacement based formulation).
134 - K_e (matrix) and f_e (vector) define the linear value of the
135 natural boundary condition (the external force in a displacement
136 based formulation).
137 - x_r (vector) is the degree of freedom in the reduction model.
138 - R (matrix) and r (vector) define the linear model reduction.
139 - L (matrix) and l (vector) define the linear essential boundary conditions.
140
141 Using the model reduction equation, the function to minimize become:
142
143 trans(R * x_r) * ((K_i - K_e) * R * x_r - f_e + f_i + (K_i - K_e) * r)
144
145 with the linear constraint:
146
147 L * R * x_r = -L * r - l
148
149 Using the Lagrange Multiplier Adjunction method, the minimization
150 problem is equivalent to solve the system of equations:
151
152 | trans(R) * (K_i - K_e) * R trans(L * R) | | x_r |
153 | | * | | =
154 | L * R 0 | | m |
155
156
157 | trans(R) * (f_e - f_i - (K_i - K_e) * r) |
158 | |
159 | -L * r - l |
160
161 The solution x is obtained from the solution x_r using the model
162 reduction equation: x = R * x_r + r
163
164 The gradients can then be computed.
165
166 The difference of the value of the natural boundary condition with
167 the value of the element (the reaction force in a displacement
168 based formulation) noted f_r is obtained by:
169
170 f_r = (K_i * x + f_i) - (K_e * x + f_e)
171
172*/
173
174template <typename T, typename MATRIX_FORMAT>
176 logging::Logger& logger = logging::get_logger("solver.static_linear");
177
178 auto time_analysis = obtain_timer("static_linear_analysis");
179 auto time_sysresolve = obtain_timer("static_linear_analysis.sysresolve");
180
181 (*time_analysis).second.start();
182
183 // logger.LOG(logging::info, "Start static linear solver");
184 logging::Logger& log_el = logging::get_logger("elementary_matrix");
185
186 if (model_ == nullptr) { Exception() << THROW; }
187
188 const std::string constraint_string = case_.get_string("CONSTRAINT_METHOD", "REDUCTION");
189
190 model_->set_case(case_);
191
192 logger << logging::info << "Start static linear solver for case " << case_.get_id()
193 << logging::LOGFLUSH;
194
195 Domain& domain = model_->get_domain();
196 size_t number_of_dof = domain.get_number_of_dof();
197 SolutionStaticLinear<T>& solution =
198 dynamic_cast<SolutionStaticLinear<T>&>(model_->get_solution());
199
200 typename SolutionStaticLinear<T>::gradient_container gc = solution.get_gradient_container();
201
202 const bool compute_rcfo =
203 solution.compute_constraint_value()
204 && (constraint_string == "REDUCTION" || case_.get_bool("GRADIENTS_ONLY", false));
205
206 // For the time being no subcases.
207 std::set<int> subcase_id_set;
208 model_->get_subcase_ids(subcase_id_set);
209 std::vector<int> subcase_ids(subcase_id_set.begin(), subcase_id_set.end());
210 const size_t number_of_subcases = subcase_ids.size();
211
212 RTable solution_attr;
213 f_.resize(number_of_dof, number_of_subcases);
214 f_.set_zero();
215 if (!case_.get_bool("GRADIENTS_ONLY", false)) {
216 static_lin_sys.assemble(model_, case_, solver_utile, solution_attr, f_, f_reac_);
217
218 logger.LOG(logging::info, "Resolve the linear problem");
219 (*time_sysresolve).second.start();
220
221 //
222 // Check matrix for structural singularities. Fix them if
223 // autospc is active.
224 //
225 handle_singularities<T, MATRIX_FORMAT>(
226 model_, case_, static_lin_sys.K_augm, static_lin_sys.trans_R);
227
228 //
229 // System resolution.
230 //
231 const int nbnsv = case_.get_int("COMPUTE_NULL_SPACE_VECTOR", 0);
232 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
233 static_lin_sys.K_augm.remove_zero(); // Also transforms K_augm to CSC format (TB)
234 b2linalg::SingularMatrixError ee;
235 bool is_singular = false;
236 try {
237 static_lin_sys.f_r = inverse(static_lin_sys.K_augm, nks_r, nbnsv) * static_lin_sys.f_r;
238 } catch (b2linalg::SingularMatrixError& e) {
239 ee = e;
240 is_singular = true;
241 if (!e.singular_dofs.empty()) {
242 if (nks_r.size2() == 0) {
243 nks_r.resize(static_lin_sys.trans_R.size1(), 1);
244 nks_r.set_zero();
245 }
246 for (auto i : e.singular_dofs) {
247 assert(i < nks_r.size1());
248 for (size_t j = 0; j != nks_r.size2(); ++j) { nks_r(i, j) = T(1); }
249 }
250 }
251 }
252 (*time_sysresolve).second.stop();
253 solution_attr.set("ELAPSED_TIME_SYSTEM_RESOLUTION", (*time_sysresolve).second.duration());
254 if (nks_r.size2() != 0) {
255 b2linalg::Matrix<T, b2linalg::Mrectangle> nks;
256 nks = transposed(static_lin_sys.trans_R)
257 * nks_r(
258 b2linalg::Interval(0, static_lin_sys.trans_R.size1()),
259 b2linalg::Interval(0, nks_r.size2()));
260 solution.set_system_null_space(nks);
261 }
262 if (is_singular) { ee << THROW; }
263
264 // store the dof solution
265 f_ = transposed(static_lin_sys.trans_R)
266 * static_lin_sys.f_r(
267 b2linalg::Interval(0, static_lin_sys.trans_R.size1()),
268 b2linalg::Interval(0, number_of_subcases));
269 for (size_t i = 0; i != number_of_subcases; ++i) {
270 f_[i] += static_lin_sys.r;
271 solution.set_subcase_id(subcase_ids[i]);
272 solution.set_dof(f_[i]);
273 }
274 solution.set_subcase_id(0);
275
276 // computation of the constraint value solution using the solution
277 if (solution.compute_constraint_value() && !compute_rcfo) {
278 for (size_t i = 0; i != number_of_subcases; ++i) {
279 b2linalg::Vector<T, b2linalg::Vdense> ll;
280 ll = static_lin_sys.l;
281
282 if (constraint_string == "PENALTY" || constraint_string == "AUGMENTED_LAGRANGE") {
283 ll += transposed(static_lin_sys.trans_L) * f_[i];
284 const double penalty_factor = case_.get_double(
285 "CONSTRAINT_PENALTY", constraint_string == "PENALTY" ? 1e10 : 1);
286 ll *= -penalty_factor;
287 } else {
288 ll.set_zero();
289 }
290 if (constraint_string == "LAGRANGE" || constraint_string == "AUGMENTED_LAGRANGE") {
291 const double lagrange_mult_scale =
292 case_.get_double("LAGRANGE_MULT_SCALE_PENALTY", 1.0);
293 ll += T(-lagrange_mult_scale)
294 * static_lin_sys.f_r[i](b2linalg::Interval(
295 static_lin_sys.trans_R.size1(), static_lin_sys.f_r[i].size()));
296 }
297 if (case_.get_bool("RCFO_ONLY_SPC", false)) {
298 for (size_t j = 0; j != static_lin_sys.trans_L.size2(); ++j) {
299 if (static_lin_sys.trans_L.get_nb_nonzero(j) != 1) { ll[j] = 0; }
300 }
301 }
302 f_reac_[i] = static_lin_sys.trans_L * ll;
303 solution.set_subcase_id(subcase_ids[i]);
304 solution.set_constraint_value(f_reac_[i]);
305 }
306 solution.set_subcase_id(0);
307 }
308 } else {
309 if (compute_rcfo) {
310 // Gradients only: Load the solution field for all subcases.
311 for (size_t i = 0; i != subcase_ids.size(); ++i) {
312 solution.set_subcase_id(subcase_ids[i]);
313 solution.get_dof(f_[i]);
314 }
315 solution.set_subcase_id(0);
316
317 // Get the natural boundary condition (K_nbc_0 * x + f)
318 nbc_t& nbc = dynamic_cast<nbc_t&>(
319 model_->get_natural_boundary_condition(nbc_t::type.get_subtype(
320 "TypedNaturalBoundaryConditionListComponent"
321 + type_name<T, typename MATRIX_FORMAT::sparse_inversible>())));
322
323 b2linalg::Vector<T, b2linalg::Vdense> f_nbc_0(number_of_dof);
324 nbc.get_linear_value(
325 f_nbc_0, b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null);
326
327 // Loop over the subcases and add the subcase-specific nbc's.
328 for (size_t i = 0; i != subcase_ids.size(); ++i) {
329 if (subcase_ids[i] != 0) {
330 nbc.set_subcase_id(subcase_ids[i]);
331 nbc.get_linear_value(
332 f_[i],
333 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null);
334 }
335 f_[i] += f_nbc_0;
336 solution.set_subcase_id(subcase_ids[i]);
337 solution.set_natural_boundary_condition(f_[i]);
338 }
339 nbc.set_subcase_id(0);
340 solution.set_subcase_id(0);
341 f_reac_ = -f_;
342 }
343 }
344
345 // Gradients requested: Compute element gradients (stresses, strains,
346 // ...) and the constraint value solution ("reaction forces", rcfo)
347 if (gc.get() != 0 || compute_rcfo) {
348 logger.LOG(logging::info, "Compute gradients and reaction forces");
349
350 for (size_t i = 0; i != number_of_subcases; ++i) {
351 domain.set_dof(b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_[i]));
352
353 model_->set_subcase_id(subcase_ids[i]);
354
355 Domain::element_iterator ii = domain.get_element_iterator();
356 b2linalg::Index index;
357 solver_utile.get_elements_values(
358 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(f_[i]), 1, 0, true, true,
359 b2linalg::Matrix<T, b2linalg::Mcompressed_col>::null,
360 b2linalg::Vector<T, b2linalg::Vdense_constref>::null,
361 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model_,
362 compute_rcfo ? f_reac_[i] : b2linalg::Vector<T, b2linalg::Vdense>::null,
363 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null,
364 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, gc.get(), 0, log_el);
365
366 if (compute_rcfo) { solution.set_constraint_value(f_reac_[i]); }
367 }
368 model_->set_subcase_id(0);
369
370 (*time_analysis).second.stop();
371 solution_attr.set("ELAPSED_TIME_ANALYSIS", (*time_analysis).second.duration());
372 solution.terminate_case(true, solution_attr);
373 }
374
375 logger.LOG(logging::info, "End of static linear solver");
376 case_.warn_on_non_used_key();
377}
378
379#endif // B2STATIC_LINEAR_SOLVER_H_
#define THROW
Definition b2exception.H:198
Definition b2case.H:154
Definition b2case.H:110
virtual CaseList & get_case_list()=0
Definition b2object.H:415
A Solver instance executes an FE analysis. It is created and initialized by the Model instance and,...
Definition b2solver.H:50
Case * case_
This also.
Definition b2solver.H:93
Model * model_
Definition b2solver.H:91
Definition b2util.H:54
Definition b2boundary_condition.H:198
Definition b2boundary_condition.H:302
Definition b2boundary_condition.H:81
Definition b2static_linear_solver.H:70
void solve() override
This function is usually called by the Model instance.
Definition b2static_linear_solver.H:77
bool solve_iteration() override
This function is called by the Solver instance itself.
Definition b2static_linear_solver.H:94