/* $Id: adaptnl.cc,v 1.2 1996/10/04 15:06:22 roitzsch Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "adaptnl.h" #include "utils.h" #include "numerics.h" #include "problemnl.h" #include "nonlin.h" #include "dirichletA.h" // !!! #include "elements.h" #include "triang.h" #include "int.h" #include "linsystem.h" #include "precondnl.h" #include "sysmatml.h" #include "family.h" #include "cmdpars.h" extern CmdPars Cmd; //------------------------------------------------------------------------- RK1:: RK1(Element* elementDLY0, Element* elementLag0, Interface* interface0) : DLY(elementDLY0, interface0), lagrangeElementDLY(elementLag0), doRefine(1) { } //------------------------------------------------------------------------- RK1:: ~RK1() { delete lagrangeElementDLY; } //------------------------------------------------------------------------- Bool RK1:: estimateError(Problem& problem) { if (infoErrorEstimator) cout << "\n\tError Est.: RK1"; distributeError(problem); enforcedPMediaRefinement(problem); return True; } //------------------------------------------------------------------------- void RK1:: distributeError(Problem& problem) { int i; Vector error(1), uQ(1), ADiag(1); solveQuadDefectProblem(problem, error, uQ, ADiag); interfaceDLY->solToHB(error); EnergyError = 0.0; for (i=problem.u.high()+1; i<=error.high(); ++i) { error[i] = error[i] * error[i] * ADiag[i]; // error on edge EnergyError += Abs(error[i]); // sum up global Error } EnergyError *= 0.5; distributeEdgeErrors(problem, error); } //------------------------------------------------------------------------- void RK1:: solveQuadDefectProblem(Problem& problem, Vector& error, Vector& uQ, Vector& ADiag) { int i, j; Num sum; PATCH* patch; MESH* mesh = problem.Mesh(); Vector& u = problem.u; const int edNodeM1 = u.high(); int edNode = edNodeM1; interfaceDLY->setHighOrderNodes(&edNode); error.resize(edNode); ADiag.resize(edNode); uQ.resize(edNode); FORALL(error,i) error[i] = ADiag[i] = 0.0; Vector uPrevOnNewMesh(1); TransientProblem* trP = 0; if ((trP = problem.castToTransientProblem())) { uPrevOnNewMesh.resize(edNodeM1+1, edNode); trP->solutionToNewMesh(uPrevOnNewMesh, interfaceDLY); } const int low = problem.element->NoOfNodes()+1; const int high = elementDLY->NoOfNodes(); Matrix AElem(high, high); Vector bElem(high); Vector globalNodes(high); Jacobian Jac; Vector LNorm(high); Vector lagrangeAreaWeights(error.high()); FORALL(lagrangeAreaWeights,i) lagrangeAreaWeights[i] = 0.0; Matrix FullDiag(high,high), LowDiag(high,high); FORALL_ROWS(FullDiag,i) FORALL_COLUMNS(FullDiag,j) FullDiag(i,j) = LowDiag(i,j) = False; for (i=1; i<=high; ++i) FullDiag(i,i) = True; for (i=1; i< low; ++i) LowDiag(i,i) = True; mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { patch->compJinv(Jac); elementDLY->initAb(AElem,bElem); problem.assemble(*elementDLY, *patch, Jac, AElem, bElem, elementDLY->DLYPattern, True); interfaceDLY->getGlobalNodes(patch, globalNodes); for (i=low; i<=high; ++i) // sum up diagonal AQQ { // and right hand side if (globalNodes[i] == 0) continue; ADiag[globalNodes[i]] += AElem(i,i); error[globalNodes[i]] += bElem[i]; sum = 0.0; for (j=1; jassembleLNorm(*patch, LNorm, Jac, &FullDiag); for (i=1; i<=high; ++i) if (globalNodes[i]) lagrangeAreaWeights[globalNodes[i]] += LNorm[i]; } if (trP) // transient problem: contrib. of previous step to rhs { const NonLinearity* nonLin = problem.getNonLinearity(); FORALL(uPrevOnNewMesh,i) error[i] += lagrangeAreaWeights[i] * nonLin->HValue(real(uPrevOnNewMesh[i])); } problem.Ab->Residual(error,u); interfaceDLY->rhsToNB(error); // residual from hier. to nodal Basis FORALL(uQ,i) uQ[i] = 0.0; FORALL(u,i) uQ[i] = u[i]; interfaceDLY->solToNB(uQ); // interpolate solution from lin. to // quad nodal Basis nonLinCorrection(error, uQ, ADiag, lagrangeAreaWeights, problem); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- void RK1:: nonLinCorrection(Vector& error, const Vector& uQ, const Vector& ADiag, const Vector& lagrangeAreaWeight, Problem& problem) { int i; Num res, a; Real uppDefO, lowDefO; // dummies Bool critical; const int dim = error.high(); Vector extUppO(dim), extLowO(dim); const NonLinearity* nonLin = problem.getNonLinearity(); nonLin->updateObstacles(extUppO, extLowO, *interfaceDLY); // -- one non-linear Jacobi-step: for (i=1; i<=dim; ++i) { res = error[i]; nonLin->defectCorrection(error[i], res, uQ[i], ADiag[i], a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); } } //------------------------------------------------------------------------- void RK1:: enforcedPMediaRefinement(Problem& problem) { int i; PATCH* patch; MESH* mesh = problem.Mesh(); doRefine.resize(mesh->noOfElements()); FORALL(doRefine,i) doRefine[i] = False; NonLinearity* NonLin = problem.getNonLinearity(); if (NonLin->castToPorousMedia()) { // -- force elements at the 'frontal boundary' to be refined: Vector& u = problem.u; Vector nodes(problem.element->NoOfNodes()); Num uMin = u[1]; Num uMax = u[1]; FORALL(u,i) { if (u[i] < uMin) uMin = u[i]; if (u[i] > uMax) uMax = u[i]; } Num upperBound = 1e-4; // upperBound=2.525e-5 upperBound *= (uMax - uMin); int no = 0; mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { ++no; problem.interface->getGlobalNodes(patch, nodes); uMin = 2.0*upperBound; Bool allNodesCritical = True; FORALL(nodes,i) if (nodes[i]) { if (!NonLin->isCritical(nodes[i])) allNodesCritical = False; if (u[nodes[i]] < uMin) uMin = u[nodes[i]]; } if (uMin < upperBound) doRefine[no] = True; if (allNodesCritical) doRefine[no] = False; } // -- extend forced refinement pattern: int noOfNeighbPatches=0; no = 0; mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { ++no; if (doRefine[no]) patch->setMark(); else patch->unMark(); noOfNeighbPatches = patch->noOfNeighbours(); } Vector neighb(noOfNeighbPatches); no = 0; mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { ++no; if (!doRefine[no]) { patch->getNeighbours(neighb); FORALL(neighb,i) { if (neighb[i]) if (neighb[i]->marked()) { doRefine[no] = True; break; } } } } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- RKA:: RKA(Element* elementDLY0, Element* elementLag0, Interface* interface0) : RK1(elementDLY0, elementLag0, interface0) { } //------------------------------------------------------------------------- Bool RKA:: estimateError(Problem& problem) { if (infoErrorEstimator) cout << "\n\tError Est.: RKA"; distributeError(problem); enforcedPMediaRefinement(problem); return True; } //------------------------------------------------------------------------- void RKA:: distributeError(Problem& problem) { int i; Vector error(1), uQ(1); MLSparseMatrix AQ(problem.Ab->symmetry, problem.SpaceDim()); solveQuadProblem(problem, error, uQ, AQ); AQ.Mult(uQ,error); EnergyError = 0.5 * Abs(cdot(uQ,error)); interfaceDLY->solToHB(error); for (i=problem.u.high()+1; i<=error.high(); ++i) { error[i] = error[i] * error[i] * AQ.Diag(i); // error on edge } distributeEdgeErrors(problem, error); //cout << "\n-- EnergyErr " << EnergyError << " EdgeErr " << EdgeError // << " d=" << 100*Abs(EdgeError-EnergyError)/EnergyError << " %\n"; } //------------------------------------------------------------------------- void RKA:: solveQuadProblem(Problem& problem, Vector& error, Vector& uQ, MLSparseMatrix& AQ) { int i; PATCH* patch; MESH* mesh = problem.Mesh(); const Vector& u = problem.u; const int edNodeM1 = u.high(); int edNode = edNodeM1; interfaceDLY->setHighOrderNodes(&edNode); uQ.resize(edNode); error.resize(edNode); FORALL(error,i) error[i] = 0.0; Vector uPrevOnNewMesh(1); TransientProblem* trP = 0; if ((trP = problem.castToTransientProblem())) { uPrevOnNewMesh.resize(1,edNode); trP->solutionToNewMesh(uPrevOnNewMesh, interfaceDLY); } // -- full assembling procedure for new lin. system: AQ.extend(edNode); LinSystem AbQ(problem.spaceDim, AQ.symmetry, problem.precond, problem.dirichletBCsDLY); AbQ.update(&AQ); AbQ.reset(); const int high = lagrangeElementDLY->NoOfNodes(); Matrix AElem(high,high); Vector bElem(high); Vector globalNodes(high); Jacobian Jac; Vector LNorm(high); Vector lagrangeAreaWeights(error.high()); FORALL(lagrangeAreaWeights,i) lagrangeAreaWeights[i] = 0.0; mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { patch->compJinv(Jac); lagrangeElementDLY->initAb(AElem,bElem); problem.assemble(*lagrangeElementDLY,*patch,Jac,AElem,bElem,0,True); // 0: use default symm. pattern interfaceDLY->getGlobalNodes(patch, globalNodes); AbQ.store(AElem, bElem, globalNodes); FORALL(LNorm,i) LNorm[i] = 0.0; lagrangeElementDLY->assembleLNorm(*patch,LNorm,Jac,0); for (i=1; i<=high; ++i) if (globalNodes[i]) lagrangeAreaWeights[globalNodes[i]] += LNorm[i]; } Real time = 0.0; if (trP) // transient problem: contrib. of previous step to rhs { const NonLinearity* nonLin = problem.getNonLinearity(); FORALL(uPrevOnNewMesh,i) AbQ.b[i] += lagrangeAreaWeights[i] * nonLin->HValue(uPrevOnNewMesh[i]); time = trP->time; } interfaceDLY->updateDirichletBCs(time); AbQ.setDirichletBCs(*problem.dirichletBCsDLY); // -- end of assembling proc. FORALL(uQ,i) uQ[i] = 0.0; FORALL(u,i) uQ[i] = u[i]; interfaceDLY->solToNB(uQ); // interpolate solution from lin. to // quad nodal Basis AbQ.Residual(error,uQ); nonLinCorrection(error, uQ, AQ, lagrangeAreaWeights, problem); } //------------------------------------------------------------------------- void RKA:: nonLinCorrection(Vector& error, const Vector& uQ, MLSparseMatrix& AQ, const Vector& lagrangeAreaWeight, Problem& problem) { int i; Num eNew, res, a; Real uppDefO, lowDefO; Bool critical; const int quadDim = error.high(); Vector extLowO(quadDim), extUppO(quadDim); const NonLinearity* nonLin = problem.getNonLinearity(); nonLin->updateObstacles(extUppO, extLowO, *interfaceDLY); if (Cmd.isSet("RKSmooth","GS")) // non-linear Gauss-Seidel steps: { AQ.symmetricExpansion(); Vector r(quadDim); FORALL(r,i) { r[i] = error[i]; error[i] = 0.0; } for (i=1; i<=quadDim; ++i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = AQ.MultRow(i,error); res = r[i] - res; nonLin->defectCorrection(error[i], res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); } for (i=quadDim; i>=1; --i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = AQ.MultRow(i,error); res = r[i] - res; nonLin->defectCorrection(eNew, res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); error[i] += eNew; } } else // non-linear Jacobi-step: { for (i=1; i<=quadDim; ++i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = error[i]; nonLin->defectCorrection(error[i], res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- RK2:: RK2(Element* elementDLY0, Element* elementLag0, Interface* interface0) : RKA(elementDLY0, elementLag0, interface0) { } //------------------------------------------------------------------------- Bool RK2:: estimateError(Problem& problem) { if (infoErrorEstimator) cout << "\n\tError Est.: RK2"; if (problem.precond->mode() != multiLevel) { cout << "\n*** RKC:: Preconditioner must be of multi-level-type:\n" << "NonLinearMLSG or TrcNonLinearMLSG\n"; cout.flush(); abort(); } distributeError(problem); enforcedPMediaRefinement(problem); return True; } //------------------------------------------------------------------------- void RK2:: nonLinCorrection(Vector& error, const Vector& uQ, MLSparseMatrix& AQ, const Vector& lagrangeAreaWeight, Problem& problem) { int i; Num eNew, res, a; Real uppDefO, lowDefO; Bool critical; const int quadDim = error.high(); Vector extLowO(quadDim), extUppO(quadDim); const NonLinearity* nonLin = problem.getNonLinearity(); nonLin->updateObstacles(extUppO, extLowO, *interfaceDLY); const int linDim = nonLin->lowObstacle.high(); Vector r(quadDim), Diag0(quadDim), aux(quadDim); FORALL(r,i) { r[i] = error[i]; error[i] = 0.0; Diag0[i] = AQ.Diag(i); } NonLinearMLGS* precond = (NonLinearMLGS*) problem.precond; Vector& uppDefObstacle = *precond->uppDefObstacle.Top(); Vector& lowDefObstacle = *precond->lowDefObstacle.Top(); FORALL(uppDefObstacle,i) { uppDefObstacle[i] = lowDefObstacle[i] = 0.0; precond->setUnCritical(i); } if (Cmd.isSet("RKSmooth","GS")) // non-linear Gauss-Seidel steps: { AQ.symmetricExpansion(); for (i=1; i<=quadDim; ++i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = AQ.MultRow(i,error); res = r[i] - res; nonLin->defectCorrection(error[i], res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); } for (i=quadDim; i>=1; --i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = AQ.MultRow(i,error); res = r[i] - res; nonLin->defectCorrection(eNew, res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); r[i] -= res; error[i] += eNew; AQ.Diag(i) += a; if (i <= linDim) { uppDefObstacle[i] = uppDefO - real(error[i]); lowDefObstacle[i] = lowDefO - real(error[i]); if (critical) precond->setCritical(i); else precond->setUnCritical(i); } } } else // non-linear Jacobi-step: { for (i=1; i<=quadDim; ++i) { if (problem.dirichletBCsDLY->isSet(i)) continue; res = r[i]; nonLin->defectCorrection(error[i], res, uQ[i], AQ.Diag(i), a, uppDefO, lowDefO, critical, extUppO[i], extLowO[i], lagrangeAreaWeight[i]); AQ.Diag(i) += a; r[i] -= res; if (i <= linDim) { uppDefObstacle[i] = uppDefO - real(error[i]); lowDefObstacle[i] = lowDefO - real(error[i]); if (critical) precond->setCritical(i); else precond->setUnCritical(i); } } } // -- restrict Matrix and residual to hierarchical linear basis: Generation gen(quadDim); interfaceDLY->setHBGeneration(gen); // for Galerkin-Restriction MLMatrix* ALin = precond->Al.Top()->castToMLMatrix(); ALin->reset(); ALin->markNodes(); ALin->GalerkinRestriction(AQ, gen); AQ.Mult(aux,error); FORALL(r,i) aux[i] = r[i] - aux[i]; // the new residual interfaceDLY->rhsToHB(aux); const int maxLevel = precond->maxLevel; Vector rLin(linDim); FORALL(rLin,i) { if (precond->isCritical(i,maxLevel)) rLin[i] = 0.0; else if (problem.dirichletBCs->isSet(i)) rLin[i] = 0.0; else rLin[i] = aux[i]; } // initialize the multi-level preconditioner and call one V-Cycle: const int nPreSmooth0 = precond->nPreSmooth; const int nPostSmooth0 = precond->nPostSmooth; precond->nPreSmooth = 1; precond->nPostSmooth = 1; Vector b(1); // a dummy precond->initialize(ALin, problem.u, b); Vector& eMG = precond->eMG; precond->el.push(&eMG); precond->MGCycle(eMG, *ALin, rLin, precond->maxLevel); precond->el.pop(); FORALL(aux,i) aux[i] = 0.0; FORALL(eMG,i) { if (!precond->isCritical(i, maxLevel) && !problem.dirichletBCs->isSet(i)) aux[i] = eMG[i]; } interfaceDLY->solToNB(aux); FORALL(error,i) error[i] += aux[i]; // -- restore preconditioner settings: precond->nPreSmooth = nPreSmooth0; precond->nPostSmooth = nPostSmooth0; FORALL(precond->Al,i) precond->Al[i]->removeSymmetricExpansion(); FORALL(Diag0,i) AQ.Diag(i) = Diag0[i]; // restore diagonal } //------------------------------------------------------------------------- //-------------------------------------------------------------------------