16#include <TStopwatch.h>
77 : fSize(mat->GetSize()),
80 fRHS((double*)rhs->GetMatrixArray()),
100 : fSize(mat->GetSize()),
149 if (
fMatrix->InheritsFrom(
"MatrixSparse")) {
163 return SolveFGMRES(VecSol.GetMatrixArray(), precon, itnlim, rtol, nkrylov);
184 double status = kTRUE;
185 double t, beta, eps1 = 0;
186 const double epsmac = 2.22E-16;
188 LOG(info) <<
"Solution by FGMRes: Preconditioner #" << precon
189 <<
" Max.iter.: " << itnlim
190 << std::scientific << std::setprecision(3) <<
" Tol.: " << rtol
191 <<
"NKrylov: " << nkrylov;
195 LOG(info) <<
"Changing N Krylov vectors from " << nkrylov <<
" 10";
201 LOG(warning) <<
"Unknown preconditioner identifier " << precon <<
", ignore";
205 LOG(error) <<
"FGMRES failed to build the preconditioner";
215 for (l =
fSize; l--;) {
226 for (l =
fSize; l--;) {
230 for (l =
fSize; l--;) {
233 beta = TMath::Sqrt(beta);
240 for (l =
fSize; l--;) {
260 for (l =
fSize; l--;) {
272 for (
int j = 0;
j <=
i;
j++) {
273 for (t = 0, l =
fSize; l--;) {
277 for (l =
fSize; l--;) {
282 for (t = 0, l =
fSize; l--;) {
288 for (t = 1. / t, l = 0; l <
fSize; l++) {
297 for (l = 1; l <=
i; l++) {
318 beta = TMath::Abs(
fPVecV[i1]);
320 }
while ((
i < nkrylov - 1) && (beta > eps1) && (its < itnlim));
324 for (
int j = 1;
j <=
i;
j++) {
326 for (t =
fPVecV[k], l = k + 1; l <=
i; l++) {
332 for (
int j = 0;
j <=
i;
j++) {
334 VecSol[l] += t *
fPvz[
j][l];
341 LOG(info) <<
"FGMRES converged in " << its
342 <<
" iterations, CPU time: "
343 << std::setprecision(1) << timer.CpuTime() <<
" sec";
349 LOG(error) << itnlim <<
" iterations limit exceeded, CPU time: "
350 << std::setprecision(1) << timer.CpuTime() <<
" sec";
364 return SolveMinRes(VecSol.GetMatrixArray(), precon, itnlim, rtol);
381 LOG(error) <<
"MinRes cannot solve asymmetric matrices, use FGMRes instead";
386 const double eps = 2.22E-16;
391 LOG(warning) <<
"Unknown preconditioner identifier "
392 << precon <<
", ignore";
396 LOG(error) <<
"MinRes failed to build the preconditioner";
401 LOG(info) <<
"Solution by MinRes: Preconditioner #" << precon
402 <<
" Max.iter.: " << itnlim <<
" Tol.: "
403 << std::scientific << std::setprecision(3) << rtol;
406 memset(VecSol, 0,
fSize *
sizeof(
double));
407 int status = 0, itn = 0;
412 double gam, gmax = 1, gmin = 1, gbar, oldeps, epsa, epsx, epsr, diag, delta,
phi, denom,
z;
418 memset(VecSol, 0,
fSize *
sizeof(
double));
437 LOG(error) <<
"Preconditioner is indefinite (init) ("
438 << std::scientific << std::setprecision(3) << beta1 <<
").";
445 LOG(warning) <<
"RHS is zero or is the nullspace of the Preconditioner: Solution is {0}";
450 beta1 = TMath::Sqrt(beta1);
459 double qrnorm = beta1;
460 double phibar = beta1;
473 while (status == 0) {
488 double s = 1. / beta;
495 double btrat = beta / oldb;
504 double alf2bt = alfa / beta;
521 LOG(error) <<
"Preconditioner is indefinite ("
522 << std::scientific << std::setprecision(3) << beta <<
").";
527 beta = TMath::Sqrt(beta);
528 tnorm2 += alfa * alfa + oldb * oldb + beta * beta;
531 if (beta / beta1 <= 10.0 * eps) {
533 LOG(info) <<
"RHS is eigenvector";
536 gmax = TMath::Abs(alfa);
547 delta = cs * dbar + sn * alfa;
548 gbar = sn * dbar - cs * alfa;
554 gam = TMath::Sqrt(gbar * gbar + beta * beta);
558 phibar = sn * phibar;
572 gmax = TMath::Max(gmax, gam);
573 gmin = TMath::Min(gmin, gam);
576 rhs1 = rhs2 - delta *
z;
580 normA = TMath::Sqrt(tnorm2);
581 ynorm = TMath::Sqrt(ynorm2);
583 epsx = normA * ynorm * eps;
584 epsr = normA * ynorm * rtol;
604 LOG(
debug) << Form(
"#%5d |qnrm: %+.2e Anrm:%+.2e Cnd:%+.2e Rnrm:%+.2e Ynrm:%+.2e EpsR:%+.2e EpsX:%+.2e Beta1:%+.2e",
605 itn, qrnorm, normA, condA, rnorm, ynorm, epsr, epsx, beta1);
610 LOG(error) << itnlim <<
" iterations limit exceeded";
612 if (condA >= 0.1 / eps) {
614 LOG(error) <<
"Matrix condition number "
615 << std::scientific << std::setprecision(3) << condA
617 << std::scientific << std::setprecision(3) << 0.1 / eps;
621 LOG(warning) <<
"Approximate convergence";
623 if (qrnorm <= epsx) {
625 LOG(info) <<
"Converged within machine precision";
627 if (qrnorm <= epsr) {
629 LOG(info) <<
"Converged";
639 "Exit from MinRes: CPU time: %.2f sec\n"
646 timer.CpuTime(), status, itn, normA, condA, rnorm, ynorm);
648 return status >= 0 && status <= 3;
655 ApplyPrecon(vecRHS.GetMatrixArray(), vecOut.GetMatrixArray());
669 vecOut[
i] = vecRHS[
i];
672 for (
int j = 0;
j <
n;
j++) {
680 for (
int j = 0;
j <
n;
j++) {
708 fPvv =
new double*[nkrylov + 1];
709 fPvz =
new double*[nkrylov];
710 for (
int i = 0;
i <= nkrylov;
i++) {
713 fPhh =
new double*[nkrylov];
714 for (
int i = 0;
i < nkrylov;
i++) {
715 fPhh[
i] =
new double[
i + 2];
721 fPVecV =
new double[nkrylov + 1];
778 LOG(info) <<
"Building Band-Diagonal preconditioner of half-width = "
783 if (
fMatrix->InheritsFrom(
"MatrixSparse")) {
785 int jmin = TMath::Max(0,
ir - hwidth);
797 int jmin = TMath::Max(0,
ir - hwidth);
798 for (
int jr = jmin; jr <=
ir; jr++) {
818 LOG(info) <<
"Building ILU" << lofM <<
" preconditioner";
835 Int_t* jw =
new Int_t[
fSize];
840 if ((
i %
int(0.1 *
fSize)) == 0) {
841 LOG(info) <<
"BuildPrecon: row " <<
i <<
" of " <<
fSize;
898 for (
int k = 0; k < rowUj.
GetNElems(); k++) {
925 LOG(fatal) <<
"Fatal error in ILIk: Zero diagonal found...";
935 LOG(info) <<
"ILU" << lofM <<
"preconditioner OK, CPU time: "
936 << std::setprecision(1) <<
sw.CpuTime() <<
" sec";
955 LOG(info) <<
"Building ILU" << lofM
956 <<
" preconditioner for dense matrix";
970 Int_t* jw =
new Int_t[
fSize];
1016 for (
int k = 0; k < rowUj.
GetNElems(); k++) {
1043 LOG(fatal) <<
"Fatal error in ILIk: Zero diagonal found...";
1053 LOG(info) <<
"ILU" << lofM <<
" dense preconditioner OK, CPU time: "
1054 << std::setprecision(1) <<
sw.CpuTime()
1074 LOG(info) <<
"PreconILUKsymb >>";
1078 UChar_t **ulvl =
nullptr, *levls =
nullptr;
1079 UShort_t* jbuf =
nullptr;
1080 Int_t* iw =
nullptr;
1081 ulvl =
new UChar_t*[
fSize];
1082 levls =
new UChar_t[
fSize];
1083 jbuf =
new UShort_t[
fSize];
1084 iw =
new Int_t[
fSize];
1095 for (
int j = 0;
j <
row.GetNElems();
j++) {
1104 }
else if (
col >
i) {
1122 while (++jpiv < incl) {
1126 for (
int j = jpiv + 1;
j < incl;
j++) {
1127 if (jbuf[
j] < kmin) {
1139 int tj = levls[jpiv];
1140 levls[jpiv] = levls[jmin];
1148 int it = ulvl[k][
j] + levls[jpiv] + 1;
1158 }
else if (
col >
i) {
1164 levls[ip] = TMath::Min(levls[ip], it);
1170 for (
int j = 0;
j < incl;
j++) {
1173 for (
int j =
i;
j < incu;
j++) {
1181 memcpy(rowLi.
GetIndices(), jbuf,
sizeof(UShort_t) * incl);
1188 memcpy(rowUi.
GetIndices(), jbuf +
i,
sizeof(UShort_t) * k);
1189 ulvl[
i] =
new UChar_t[k];
1190 memcpy(ulvl[
i], levls +
i, k *
sizeof(UChar_t));
1209 LOG(info) <<
"PreconILUKsymb <<";
1222 UChar_t **ulvl =
nullptr, *levls =
nullptr;
1223 UShort_t* jbuf =
nullptr;
1224 Int_t* iw =
nullptr;
1225 ulvl =
new UChar_t*[
fSize];
1226 levls =
new UChar_t[
fSize];
1227 jbuf =
new UShort_t[
fSize];
1228 iw =
new Int_t[
fSize];
1255 while (++jpiv < incl) {
1259 for (
int j = jpiv + 1;
j < incl;
j++) {
1260 if (jbuf[
j] < kmin) {
1272 int tj = levls[jpiv];
1273 levls[jpiv] = levls[jmin];
1281 int it = ulvl[k][
j] + levls[jpiv] + 1;
1291 }
else if (
col >
i) {
1297 levls[ip] = TMath::Min(levls[ip], it);
1303 for (
int j = 0;
j < incl;
j++) {
1306 for (
int j =
i;
j < incu;
j++) {
1314 memcpy(rowLi.
GetIndices(), jbuf,
sizeof(UShort_t) * incl);
1321 memcpy(rowUi.
GetIndices(), jbuf +
i,
sizeof(UShort_t) * k);
1322 ulvl[
i] =
new UChar_t[k];
1323 memcpy(ulvl[
i], levls +
i, k *
sizeof(UChar_t));
Sparse matrix class (from AliROOT), used as a global matrix for MillePede2.
Abstract class (from AliROOT) for square matrix used for millepede2 operation.
General class (from AliROOT) for solving large system of linear equations.
Symmetric Band Diagonal matrix (from AliROOT) with half band width W (+1 for diagonal)
void SortIndices(Bool_t valuesToo=kFALSE)
sort columns in increasing order. Used to fix the matrix after ILUk decompostion
Float_t GetDensity() const override
get fraction of non-zero elements
VectorSparse * GetRow(Int_t ir) const
static Bool_t IsZero(Double_t x, Double_t thresh=1e-64)
Bool_t IsSymmetric() const override
virtual Int_t GetSize() const
virtual Double_t Query(Int_t rown, Int_t coln) const
virtual void MultiplyByVec(const Double_t *vecIn, Double_t *vecOut) const
fill vecOut by matrix * vecIn (vector should be of the same size as the matrix)
void SetSymmetric(Bool_t v=kTRUE)
for solving large system of linear equations
MinResSolve()
default constructor
Int_t BuildPreconBD(Int_t hwidth)
build Band-Diagonal preconditioner
MatrixSq * fMatrix
matrix defining the equations
void ApplyPrecon(const TVectorD &vecRHS, TVectorD &vecOut) const
apply precond.
Int_t BuildPreconILUKDense(Int_t lofM)
ILUK preconditioner.
MinResSolve & operator=(const MinResSolve &rhs)
assignment op.
Bool_t InitAuxFGMRES(int nkrylov)
init auxiliary space for fgmres
Int_t fPrecon
preconditioner type
Int_t PreconILUKsymb(Int_t lofM)
ILUK preconditioner.
Double_t * fPVecY
aux. space
Int_t BuildPreconILUK(Int_t lofM)
ILUK preconditioner.
void ClearAux()
clear aux. space
Int_t BuildPrecon(Int_t val=0)
preconditioner building
~MinResSolve() override
destructor
Double_t * fRHS
right hand side
Int_t fSize
dimension of the input matrix
Int_t PreconILUKsymbDense(Int_t lofM)
ILUK preconditioner.
Bool_t InitAuxMinRes()
init auxiliary space for MinRes
Bool_t SolveMinRes(Double_t *VecSol, Int_t precon=0, int itnlim=2000, double rtol=1e-12)
MINRES method (for symmetric matrices)
Bool_t SolveFGMRES(Double_t *VecSol, Int_t precon=0, int itnlim=2000, double rtol=1e-12, int nkrylov=60)
FGMRES method (for general symmetric matrices)
void Solve(Double_t *rhs)
solve matrix equation
void DecomposeLDLT()
decomposition to L Diag L^T
UShort_t * GetIndices() const
Double_t & GetElem(Int_t i) const
UShort_t & GetIndex(Int_t i)
void ReSize(Int_t sz, Bool_t copy=kFALSE)
change the size
GLdouble GLdouble GLdouble z
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)