19#ifndef B2MODEL_REDUCTION_SOLVER_H_
20#define B2MODEL_REDUCTION_SOLVER_H_
24#include "b2solver_utils.H"
27#include "model/b2element.H"
32#include "utils/b2linear_algebra.H"
36namespace b2000::solver {
38template <
typename T,
typename MATRIX_FORMAT>
39class ModelReductionSolver :
public Solver {
41 using ebc_t = TypedEssentialBoundaryCondition<T>;
42 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
43 using type_t = ObjectTypeComplete<ModelReductionSolver, Solver::type_t>;
45 void solve()
override {
46 while (solve_iteration()) { ; }
49 bool solve_iteration()
override;
54 SolutionStaticNonlinear<T>* solution;
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);
63template <
typename T,
typename MATRIX_FORMAT>
64struct eigen_matrix_type {};
67struct eigen_matrix_type<std::complex<T>, b2linalg::Munsymmetric> {
68 static const char A =
'N';
69 static const char B =
'N';
73struct eigen_matrix_type<T, b2linalg::Msymmetric> {
74 static const char A =
'P';
75 static const char B =
'S';
78template <
typename T,
typename MATRIX_FORMAT>
79bool b2000::solver::ModelReductionSolver<T, MATRIX_FORMAT>::solve_iteration() {
82 if (case_iterator_.get() ==
nullptr) {
83 case_iterator_ = model_->get_case_list().get_case_iterator();
86 case_ = case_iterator_->next();
87 if (case_ ==
nullptr) {
92 model_->set_case(*case_);
94 Domain& domain = model_->get_domain();
95 const size_t number_of_dof = domain.get_number_of_dof();
97 SolutionModelReduction<T, typename MATRIX_FORMAT::dense>* solution =
98 &
dynamic_cast<SolutionModelReduction<T, typename MATRIX_FORMAT::dense>&
>(
99 model_->get_solution());
101 TypeError() <<
"The solver only accepts solutions of type SolutionModelReduction<T>"
105 const std::string constraint_string = case_->get_string(
"CONSTRAINT_METHOD",
"REDUCTION");
107 const std::string reduction_method = case_->get_string(
"REDUCTION_METHOD",
"CRAIG_BAMPTON");
110 b2linalg::Index interface_dof;
111 solution->get_interface_dof(interface_dof);
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);
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);
125 for (Element* e = i->next(); e !=
nullptr; e = i->next()) {
126 if (
auto te =
dynamic_cast<TypedElement<T>*
>(e); te !=
nullptr) {
133 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
136 index, b2linalg::Vector<T, b2linalg::Vdense>::null, d_value_d_dof_flags,
137 d_value_d_dof, b2linalg::Vector<T, b2linalg::Vdense>::null);
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]);
143 b2linalg::Matrix<T> tmp_element(d_value_d_dof[0]);
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];
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];
153 << logging::DBName(
"ELSV", 2, e->get_object_name()) << tmp_element
154 <<
" of element id " << e->get_object_name() << logging::LOGFLUSH;
157 logger <<
logging::info <<
"Element matrix assembly finished" << logging::LOGFLUSH;
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);
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);
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;
182 if (constraint_string ==
"LAGRANGE" || constraint_string ==
"AUGMENTED_LAGRANGE") {
187 b2linalg::Matrix<T, b2linalg::Mrectangle> B;
189 if (reduction_method ==
"CRAIG_BAMPTON" || reduction_method ==
"GUYAN") {
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;
196 trans_R.remove_row(row_to_remove);
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") {
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);
213 const size_t number_of_mode =
214 reduction_method ==
"GUYAN"
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);
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);
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; }
236 if (number_of_mode > 0) {
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);
243 T sigma = case_->get_double(
"SHIFT", 0);
244 std::string which = case_->get_string(
"WHICH_EIGENVALUES",
"SM");
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(),
252 b2linalg::Matrix<T, b2linalg::Mrectangle> eigvector =
255 b2linalg::Interval(0, trans_R.size1()),
256 b2linalg::Interval(0, eigvector_red.size2()));
257 B(b2linalg::Interval(interface_dof.size(), B.size2())) += eigvector;
260 }
else if (reduction_method ==
"MODE_DISPLACEMENT" || reduction_method ==
"MODE_ACCELERATION") {
261 const bool mode_acc = reduction_method ==
"MODE_ACCELERATION";
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") {
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);
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));
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);
285 typedef eigen_matrix_type<T, MATRIX_FORMAT> eig_matrix_type;
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));
293 B(b2linalg::Interval(0, number_of_mode)) =
294 b2linalg::transposed(trans_R)
296 b2linalg::Interval(0, trans_R.size1()),
297 b2linalg::Interval(0, eigvector_red.size2()));
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())) =
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()));
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);
319 Exception() <<
"unknown reduction method " << reduction_method <<
"." <<
THROW;
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;
333 RedSys[1].resize(B.size2(), B.size2());
335 RedSys[2] = b2linalg::transposed(B) * M * B;
336 solution->set_reduction(interface_dof.size(), B, RedSys);
340 solution->terminate_case(
true, attributes);
343 case_->warn_on_non_used_key();
#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