/* $Id: precondnl.cc,v 1.3 1996/11/20 09:57:29 roitzsch Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "precondnl.h" #include "int.h" #include "nonlin.h" #include "sysmatml.h" #include "family.h" #include "dirichlet.h" #include "cmdpars.h" extern CmdPars Cmd; //------------------------------------------------------------------------- NonLinearSGGS:: NonLinearSGGS(NonLinearity& nonLinearity0) : Preconditioner(), nonLinearity(nonLinearity0), sol(0) { } //------------------------------------------------------------------------- void NonLinearSGGS:: initialize(SystemMatrix* A, Vector& x, Vector& /*b*/) { int i; if (infoLinSystem) cout << " -- Nonlinear SL-GS Preconditioner\n"; if (A->DirectSolution()) { cout << "\n*** NonLinearSGGS::initialize(...) : wrong Matrix-type;" << "\n\t DirectSolution()==true (set directSolverNodeLimit=0 ?)\n"; cout.flush(); abort(); } FORALL(x,i) { if (dirichletBCs->isSet(i)) x[i] = dirichletBCs->value(i); } sol = &x; A->symmetricExpansion(); } //------------------------------------------------------------------------- void NonLinearSGGS:: close(SystemMatrix* A, Vector& /*x*/, Vector& /*b*/) { A->removeSymmetricExpansion(); } //------------------------------------------------------------------------- // -- perform one non-linear Gauss-Seidel step on A*e = r : void NonLinearSGGS:: invert(Vector& e, SystemMatrix* A, Vector& r) { int i; Num res; FORALL(e,i) e[i] = 0.0; for (i=1; i<=A->Dim(); ++i) { if (dirichletBCs->isSet(i)) continue; res = A->MultRow(i,e); res = r[i] - res; // the new (linear) residual of node i nonLinearity.defectCorrection(i, e[i], res, (*sol)[i], A->Diag(i)); r[i] -= res; // res may have changed } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // -- Non-linear Gauss-Seidel multi-level preconditioner NonLinearMLGS:: NonLinearMLGS(NonLinearity& nonLinearity0) : MMGPreconditioner(), nonLinearity(nonLinearity0), lowDefObstacle(0,DefaultStackSize), uppDefObstacle(0,DefaultStackSize), sol(0) { topLevelSmoothing = True; Cmd.get("topLevelSmoothing",&topLevelSmoothing); lowDefObstacle.push(new Vector(1)); uppDefObstacle.push(new Vector(1)); } //------------------------------------------------------------------------- NonLinearMLGS:: ~NonLinearMLGS() { int i; FORALL(lowDefObstacle,i) { delete lowDefObstacle[i]; delete uppDefObstacle[i]; } } //------------------------------------------------------------------------- void NonLinearMLGS:: update(SystemMatrix* A, FamilyTree* familyTree0, DirichletBCs* dirichletBCs0) { int level, dim; familyTree = familyTree0; dirichletBCs = dirichletBCs0; initParameters(); if (A->DirectSolution()) { cout << "\n*** NonLinearMLGS::update : wrong Matrix-type;" << "\n\t DirectSolution()==True (set directSolverNodeLimit=0 ?)\n"; cout.flush(); abort(); } if (maxLevel < 0) // level 0 call { maxLevel = 0; Al.push(A); lowDefObstacle[0]->resize(A->Dim()); uppDefObstacle[0]->resize(A->Dim()); return; } maxLevel = familyTree->MaxLevel(); if (maxLevel > 0) if (maxLevel-1 > rl.high()) // depth has increased { Al.push(A); rl.push(new Vector(1)); el.push(new Vector(1)); } for (level=0; levelDim(); rl[level]->resize(dim); el[level]->resize(dim); } if (maxLevel > uppDefObstacle.high()) // depth has increased { lowDefObstacle.push(new Vector(1)); uppDefObstacle.push(new Vector(1)); } for (level=0; level<=maxLevel; ++level) { dim = Al[level]->Dim(); lowDefObstacle[level]->resize(dim); uppDefObstacle[level]->resize(dim); } if (infoPrecond) memSpace(True); if (Cmd.isTrue("printAL")) { int i; FORALL(Al,i) Al[i]->print(); } } //------------------------------------------------------------------------- void NonLinearMLGS:: initialize(SystemMatrix* A, Vector& x, Vector& /*b*/) { int i; if (infoLinSystem) cout << " -- Nonlinear ML-GS Preconditioner\n"; aux.resize(A->Dim()); eMG.resize(A->Dim()); ADiag0.resize(A->Dim()); FORALL(x,i) { if (dirichletBCs->isSet(i)) x[i] = dirichletBCs->value(i); } sol = &x; A->symmetricExpansion(); } //------------------------------------------------------------------------- void NonLinearMLGS:: close(SystemMatrix* A, Vector& /*x*/, Vector& /*b*/) { aux.resize (1); eMG.resize (1); ADiag0.resize(1); A->removeSymmetricExpansion(); } //------------------------------------------------------------------------- void NonLinearMLGS:: invert(Vector& e, SystemMatrix* A, Vector& r) { int i; FORALL(ADiag0,i) ADiag0[i] = A->Diag(i); // save diagonal NonLinGSStep(e, A, r); residual(aux,r,*A,e); // new residual in aux FORALL(r,i) r[i] = aux[i]; el.push(&eMG); // available for restrictObstacles MGCycle(eMG, *Al[maxLevel], r, maxLevel); el.pop(); FORALL(e,i) e[i] += eMG[i]; // add multi-grid defect correction FORALL(ADiag0,i) A->Diag(i) = ADiag0[i]; } //------------------------------------------------------------------------- void NonLinearMLGS:: NonLinGSStep(Vector& e, SystemMatrix* A, Vector& r) { int i; Num res, a; Bool critic; Vector& uppDefO = *uppDefObstacle[maxLevel]; Vector& lowDefO = *lowDefObstacle[maxLevel]; FORALL(e,i) { e[i] = uppDefO[i] = lowDefO[i] = 0.0; setUnCritical(i); } for (i=1; i<=A->Dim(); ++i) { if (dirichletBCs->isSet(i)) continue; res = A->MultRow(i,e); res = r[i] - res; // the new (linear) residual of node i nonLinearity.defectCorrection(i, e[i], res, (*sol)[i], A->Diag(i), a, uppDefO[i], lowDefO[i], critic); r[i] -= res; A->Diag(i) += a; if (critic) setCritical(i); } } //------------------------------------------------------------------------- void NonLinearMLGS:: preSmooth(int level, Vector& e, SystemMatrix& A, Vector& r) { if (level==maxLevel && !topLevelSmoothing) return; int i, n; Vector& uppO = *uppDefObstacle[level]; Vector& lowO = *lowDefObstacle[level]; for (n=1; n<=nPreSmooth; ++n) { for (i=1; i<=A.Dim(); ++i) { if (!isCritical(i,level)) { A.smoothNode(i,e,r); if (e[i] > uppO[i]) e[i] = uppO[i]; if (e[i] < lowO[i]) e[i] = lowO[i]; } } } } //------------------------------------------------------------------------- void NonLinearMLGS:: postSmooth(int level, Vector& e, SystemMatrix& A, Vector& r) { if (level==maxLevel && !topLevelSmoothing) return; int i, n; Vector& uppO = *uppDefObstacle[level]; Vector& lowO = *lowDefObstacle[level]; for (n=1; n<=nPostSmooth; ++n) { for (i=A.Dim(); i>=1; --i) { if (!isCritical(i,level)) { A.smoothNode(i,e,r); if (e[i] > uppO[i]) e[i] = uppO[i]; if (e[i] < lowO[i]) e[i] = lowO[i]; } } } } //------------------------------------------------------------------------- void NonLinearMLGS:: restr(Vector& rHigh, Vector& rLow, int level) { familyTree->restr(rHigh, rLow, level); Al[level-1]->resetDirichletEntries(rLow); restrictObstacles(level); MLMatrix* AMLM1 = Al[level-1]->castToMLMatrix(); MLMatrix* AML = Al[level]->castToMLMatrix(); AMLM1->markNodes(); // -> all nodes will be restricted AMLM1->GalerkinRestriction(*AML, *familyTree->getGeneration(level)); AMLM1->symmetricExpansion(); } //------------------------------------------------------------------------- void NonLinearMLGS:: prolong(Vector& eLow, Vector& eHigh, int level) { Al[level-1]->resetDirichletEntries(eLow); familyTree->prolong(eLow, eHigh, level); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // -- Truncated non-linear Gauss-Seidel multi-level preconditioner TrcNonLinearMLGS:: TrcNonLinearMLGS(NonLinearity& nonLinearity0) : NonLinearMLGS(nonLinearity0), critical(0,DefaultStackSize) { critical.push(new Vector(1)); } //------------------------------------------------------------------------- TrcNonLinearMLGS:: ~TrcNonLinearMLGS() { int i; FORALL(critical,i) delete critical[i]; } //------------------------------------------------------------------------- void TrcNonLinearMLGS:: update(SystemMatrix* A, FamilyTree* familyTree0, DirichletBCs* dirichletBCs0) { int level; NonLinearMLGS::update(A, familyTree0, dirichletBCs0); if (maxLevel > critical.high()) // depth has increased critical.push(new Vector(1)); for (level=0; level<=maxLevel; ++level) { Vector& critic = *critical[level]; critic.resize(Al[level]->Dim()); } } //------------------------------------------------------------------------- void TrcNonLinearMLGS:: initialize(SystemMatrix* A, Vector& x, Vector& /*b*/) { int i; if (infoLinSystem) cout << " -- Truncated Nonlinear ML-GS Prec.\n"; aux.resize(A->Dim()); eMG.resize(A->Dim()); ADiag0.resize(A->Dim()); FORALL(x,i) { if (dirichletBCs->isSet(i)) x[i] = dirichletBCs->value(i); } sol = &x; A->symmetricExpansion(); } //------------------------------------------------------------------------- void TrcNonLinearMLGS:: restr(Vector& rHigh, Vector& rLow, int level) { int i; Son* son; Generation& generation = *familyTree->getGeneration(level); Vector& criticM1 = *critical[level-1]; Vector& critic = *critical[level]; FORALL(criticM1,i) criticM1[i] = 0; FORALL(critic,i) { son = generation.getSon(i); if (son->NoOfFathers() == 1) criticM1[son->getFather()] = critic[i]; } FORALL(critic,i) { if (critic[i]) rHigh[i] = 0.0; } familyTree->restr(rHigh, rLow, level); Al[level-1]->resetDirichletEntries(rLow); restrictObstacles(level); MLMatrix* AMLM1 = Al[level-1]->castToMLMatrix(); MLMatrix* AML = Al[level]->castToMLMatrix(); AMLM1->markNodes(); // -> all nodes will be restricted AMLM1->GalerkinRestriction(*AML, generation, &critic); AMLM1->symmetricExpansion(); } //------------------------------------------------------------------------- void TrcNonLinearMLGS:: prolong(Vector& eLow, Vector& eHigh, int level) { int i; Vector& criticM1 = *critical[level-1]; Vector& critic = *critical[level]; FORALL(eLow,i) { if (criticM1[i]) eLow[i] = 0.0; } Al[level-1]->resetDirichletEntries(eLow); familyTree->prolong(eLow, eHigh, level); FORALL(eHigh,i) { if (critic[i]) eHigh[i] = 0.0; } } //------------------------------------------------------------------------- void TrcNonLinearMLGS:: setCritical(int node) { (*critical[maxLevel])[node] = True; } void TrcNonLinearMLGS:: setUnCritical(int node) { (*critical[maxLevel])[node] = False; } Bool TrcNonLinearMLGS:: isCritical(int node, int level) { return (*critical[level])[node]; } //------------------------------------------------------------------------- void NonLinearMLGS:: restrictObstacles(int highLevel) { int i, father1, father2; Real v1,v2,vm, meanv; Son* son; const Generation* generation = familyTree->getGeneration(highLevel); Vector& uppOM1 = *uppDefObstacle[highLevel-1]; Vector& uppO = *uppDefObstacle[highLevel]; Vector& lowOM1 = *lowDefObstacle[highLevel-1]; Vector& lowO = *lowDefObstacle[highLevel]; Vector& e = *el[highLevel]; FORALL(e,i) { uppO[i] -= real(e[i]); lowO[i] -= real(e[i]); } FORALL(uppO,i) { son = generation->getSon(i); if (son->NoOfFathers() == 1) { father1 = son->getFather(); uppOM1[father1] = uppO[i]; lowOM1[father1] = lowO[i]; } } FORALL(uppO,i) { son = generation->getSon(i); if (son->NoOfFathers() > 1) { father1 = son->getFather(1); father2 = son->getFather(2); v1= uppOM1[father1]; v2= uppOM1[father2]; vm = uppO[i]; meanv=(v1+v2)/2.; if (meanv != 0.0 && meanv > vm && !isCritical(i,highLevel)) { if (v1 > vm) { if (v2 > vm) { uppOM1[father1] = vm; uppOM1[father2] = vm; } else uppOM1[father1] = 2*vm - v2; } else { if (v2 > vm) uppOM1[father2] = 2*vm - v1; } } v1= lowOM1[father1]; v2= lowOM1[father2]; vm = lowO[i]; meanv=(v1+v2)/2.; //if (equal(meanv,0.0)) continue; //if (meanv >= vm) continue; if (meanv != 0.0 && meanv < vm && !isCritical(i,highLevel)) { if (v1 < vm) { if (v2 < vm) { lowOM1[father1] = vm; lowOM1[father2] = vm; } else lowOM1[father1] = 2*vm - v2; } else { if (v2 < vm) lowOM1[father2] = 2*vm - v1; } } } } // -- restore old values for post-smoothing: FORALL(e,i) { uppO[i] += real(e[i]); lowO[i] += real(e[i]); } }