KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
mvqn_randomized_svd_convergence_accelerator.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main author: Ruben Zorrilla
11 //
12 
13 #pragma once
14 
15 // System includes
16 #include <random>
17 
18 // External includes
19 
20 // Project includes
25 
26 // Application includes
29 
30 namespace Kratos
31 {
32 
35 
36 
40 
41 
45 
46 
50 
51 
55 
71 template<class TSparseSpace, class TDenseSpace>
73 {
74 public:
75 
79 
80  typedef std::size_t SizeType;
81 
83  typedef typename BaseType::Pointer BaseTypePointer;
84 
87 
90 
93 
97 
105  DenseQRPointerType pDenseQR,
106  DenseSVDPointerType pDenseSVD,
107  Parameters ConvAcceleratorParameters)
108  : BaseType()
109  , mpDenseQR(pDenseQR)
110  , mpDenseSVD(pDenseSVD)
111  {
112  ConvAcceleratorParameters.ValidateAndAssignDefaults(GetDefaultParameters());
113  mUserNumberOfModes = ConvAcceleratorParameters["jacobian_modes"].GetInt();
114  mAutomaticJacobianModes = ConvAcceleratorParameters["automatic_jacobian_modes"].GetBool();
115  mLimitModesToIterations = ConvAcceleratorParameters["limit_modes_to_iterations"].GetBool();
116  mMinRandSVDExtraModes = ConvAcceleratorParameters["min_rand_svd_extra_modes"].GetInt();
117  BaseType::SetInitialRelaxationOmega(ConvAcceleratorParameters["w_0"].GetDouble());
118  BaseType::SetCutOffTolerance(ConvAcceleratorParameters["cut_off_tol"].GetDouble());
119 
120  KRATOS_WARNING_IF("MVQNRandomizedSVDConvergenceAccelerator", mAutomaticJacobianModes && mUserNumberOfModes != 0)
121  << "Custom and automatic number of modes have been selected. Automatic will be used." << std::endl;
122  }
123 
128  // Required to build the IBQN-MVQN
130 
135 
139 
140 
144 
145  void FinalizeSolutionStep() override
146  {
147  KRATOS_TRY;
148 
149  // If required, calculate the SVD of the inverse Jacobian approximation
150  // It is important to check if the residual minimization has been done to avoid throwing errors in the first do nothing steps
151  // Note that in the IBQN case we avoid doing the decomposition as we reuse the last iteration one
154  }
155 
156  // Save the current (last) inverse Jacobian decomposition data for the next step
157  // Note that the current decomposition is checked in case the current step converges in one iteration with the old Jacobian
158  if (mpJacQU != nullptr && mpJacSigmaV != nullptr) {
159  mpOldJacQU = mpJacQU;
160  mpOldJacSigmaV = mpJacSigmaV;
161  std::size_t n_obs = BaseType::GetNumberOfObservations();
162  if (n_obs > mOldMaxRank) {
163  mOldMaxRank = n_obs;
164  }
165  }
166 
167  // Call the base class FinalizeSolutionStep
168  // Note that this clears the observation matrices so it needs to be called after the inverse Jacobian SVD
170 
171  // Clear the current step Jacobian decomposition pointers
172  mpJacQU = nullptr;
173  mpJacSigmaV = nullptr;
174 
175  // Update the seed for the next time step
176  mSeed++;
177 
178  KRATOS_CATCH( "" );
179  }
180 
182  {
183  Parameters mvqn_randomized_svd_default_parameters(R"({
184  "solver_type" : "MVQN_randomized_SVD",
185  "automatic_jacobian_modes" : true,
186  "jacobian_modes" : 0,
187  "w_0" : 0.825,
188  "cut_off_tol" : 1e-8,
189  "interface_block_newton" : false,
190  "limit_modes_to_iterations" : true,
191  "min_rand_svd_extra_modes" : 1
192  })");
193 
194  return mvqn_randomized_svd_default_parameters;
195  }
196 
200 
201 
205 
206 
210 
211 
215 
216  friend class IBQNMVQNRandomizedSVDConvergenceAccelerator<TSparseSpace, TDenseSpace>;
217 
219 protected:
222 
235  DenseQRPointerType pDenseQR,
236  DenseSVDPointerType pDenseSVD,
237  const bool AutomaticJacobianModes,
238  const unsigned int JacobianModes,
239  const double CutOffTolerance,
240  const bool LimitModesToIterations,
241  const unsigned int MinRandSVDExtraModes)
242  : BaseType(CutOffTolerance)
243  , mUserNumberOfModes(JacobianModes)
244  , mMinRandSVDExtraModes(MinRandSVDExtraModes)
245  , mAutomaticJacobianModes(AutomaticJacobianModes)
246  , mLimitModesToIterations(LimitModesToIterations)
247  , mpDenseQR(pDenseQR)
248  , mpDenseSVD(pDenseSVD)
249  {
250  KRATOS_WARNING_IF("MVQNRandomizedSVDConvergenceAccelerator", mAutomaticJacobianModes && mUserNumberOfModes != 0)
251  << "Custom and automatic number of modes have been selected. Automatic will be used." << std::endl;
252  }
253 
257 
259  const VectorType& rResidualVector,
260  const VectorType& rIterationGuess) override
261  {
262  // Append the current iteration information to the observation matrices
263  // This method also checks the linear dependency of the new data to dismiss it
264  BaseType::AppendCurrentIterationInformation(rResidualVector, rIterationGuess);
265 
266  // If the complete Jacobian is required for the IBQN equations calculate it
267  // Note that this is only done after the first iteration since the observation matrices are empty at the first one
270  }
271  }
272 
273  void CalculateCorrectionWithJacobian(VectorType& rCorrection) override
274  {
276  const auto p_V = BaseType::pGetResidualObservationMatrix();
277  const auto p_W = BaseType::pGetSolutionObservationMatrix();
278  auto& r_res_vect = *(BaseType::pGetCurrentIterationResidualVector());
279 
280  if (p_V != nullptr && p_W != nullptr) {
281  // Get the required arrays
282  const auto& r_V = *p_V;
283  const auto& r_W = *p_W;
284 
285  // Calculate the correction as the inverse Jacobian approximation times the current iteration residual
286  MatrixType aux_M;
287  CalculateAuxiliaryMatrixM(aux_M);
288  VectorType M_res = prod(aux_M, r_res_vect);
289  VectorType V_M_res = prod(r_V, M_res);
290  VectorType W_M_res = prod(r_W, M_res);
291 
292  noalias(rCorrection) = ZeroVector(n_dofs);
293  TDenseSpace::UnaliasedAdd(rCorrection, 1.0, V_M_res);
294  TDenseSpace::UnaliasedAdd(rCorrection, 1.0, W_M_res);
295  TDenseSpace::UnaliasedAdd(rCorrection, -1.0, r_res_vect);
296 
297  if (mpOldJacQU != nullptr && mpOldJacSigmaV != nullptr) {
298  const auto& r_A = *mpOldJacQU;
299  const auto& r_B = *mpOldJacSigmaV;
300  VectorType B_res = prod(r_B, r_res_vect);
301  VectorType A_B_res = prod(r_A, B_res);
302  VectorType B_V_M_res = prod(r_B, V_M_res);
303  VectorType A_B_V_M_res = prod(r_A, B_V_M_res);
304  TDenseSpace::UnaliasedAdd(rCorrection, 1.0, A_B_res);
305  TDenseSpace::UnaliasedAdd(rCorrection, -1.0, A_B_V_M_res);
306  }
307  } else {
308  if (mpOldJacQU != nullptr && mpOldJacSigmaV != nullptr) {
309  const auto& r_A = *mpOldJacQU;
310  const auto& r_B = *mpOldJacSigmaV;
311  const SizeType n_modes = TDenseSpace::Size2(r_A);
312  VectorType B_res(n_modes);
313  TDenseSpace::Mult(r_B, r_res_vect, B_res);
314  TDenseSpace::Mult(r_A, B_res, rCorrection);
315  TDenseSpace::UnaliasedAdd(rCorrection, -1.0, r_res_vect);
316  } else {
317  KRATOS_ERROR << "There is neither observation nor old Jacobian decomposition. Correction cannot be computed." << std::endl;
318  }
319  }
320  }
321 
323  {
324  const auto p_W = BaseType::pGetSolutionObservationMatrix();
325  const auto p_V = BaseType::pGetResidualObservationMatrix();
326 
327  // If there exists new observations, use these to calculate the inverse Jacobian SVD
328  // If not, the old Jacobian decomposition will be used
329  if (p_V != nullptr && p_W != nullptr) {
330  // Compute ((trans(V)*V)^-1)*trans(V)
331  MatrixType aux_M;
332  CalculateAuxiliaryMatrixM(aux_M);
333 
334  // If not initialized yet, create the random values matrix for the truncated SVD
335  if (!mRandomValuesAreInitialized || mpOmega == nullptr) {
336  InitializeRandomValuesMatrix();
337  }
338 
339  // Do the randomized SVD decomposition of the current Jacobian approximation
340  // Note that the identity part of the Jacobian will not be considered in the randomized SVD as this is full rank
341  MatrixType y;
342  MultiplyRight(aux_M, *mpOmega, y);
343 
344  mpDenseQR->Compute(y);
346  const SizeType n_modes = TDenseSpace::Size2(*mpOmega);
347  MatrixType Q(n_dofs, n_modes);
348  mpDenseQR->MatrixQ(Q);
349 
350  MatrixType phi;
351  MultiplyTransposeLeft(aux_M, Q, phi);
352 
353  VectorType s_svd; // Singular values vector
354  MatrixType u_svd; // Left orthogonal matrix
355  MatrixType v_svd; // Right orthogonal matrix
356  Parameters svd_settings(R"({
357  "compute_thin_u" : true,
358  "compute_thin_v" : true
359  })");
360  mpDenseSVD->Compute(phi, s_svd, u_svd, v_svd, svd_settings);
361 
362  // Save the decomposition matrices
363  // Note that the added extra modes are discarded in here
364  SizeType n_modes_final = n_modes - mNumberOfExtraModes;
365  auto p_aux_Q_U = Kratos::make_shared<MatrixType>(ZeroMatrix(n_dofs, n_modes_final));
366  auto p_aux_sigma_V = Kratos::make_shared<MatrixType>(n_modes_final, n_dofs);
367  auto& r_aux_Q_U = *p_aux_Q_U;
368  auto& r_aux_sigma_V = *p_aux_sigma_V;
370  for (SizeType j = 0; j < n_modes_final; ++j) {
371  for (SizeType k = 0; k < n_modes_final; ++k) {
372  r_aux_Q_U(I,j) += Q(I,k) * u_svd(k,j);
373  }
374  r_aux_sigma_V(j,I) = s_svd(j) * v_svd(I,j);
375  }
376  });
377 
378  std::swap(mpJacQU, p_aux_Q_U);
379  std::swap(mpJacSigmaV, p_aux_sigma_V);
380 
381  // Clear the random values matrix
382  if (mLimitModesToIterations) {
383  mpOmega = nullptr;
384  }
385 
386  } else {
387  mpJacQU = nullptr;
388  mpJacSigmaV = nullptr;
389  }
390  }
391 
395 
397  {
398  return mpJacQU;
399  }
400 
402  {
403  return mpJacSigmaV;
404  }
405 
407  {
408  return mpOldJacQU;
409  }
410 
412  {
413  return mpOldJacSigmaV;
414  }
415 
417 private:
420 
421 
425 
426  SizeType mSeed = 0; // Seed to be used in the random matrix generation (to be updated at each step)
427  SizeType mUserNumberOfModes; // User-defined number of modes to be kept in the Jacobian randomized SVD
428  SizeType mNumberOfExtraModes; // Number of extra modes used in the randomization
429  SizeType mMinRandSVDExtraModes; // Minimum number of extra modes used in the randomization
430  SizeType mCurrentNumberOfModes = 0; // Current number of modes to be kept in the Jacobian randomized SVD
431  bool mAutomaticJacobianModes = true; // Automatic selection of randomized SVD number of modes
432  bool mLimitModesToIterations = true; // Limits the number of modes to the current iterations
433  bool mRandomValuesAreInitialized = false; // Indicates if the random values for the truncated SVD have been already set
434 
435  DenseQRPointerType mpDenseQR; // Pointer to the dense QR utility
436  DenseSVDPointerType mpDenseSVD; // Pointer to the dense SVD utility
437 
438  MatrixPointerType mpOmega = nullptr; // Matrix with random values for truncated SVD
439  MatrixPointerType mpJacQU = nullptr; // Left DOFs x modes matrix from the current Jacobian decomposition
440  MatrixPointerType mpJacSigmaV = nullptr; // Right modes x DOFs matrix from the current Jacobian decomposition
441  MatrixPointerType mpOldJacQU = nullptr; // Left DOFs x modes matrix from the previous Jacobian decomposition
442  MatrixPointerType mpOldJacSigmaV = nullptr; // Right modes x DOFs matrix from the previous Jacobian decomposition
443 
444  SizeType mOldMaxRank = 0; // Previous Jacobian rank (computed from the SVD decomposition)
445 
449 
450 
454 
455  void InitializeRandomValuesMatrix()
456  {
457  // Initialize the number of modes
458  // Note that if automatic modes are selected we set the previous step rank plus the current number of observations
459  // This comes from the additivity property rank(A+B) \leq rank(A) + rank(B). Hence, the current Jacobian rank is at
460  // most the summation of the old Jacobian rank plus the number of current of observations
461  // This is current option, however there are alternative estimates (see below) that could be also used
463  const SizeType full_rank_modes = mOldMaxRank + n_obs;
464  SizeType n_modes;
465  if (mAutomaticJacobianModes) {
466  //TODO: make this optional
467  // n_modes = n_obs; // This is a good estimate assuming that rank remains almost constant among iterations.
468  // n_modes = mOldMaxRank; // This is a good estimate between n_obs and full_rank_modes. It seems to work slightly better than one above.
469  // n_modes = std::min(mOldMaxRank, n_obs); // The most robust automation estimate. With this, chances are that we never get a full-rank decomposition. However numerical noise is minimized.
470  n_modes = full_rank_modes; // This is the upper bound for a full-rank decomposition. Note that it might eventually introduce too much noise if the rank is smaller.
471  } else {
472  // If the number of modes is not automatic we need to check if it needs to be limited to the number of iterations (e.g. IBQN)
473  // Note that we check it with the current number of observations rather than using the iteration counter
474  // This is important in case some iteration information has been dropped because its linear dependency
475  // Also note that we consider the previous Jacobian (via the full_rank_modes variable) as this contributes to the rank
476  n_modes = mLimitModesToIterations ? std::min(full_rank_modes, mUserNumberOfModes) : mUserNumberOfModes;
477  }
478 
479  // Initialize auxiliary variables
480  const SizeType aux_extra_modes = std::ceil(0.1 * n_modes);
481  mNumberOfExtraModes = mMinRandSVDExtraModes > aux_extra_modes ? mMinRandSVDExtraModes : aux_extra_modes;
482  mCurrentNumberOfModes = n_modes + mNumberOfExtraModes;
483 
484  // Set the random values matrix pointer
486  auto p_aux_omega = Kratos::make_shared<MatrixType>(n_dofs, mCurrentNumberOfModes);
487  std::swap(p_aux_omega, mpOmega);
488 
489  // Create the random values generator
490  std::mt19937 generator(mSeed); //Standard mersenne_twister_engine seeded with the step number as seed
491  std::uniform_real_distribution<> distribution(0.0, 1.0);
492 
493  // Fill the random values matrix
494  auto& r_omega_matrix = *mpOmega;
495  for (SizeType i = 0; i < n_dofs; ++i) {
496  for (SizeType j = 0; j < mCurrentNumberOfModes; ++j) {
497  // Use distribution to transform the random unsigned int generated by generator into a
498  // double in [0.0, 1.0). Each call to distribution(generator) generates a new random double
499  r_omega_matrix(i,j) = distribution(generator);
500  }
501  }
502 
503  // Set the flag to avoid performing this operation again (the random values are stored)
504  mRandomValuesAreInitialized = !mLimitModesToIterations;
505  }
506 
507  void MultiplyRight(
508  const Matrix& rAuxM,
509  const Matrix& rRightMatrix,
510  Matrix& rSolution)
511  {
513  KRATOS_ERROR_IF(TDenseSpace::Size1(rRightMatrix) != n_dofs) << "Obtained right multiplication matrix size " << TDenseSpace::Size1(rRightMatrix) << " does not match the problem size " << n_dofs << " expected one." << std::endl;
514  if (TDenseSpace::Size1(rSolution) != n_dofs || TDenseSpace::Size2(rSolution) != mCurrentNumberOfModes) {
515  rSolution.resize(n_dofs, mCurrentNumberOfModes);
516  }
517 
518  // Get observation matrices from base MVQN convergence accelerator
519  const auto& r_W = *(BaseType::pGetSolutionObservationMatrix());
520  const auto& r_V = *(BaseType::pGetResidualObservationMatrix());
521 
522  // Add to the solution matrix
523  MatrixType M_omega = prod(rAuxM, rRightMatrix);
524  noalias(rSolution) = prod(r_W, M_omega);
525 
526  if (mpOldJacQU == nullptr && mpOldJacSigmaV == nullptr) {
528  // Old Jacobian initialized to minus the identity matrix
529  MatrixType V_M_omega = prod(r_V, M_omega);
530  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&V_M_omega,this](SizeType I){
531  for (SizeType j = 0; j < mCurrentNumberOfModes; ++j) {
532  rSolution(I,j) += V_M_omega(I,j);
533  }
534  });
535  }
536  } else {
537  MatrixType V_M_omega = prod(r_V, M_omega);
538  MatrixType B_omega = prod(*mpOldJacSigmaV, rRightMatrix);
539  MatrixType A_B_omega = prod(*mpOldJacQU, B_omega);
540  MatrixType B_V_M_omega = prod(*mpOldJacSigmaV, V_M_omega);
541  MatrixType A_B_V_M_omega = prod(*mpOldJacQU, B_V_M_omega);
543  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&A_B_omega,&V_M_omega,&A_B_V_M_omega,this](SizeType I){
544  for (SizeType j = 0; j < mCurrentNumberOfModes; ++j) {
545  rSolution(I,j) += A_B_omega(I,j) + V_M_omega(I,j) - A_B_V_M_omega(I,j);
546  }
547  });
548  } else {
549  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&A_B_omega,&A_B_V_M_omega,this](SizeType I){
550  for (SizeType j = 0; j < mCurrentNumberOfModes; ++j) {
551  rSolution(I,j) += A_B_omega(I,j) - A_B_V_M_omega(I,j);
552  }
553  });
554  }
555  }
556  }
557 
558  void MultiplyTransposeLeft(
559  const Matrix& rAuxM,
560  const Matrix& rLeftMatrix,
561  Matrix& rSolution)
562  {
564  KRATOS_ERROR_IF(TDenseSpace::Size1(rLeftMatrix) != n_dofs) << "Obtained left multiplication matrix size " << TDenseSpace::Size1(rLeftMatrix) << " does not match the problem size " << n_dofs << " expected one." << std::endl;
565  if (TDenseSpace::Size1(rSolution) != mCurrentNumberOfModes|| TDenseSpace::Size2(rSolution) != n_dofs) {
566  rSolution.resize(mCurrentNumberOfModes, n_dofs);
567  }
568 
569  // Get observation matrices from base MVQN convergence accelerator
570  const auto& r_W = *(BaseType::pGetSolutionObservationMatrix());
571  const auto& r_V = *(BaseType::pGetResidualObservationMatrix());
572 
573  // Add to the solution matrix
574  const auto Qtrans = trans(rLeftMatrix);
575  MatrixType Qtrans_W = prod(Qtrans, r_W);
576  noalias(rSolution) = prod(Qtrans_W, rAuxM);
577 
578  if (mpOldJacQU == nullptr && mpOldJacSigmaV == nullptr) {
580  // Old Jacobian initialized to minus the identity matrix
581  MatrixType Qtrans_V = prod(Qtrans, r_V);
582  MatrixType Qtrans_V_M = prod(Qtrans_V, rAuxM);
583  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&Qtrans_V_M,this](SizeType J){
584  for (SizeType i = 0; i < mCurrentNumberOfModes; ++i) {
585  rSolution(i,J) += Qtrans_V_M(i,J);
586  }
587  });
588  }
589  } else {
590  MatrixType Qtrans_V = prod(Qtrans, r_V);
591  MatrixType Qtrans_V_M = prod(Qtrans_V, rAuxM);
592  MatrixType Qtrans_A = prod(Qtrans, *mpOldJacQU);
593  MatrixType Qtrans_A_B = prod(Qtrans_A, *mpOldJacSigmaV);
594  MatrixType Qtrans_A_B_V = prod(Qtrans_A_B, r_V);
595  MatrixType Qtrans_A_B_V_M = prod(Qtrans_A_B_V, rAuxM);
597  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&Qtrans_A_B,&Qtrans_V_M,&Qtrans_A_B_V_M,this](SizeType J){
598  for (SizeType i = 0; i < mCurrentNumberOfModes; ++i) {
599  rSolution(i,J) += Qtrans_A_B(i,J) + Qtrans_V_M(i,J) - Qtrans_A_B_V_M(i,J);
600  }
601  });
602  } else {
603  IndexPartition<SizeType>(n_dofs).for_each([&rSolution,&Qtrans_A_B,&Qtrans_A_B_V_M,this](SizeType J){
604  for (SizeType i = 0; i < mCurrentNumberOfModes; ++i) {
605  rSolution(i,J) += Qtrans_A_B(i,J) - Qtrans_A_B_V_M(i,J);
606  }
607  });
608  }
609  }
610  }
611 
612  void CalculateAuxiliaryMatrixM(MatrixType& rAuxM)
613  {
614  // Do the QR decomposition of V
615  // Note that we require to do a copy of V observation matrix as QR decomposition is done inplace
616  const auto& r_V = *(BaseType::pGetResidualObservationMatrix());
617  MatrixType aux_V(r_V);
618  mpDenseQR->Compute(aux_V);
619 
620  // Get the QR decomposition matrices
621  // Note that in here we are assuming that the pivoting QR is used
622  const std::size_t n_dofs = TDenseSpace::Size1(r_V);
623  const std::size_t n_data_cols = TDenseSpace::Size2(r_V);
624  MatrixType Q(n_dofs, n_data_cols);
625  MatrixType R(n_data_cols, n_data_cols);
626  MatrixType P(n_data_cols, n_data_cols);
627  mpDenseQR->MatrixQ(Q);
628  mpDenseQR->MatrixR(R);
629  mpDenseQR->MatrixP(P);
630 
631  // Calculate the SVD decomposition of R
632  // Note that we firstly undo the pivoting by doing R*inv(P)
633  // Also note that since P is orthogonal we actually do R*trans(P)
634  MatrixType R_transP(n_data_cols, n_data_cols);
635  noalias(R_transP) = prod(R, trans(P));
636 
637  // Compute the Moore-Penrose pseudo-inverse of R
638  MatrixType R_transP_inv;
639  CalculateMoorePenroseInverse(R_transP, R_transP_inv);
640 
641  // Calculate the solution of the problem inv(trans(V)*V)*trans(V)
642  // The problem is written to avoid the transpose multiplication as V*M=I
643  // Hence, from the previous QR decomposition we can do Q*R*M=I that is M=pseudoinv(R)*trans(Q)
644  const std::size_t m = TDenseSpace::Size1(rAuxM);
645  const std::size_t n = TDenseSpace::Size2(rAuxM);
646  if (m != n_data_cols || n != n_dofs) {
647  TDenseSpace::Resize(rAuxM, n_data_cols, n_dofs);
648  }
649  const MatrixType trans_Q = trans(Q);
650  noalias(rAuxM) = prod(R_transP_inv, trans_Q);
651  }
652 
653  //TODO: Whe should add this to the MathUtils
654  void CalculateMoorePenroseInverse(
655  const MatrixType& rInputMatrix,
656  MatrixType& rMoorePenroseInverse)
657  {
658  IndexType aux_size_1 = TDenseSpace::Size1(rInputMatrix);
659  IndexType aux_size_2 = TDenseSpace::Size2(rInputMatrix);
660  KRATOS_ERROR_IF_NOT(aux_size_1 == aux_size_2) << "Input matrix is not squared." << std::endl;
661 
662  VectorType s_svd; // Singular values vector
663  MatrixType u_svd; // Left orthogonal matrix
664  MatrixType v_svd; // Right orthogonal matrix
665  Parameters svd_settings(R"({
666  "compute_thin_u" : true,
667  "compute_thin_v" : true
668  })");
669  mpDenseSVD->Compute(const_cast<MatrixType&>(rInputMatrix), s_svd, u_svd, v_svd, svd_settings);
670  const std::size_t n_sing_val = s_svd.size();
671  //TODO: This allocation can be avoided
672  MatrixType s_inv = ZeroMatrix(n_sing_val, n_sing_val);
673  for (std::size_t i = 0; i < n_sing_val; ++i) {
674  s_inv(i,i) = 1.0 / s_svd(i);
675  }
676 
677  // Calculate and save the input matrix pseudo-inverse
678  rMoorePenroseInverse = ZeroMatrix(aux_size_2, aux_size_1);
679 
680  // Note that we take advantage of the fact that the input matrix is always square
681  for (std::size_t i = 0; i < aux_size_2; ++i) {
682  for (std::size_t j = 0; j < aux_size_1; ++j) {
683  double& r_value = rMoorePenroseInverse(i,j);
684  for (std::size_t k = 0; k < n_sing_val; ++k) {
685  const double v_ik = v_svd(i,k);
686  for (std::size_t m = 0; m < n_sing_val; ++m) {
687  const double ut_mj = u_svd(j,m);
688  const double s_inv_km = s_inv(k,m);
689  r_value += v_ik * s_inv_km * ut_mj;
690  }
691  }
692  }
693  }
694  }
695 
699 
700 
704 
705 
709 
710 
714 
715 
717 }; /* Class MVQNRandomizedSVDConvergenceAccelerator */
718 
722 
723 
727 
728 
730 
731 } /* namespace Kratos.*/
Base class for convergence accelerators This class is intended to be the base of any convergence acce...
Definition: convergence_accelerator.h:43
Definition: dense_qr_decomposition.h:44
Definition: dense_svd_decomposition.h:45
Interface Block Newton MVQN with randomized Jacobian convergence accelerator Interface Block Newton e...
Definition: ibqn_mvqn_randomized_svd_convergence_accelerator.h:60
This class is useful for index iteration over containers.
Definition: parallel_utilities.h:451
void for_each(TUnaryFunction &&f)
Definition: parallel_utilities.h:514
MVQN acceleration scheme MultiVectorQuasiNewton convergence accelerator from Bogaers et al....
Definition: mvqn_convergence_accelerator.hpp:58
void SetInitialRelaxationOmega(const double Omega)
Set the Initial Relaxation Omega This method sets the relaxation parameter to be used in the very fir...
Definition: mvqn_convergence_accelerator.hpp:543
std::size_t GetNumberOfObservations() const
Definition: mvqn_convergence_accelerator.hpp:477
void FinalizeSolutionStep() override
Save the current step Jacobian This method saves the current step Jacobian as previous step Jacobian ...
Definition: mvqn_convergence_accelerator.hpp:187
bool IsFirstCorrectionPerformed() const
Definition: mvqn_convergence_accelerator.hpp:482
std::size_t GetProblemSize() const override
Get the Problem Size object This method returns the problem size, which equals the number of interfac...
Definition: mvqn_convergence_accelerator.hpp:467
VectorPointerType pGetCurrentIterationResidualVector()
Get the residual vector This method returns a pointer to the current iteration residual vector.
Definition: mvqn_convergence_accelerator.hpp:503
MatrixPointerType pGetSolutionObservationMatrix()
Get the observation matrix W This method returns a pointer to the solution observation matrix.
Definition: mvqn_convergence_accelerator.hpp:533
void AppendCurrentIterationInformation(const VectorType &rResidualVector, const VectorType &rIterationGuess)
Append the current iteration information to the observation matrices This method appends the current ...
Definition: mvqn_convergence_accelerator.hpp:289
std::size_t GetConvergenceAcceleratorIteration() const
Definition: mvqn_convergence_accelerator.hpp:472
MatrixPointerType pGetResidualObservationMatrix()
Get the observation matrix V This method returns a pointer to the residual observation matrix.
Definition: mvqn_convergence_accelerator.hpp:523
bool IsUsedInBlockNewtonEquations() const
Returns the a bool indicating if IBQN are used This method returns a bool flag indicating if the curr...
Definition: mvqn_convergence_accelerator.hpp:493
void SetCutOffTolerance(const double CutOffTolerance)
Set the Cut Off Tolerance This method sets the cut off relative tolerance value to be used in the inf...
Definition: mvqn_convergence_accelerator.hpp:553
MVQN-RZ acceleration scheme RandomiZed Multi-Vector Quasi-Newton (MVQN-RZ) method convergence acceler...
Definition: mvqn_randomized_svd_convergence_accelerator.h:73
BaseType::DenseMatrixPointerType MatrixPointerType
Definition: mvqn_randomized_svd_convergence_accelerator.h:89
std::size_t SizeType
Definition: mvqn_randomized_svd_convergence_accelerator.h:80
BaseType::DenseVectorPointerType VectorPointerType
Definition: mvqn_randomized_svd_convergence_accelerator.h:86
BaseType::DenseMatrixType MatrixType
Definition: mvqn_randomized_svd_convergence_accelerator.h:88
void FinalizeSolutionStep() override
Save the current step Jacobian This method saves the current step Jacobian as previous step Jacobian ...
Definition: mvqn_randomized_svd_convergence_accelerator.h:145
void CalculateCorrectionWithJacobian(VectorType &rCorrection) override
Calculates the current iteration correction with the Jacobian This method calculates the current iter...
Definition: mvqn_randomized_svd_convergence_accelerator.h:273
MatrixPointerType pGetJacobianDecompositionMatrixQU() override
Definition: mvqn_randomized_svd_convergence_accelerator.h:396
KRATOS_CLASS_POINTER_DEFINITION(MVQNRandomizedSVDConvergenceAccelerator)
BaseType::DenseVectorType VectorType
Definition: mvqn_randomized_svd_convergence_accelerator.h:85
DenseQRDecomposition< TDenseSpace >::Pointer DenseQRPointerType
Definition: mvqn_randomized_svd_convergence_accelerator.h:91
void CalculateInverseJacobianRandomizedSVD()
Definition: mvqn_randomized_svd_convergence_accelerator.h:322
void UpdateInverseJacobianApproximation(const VectorType &rResidualVector, const VectorType &rIterationGuess) override
Update the inverse Jacobian approximation This method first appends the current iteration values to t...
Definition: mvqn_randomized_svd_convergence_accelerator.h:258
BaseType::Pointer BaseTypePointer
Definition: mvqn_randomized_svd_convergence_accelerator.h:83
Parameters GetDefaultParameters() const override
Definition: mvqn_randomized_svd_convergence_accelerator.h:181
MatrixPointerType pGetOldJacobianDecompositionMatrixQU() override
Definition: mvqn_randomized_svd_convergence_accelerator.h:406
MVQNRandomizedSVDConvergenceAccelerator(const MVQNRandomizedSVDConvergenceAccelerator &rOther)=default
MVQNRandomizedSVDConvergenceAccelerator(DenseQRPointerType pDenseQR, DenseSVDPointerType pDenseSVD, Parameters ConvAcceleratorParameters)
Construct a new MVQNRandomizedSVDConvergenceAccelerator object MultiVector Quasi-Newton convergence a...
Definition: mvqn_randomized_svd_convergence_accelerator.h:104
MVQNFullJacobianConvergenceAccelerator< TSparseSpace, TDenseSpace > BaseType
Definition: mvqn_randomized_svd_convergence_accelerator.h:82
MatrixPointerType pGetOldJacobianDecompositionMatrixSigmaV() override
Definition: mvqn_randomized_svd_convergence_accelerator.h:411
MVQNRandomizedSVDConvergenceAccelerator(DenseQRPointerType pDenseQR, DenseSVDPointerType pDenseSVD, const bool AutomaticJacobianModes, const unsigned int JacobianModes, const double CutOffTolerance, const bool LimitModesToIterations, const unsigned int MinRandSVDExtraModes)
Construct a new MVQNRandomizedSVDConvergenceAccelerator object Multivector Quasi-Newton convergence a...
Definition: mvqn_randomized_svd_convergence_accelerator.h:234
MatrixPointerType pGetJacobianDecompositionMatrixSigmaV() override
Definition: mvqn_randomized_svd_convergence_accelerator.h:401
virtual ~MVQNRandomizedSVDConvergenceAccelerator()
Definition: mvqn_randomized_svd_convergence_accelerator.h:134
DenseSingularValueDecomposition< TDenseSpace >::Pointer DenseSVDPointerType
Definition: mvqn_randomized_svd_convergence_accelerator.h:92
This class provides to Kratos a data structure for I/O based on the standard of JSON.
Definition: kratos_parameters.h:59
int GetInt() const
This method returns the integer contained in the current Parameter.
Definition: kratos_parameters.cpp:666
void ValidateAndAssignDefaults(const Parameters &rDefaultParameters)
This function is designed to verify that the parameters under testing match the form prescribed by th...
Definition: kratos_parameters.cpp:1306
bool GetBool() const
This method returns the boolean contained in the current Parameter.
Definition: kratos_parameters.cpp:675
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
TDenseSpace::VectorType DenseVectorType
Definition: convergence_accelerator.h:56
TSparseSpace::VectorType VectorType
Definition: convergence_accelerator.h:50
std::size_t IndexType
The definition of the index type.
Definition: key_hash.h:35
#define KRATOS_ERROR
Definition: exception.h:161
#define KRATOS_ERROR_IF_NOT(conditional)
Definition: exception.h:163
TDenseSpace::MatrixPointerType DenseMatrixPointerType
Definition: convergence_accelerator.h:59
TDenseSpace::MatrixType DenseMatrixType
Definition: convergence_accelerator.h:57
TSparseSpace::MatrixPointerType MatrixPointerType
Definition: convergence_accelerator.h:54
#define KRATOS_ERROR_IF(conditional)
Definition: exception.h:162
TDenseSpace::VectorPointerType DenseVectorPointerType
Definition: convergence_accelerator.h:60
TSparseSpace::MatrixType MatrixType
Definition: convergence_accelerator.h:51
#define KRATOS_WARNING_IF(label, conditional)
Definition: logger.h:266
static double min(double a, double b)
Definition: GeometryFunctions.h:71
TSpaceType::IndexType Size1(TSpaceType &dummy, typename TSpaceType::MatrixType const &rM)
Definition: add_strategies_to_python.cpp:117
TSpaceType::IndexType Size2(TSpaceType &dummy, typename TSpaceType::MatrixType const &rM)
Definition: add_strategies_to_python.cpp:123
void Mult(TSpaceType &dummy, typename TSpaceType::MatrixType &rA, typename TSpaceType::VectorType &rX, typename TSpaceType::VectorType &rY)
Definition: add_strategies_to_python.cpp:98
void UnaliasedAdd(TSpaceType &dummy, typename TSpaceType::VectorType &x, const double A, const typename TSpaceType::VectorType &rY)
Definition: add_strategies_to_python.cpp:170
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
KratosZeroVector< double > ZeroVector
Definition: amatrix_interface.h:561
KratosZeroMatrix< double > ZeroMatrix
Definition: amatrix_interface.h:559
Internals::Matrix< double, AMatrix::dynamic, AMatrix::dynamic > Matrix
Definition: amatrix_interface.h:470
AMatrix::MatrixProductExpression< TExpression1Type, TExpression2Type > prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:568
std::size_t SizeType
The definition of the size type.
Definition: mortar_classes.h:43
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
AMatrix::TransposeMatrix< const T > trans(const T &TheMatrix)
Definition: amatrix_interface.h:486
y
Other simbols definition.
Definition: generate_axisymmetric_navier_stokes_element.py:54
n_dofs
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:151
phi
Definition: isotropic_damage_automatic_differentiation.py:168
R
Definition: isotropic_damage_automatic_differentiation.py:172
tuple Q
Definition: isotropic_damage_automatic_differentiation.py:235
int n
manufactured solution and derivatives (u=0 at z=0 dudz=0 at z=domain_height)
Definition: ode_solve.py:402
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
int m
Definition: run_marine_rain_substepping.py:8
J
Definition: sensitivityMatrix.py:58
integer i
Definition: TensorModule.f:17