/* $Id: problemtr.cc,v 1.5 1996/11/20 10:00:10 roitzsch Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "problemtr.h" #include "nodeco.h" #include "physics.h" #include "triang.h" #include "elements.h" #include "dirichlettr.h" #include "materialstr.h" #include "adapt.h" #include "linsystem.h" #include "sysmatml.h" #include "sysmatbl.h" #include "int.h" #include "cmdpars.h" extern CmdPars Cmd; //------------------------------------------------------------------------- TransientProblem:: TransientProblem() : uPrev(1), uPrevOnNewMesh(1) { transientMode = True; lumpedMass = True; Cmd.get("lumpedMass", &lumpedMass); plotTimeStep = False; Cmd.get("plotTimeStep", &plotTimeStep); postTimeStep = False; Cmd.get("postTimeStep", &postTimeStep); writeTimeStep = False; Cmd.get("writeTimeStep",&writeTimeStep); maxTimeSteps=1000; Cmd.get("maxTimeSteps", &maxTimeSteps); startTime = 0.0; Cmd.get("startTime", &startTime); if (!Cmd.get("endTime",&endTime)) MissingParameter("endTime"); theta = 1.0; Cmd.get("theta",&theta); if (theta < 0.5 || theta > 1) { cout << "\n*** Wrong value for theta given (" << theta << ") -- must be between 0.5 and 1.0\n"; cout.flush(); abort(); } if (equal(theta,1.0)) implicitEuler = True; else implicitEuler = False; midPointRule = False; Cmd.get("midPointRule", &midPointRule); if (midPointRule) { theta = 0.5; implicitEuler = False; } if ((constTimeStep = Cmd.isTrue("constTimeStep"))) { if (!Cmd.get("tau", &tau)) missingTau(); if (tau >= endTime) endTime = tau; } if (!constTimeStep) { tau = 0.1*(endTime-startTime); Cmd.get("Tau",&tau); // init. guess staticFirstStep = Cmd.isTrue("staticFirstStep"); if ((fixedFirstStep = Cmd.isTrue("fixedFirstStep"))) { if (!Cmd.get("tau", &tau)) missingTau(); if (tau >= endTime) tau = 0.99*endTime; } maxTau = 0.1*(endTime-startTime); Cmd.get("maxTau", &maxTau); rhoTime = 0.5; Cmd.get("rhoTime", &rhoTime); // 0.18 rhoSpace = 1.0-rhoTime-0.1; Cmd.get("rhoSpace", &rhoSpace); fSpace = 1.0; Cmd.get("fSpace", &fSpace); rhoSpace *= fSpace; maxReductions = 25; Cmd.get("maxReductions", &maxReductions); dynamicScaling = Cmd.isSet("scaling","dynamic"); } } //------------------------------------------------------------------------- void TransientProblem:: missingTau() { cout << "\n*** time step tau not specified\n"; cout.flush(); abort(); } //------------------------------------------------------------------------- void TransientProblem:: notImplemented(const char* name) const { cout << "\n*** class TransientProblem: function " << name << " not implemented\n"; cout.flush(); abort(); } //------------------------------------------------------------------------- void TransientProblem:: assembleGlobalDefect(MLMatrix& /*AD*/, Vector& /*MD*/, Vector& /*bD*/) { notImplemented("assembleGlobalDefect"); } //------------------------------------------------------------------------- Bool TransientProblem:: solve(Real relGlobalPrecision) { if (constTimeStep) return fixedTimeSteps (relGlobalPrecision); else return adaptiveTimeSteps(relGlobalPrecision); } //------------------------------------------------------------------------- Bool TransientProblem:: fixedTimeSteps(Real relGlobalPrecision) { Bool lastStep = False, absPrecision = False; int i, timeStep; time = startTime + tau; for (timeStep=1; timeStep<=maxTimeSteps; ++timeStep) { staticSolution(relGlobalPrecision, absPrecision, time); TransientSolutionInfo(timeStep, time, tau); if (lastStep) break; else if (time+tau >= endTime) { tau = endTime-time; lastStep = True; } if (equal(endTime+tau, endTime)) break; time += tau; uPrev.resize(u.high()); FORALL(u,i) uPrev[i] = u[i]; shiftMesh(); } if (timeStep > maxTimeSteps) { cout << "\n** Time step limit reached: " << timeStep << "\n"; return False; } else return True; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Bool TransientProblem:: adaptiveTimeSteps(Real globalPrecision) { int i, timeStep, reductions; Real statPrecision, newTau; Real UNorm, timeError, newUNorm; Bool lastStep = False; const Bool absPrecision = True; const Real TOL = sqrt(globalPrecision); time = startTime + tau; if (staticFirstStep) staticInitialSolution(&UNorm, TOL); else if (fixedFirstStep) initialUNorm(&UNorm); else adaptiveInitialSolution(&UNorm, TOL); newUNorm = UNorm; for (timeStep=1; timeStep<=maxTimeSteps; ++timeStep) { for (reductions=0; True; ++reductions) { if (dynamicScaling) UNorm = newUNorm; else if (timeStep == 1) UNorm = Max(UNorm,newUNorm); statPrecision = sqr(rhoSpace*TOL*UNorm); staticSolution(statPrecision, absPrecision, time); compTimeError(&timeError, &newUNorm, TOL); if (timeConvergence(TOL, timeError, UNorm, &newTau, timeStep, reductions)) break; if (fixedFirstStep && timeStep==1) break; time -= tau; tau = newTau; time += tau; } tau = newTau; TransientSolutionInfo(timeStep, time, tau); if (lastStep) break; else if (time+tau >= endTime) { tau = endTime-time; lastStep = True; } if (equal(endTime+tau, endTime)) break; time += tau; uPrev.resize(u.high()); FORALL(u,i) uPrev[i] = u[i]; // save solution for next step shiftMesh(); } if (timeStep > maxTimeSteps) { cout << "\n** Time step limit reached: " << timeStep << "\n"; return False; } else return True; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // -- one coarse initial solution step to compute UNorm for scaling: void TransientProblem:: initialUNorm(Real* UNorm) { staticSolution(0.05, False, time); // 5 % are sufficient *UNorm = compUNorm(u); cout << Form("\n Initial UNorm = %1.3g\n", *UNorm); TransientSolutionInfo(0, time, tau); } //------------------------------------------------------------------------- // -- try to find a good guess for the first time step by successively // reducing the tolerance void TransientProblem:: adaptiveInitialSolution(Real* UNorm, Real TOL) { Real tol, initTol, statPrecision, timeError, newTau; Bool absPrecision = True; int reductions; initialUNorm(UNorm); Real newUNorm = *UNorm; if (TOL >= 0.1) initTol = 2.1*TOL; else initTol = 0.1; cout << Form("\n Search for initial time step") << Form(" - start with TOL = %1.3g, UNorm = %1.3g\n",initTol,*UNorm); for (tol=initTol; tol >= 2.001*TOL; tol=0.5*tol) { for (reductions=0; True; ++reductions) { *UNorm = Max(*UNorm,newUNorm); statPrecision = sqr(rhoSpace*tol*(*UNorm)); staticSolution(statPrecision, absPrecision, time); compTimeError(&timeError, &newUNorm, tol); if (timeConvergence(tol, timeError, *UNorm, &newTau, 0, reductions)) break; tau = newTau; time = startTime + tau; } tau = newTau; TransientSolutionInfo(0, time, tau); time = startTime + tau; } } //------------------------------------------------------------------------- // -- static solution for tau = 0 to supply initial values void TransientProblem:: staticInitialSolution(Real* UNorm, Real TOL) { int i; Bool absPrecision = False; Real precision; time = startTime; transientMode = False; // -- one first coarse solution to get UNorm for absolute precision staticSolution(0.05, absPrecision, time); *UNorm = compUNorm(u); cout << Form("\n Static Initial Solution: UNorm = %1.3g\n", *UNorm); absPrecision = True; precision = sqr(rhoSpace*TOL*(*UNorm)); staticSolution(precision, absPrecision, time); TransientSolutionInfo(0, time, 0.0); time = startTime + tau; uPrev.resize(u.high()); FORALL(u,i) uPrev[i] = u[i]; // save solution for next step shiftMesh(); transientMode = True; } //------------------------------------------------------------------------- Real TransientProblem:: compUNorm(Vector& v, Vector* MDiag) { int i; Real minU = ::real(v[1]); FORALL(v,i) { if (::real(v[i]) < minU) minU = ::real(v[i]); } // FORALL(v,i) { if (::real(v[1]) < minU) minU = ::real(v[1]); } FORALL(v,i) v[i] -= minU; Real UNorm = 0.0; if (MDiag) FORALL(v,i) UNorm += Abs((*MDiag)[i] * v[i]*v[i]); else UNorm = 2.0*L2MassNorm(v); FORALL(v,i) v[i] += minU; return sqrt(UNorm); } //------------------------------------------------------------------------- Real TransientProblem:: L2MassNorm(const Vector& x) const { int dim; Real L2 = 0.0; PATCH* patch; dim = element->NoOfNodes(); Matrix AElem(dim,dim); Vector globalNodes(dim); Jacobian Jac; Mesh()->resetElemIter(); while ((patch = Mesh()->elemIterAll())) { patch->compJinv(Jac); element->initAb(AElem); element->assembleP(*patch, AElem, Jac, 0); interface->getGlobalNodes(patch, globalNodes); L2 += energyProd(AElem, x, globalNodes); } // L2 = sqrt(2.0*L2); // annihilate factor 1/2 in energy return L2; } //------------------------------------------------------------------------- Bool TransientProblem:: timeConvergence(Real TOL, Real timeError, Real UNorm, Real* newTau, int timeStep, int reductions) { Bool status; Real totalError, spaceError; if (timeError==0) *newTau = maxTau; else *newTau = tau * sqrt(rhoTime*TOL*UNorm/timeError); if (*newTau > maxTau) *newTau = maxTau; spaceError = sqrt(2.0*Error.Top()); totalError = timeError + spaceError; if ( (totalError < TOL*UNorm) || (totalError==0) ) status = True; else { status = False; *newTau *= 0.5; if (reductions > maxReductions) { cout << "\n*** Time Step reductions > maxReductions (" << maxReductions << ")\n"; cout.flush(); abort(); } } timeErrorInfo(totalError, timeError, spaceError, UNorm, TOL, tau, *newTau, timeStep, reductions); return status; } //------------------------------------------------------------------------- void TransientProblem:: timeErrorInfo(Real /*totalError*/, Real timeError, Real spaceError, Real UNorm, Real TOL, Real tau0, Real newTau, int timeStep, int reductions) { const char *format0 = "\n% 5s %10s %10s %7s %7s %8s %8s %3s %6s"; const char *format = "\n %5d %8.3g %% %8.3g %% %7.3g %7.3g %8.3g %8.3g %3d %6d\n"; Real absTOL = UNorm*TOL; cout << Form(format0, " TStep", "TimeError", "SpaceError", "TOL", "Norm", "tau", "new/tau", "red", "nodes"); cout << Form(format, timeStep, quot(100*timeError,absTOL), quot(100*spaceError,absTOL), TOL, UNorm, tau0, quot(newTau,tau0), reductions, interface->Dim()); cout << ' '; for (int i=1; i<=76; ++i) cout << '~'; cout << "\n"; // Pause(); } //------------------------------------------------------------------------- void TransientProblem:: TransientSolutionInfo(int timeStep, Real time0, Real tau0) { const int step = Error.high(); Real error = sqrt(quot(Error.Top(),Energy.Top())); const char *format0 = "\n %8s %10s %8s %5s %5s %9s %10s %10s"; const char *format = "\n %8d %10.3g %8.3g %5d %5d %9d %10.6g %10.3g\n"; cout << Form(format0,"TimeStep", "time(sec)", " new tau", "Steps", "level", "nodes", "ENorm", "rel.Error"); cout << Form(format, timeStep, time0, tau0, step, interface->MaxDepth(), interface->Dim(), sqrt(2.0*Energy.Top()), error); cout << ' '; for (int i=1; i<=76; ++i) cout << '='; cout << "\n"; if (plotTimeStep) interface->plot (u, step, fileName, timeStep); if (writeTimeStep) interface->write(u, step, fileName); if (postTimeStep > 0) if (timeStep%postTimeStep == 0) interface->autoPost(u, step, fileName, timeStep); while ( Pause() == picture ) interface->post (u, step, fileName); // Pause(); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // -- transport Solution of previous time step to the nodes of the new mesh void TransientProblem:: solutionToNewMesh(Vector& uPrevOnNewMesh0, const Interface* interfaceDLY) const { Timer timer; int i, k, n, node, comp; Vector x(spaceDim); const Interface* interf = interface; if (interfaceDLY) interf = interfaceDLY; const int lowNode = uPrevOnNewMesh0.low(); const int highNode = uPrevOnNewMesh0.high(); NodeCoordinates nc(spaceDim, lowNode, highNode); interf->getNodeCoordinates(nc); if (PrevMesh() == 0) // the first time step { node = lowNode; for (n=lowNode; n<=highNode; n+=nComp) { nc.getCoordinate(n,x); for (comp=1; comp<=nComp; ++comp) uPrevOnNewMesh0[node++] = dirichletBCs->initialValue(x, startTime, comp); } } else { Vector xUnit(spaceDim); Vector prevNodes(element->NoOfNodes()); Vector uLocal(element->NoOfNodes()); Vector nodes(interf->element->NoOfNodes()); const PATCH* patch, *prevPatch; Vector done(lowNode, highNode); FORALL(done,i) done[i] = False; MESH* mesh = Mesh(); mesh->resetElemIter(); while ((patch = mesh->elemIterAll())) { interf->getGlobalNodes(patch, nodes); for (n=1; n<=nodes.high(); n+=nComp) { if ((node=nodes[n]) >= lowNode) { if (!done[node]) { nc.getCoordinate(node, x); prevPatch = PrevMesh()->findPatch(x, xUnit, patch); interface->getGlobalNodes(prevPatch, prevNodes); FORALL(uLocal,k) uLocal[k] = uPrev[prevNodes[k]]; if (nComp==1) uPrevOnNewMesh0[node] = element->valueAt(xUnit, uLocal); else element->valueAt(xUnit, uLocal, uPrevOnNewMesh0, node, nComp); done[node] = True; } } } } } if (Cmd.isTrue("TimeTransport")) { cout << "\n\tSolution Transport: "; timer.cpu(); } /* FORALL(uPrevOnNewMesh0,node) { nc.getCoordinate(node,x); const PATCH* patch = PrevMesh()->findPatch(x, xUnit, 0); interface->getGlobalNodes(patch, prevNodes); FORALL(prevNodes,i) uLocal[i] = uPrev[prevNodes[i]]; uPrevOnNewMesh0[node] = element->valueAt(xUnit, uLocal); } */ } //------------------------------------------------------------------------- //------------------------------------------------------------------------- TransientHeatConduction:: TransientHeatConduction() { } //------------------------------------------------------------------------- DirichletBCs* TransientHeatConduction:: newDirichletBCs() { if (Cmd.isSet("DirichletBCs","ConstDirichlet")) return new ConstDirichletBCs(fileName); else if (Cmd.isSet("DirichletBCs","ConstTransDirichlet")) return new ConstTransDirichlet(fileName); else if (Cmd.isSet("DirichletBCs","StepDirichlet")) return new StepDirichlet(); else if (Cmd.isSet("DirichletBCs","UserTransient")) return new UserTransDirichlet(); else if (Cmd.isSet("DirichletBCs","JumpDirichlet")) return new JumpDirichlet(); else if (Cmd.isSet("DirichletBCs","TransDirichlet")) return new TransDirichlet(); else MissingParameter("DirichletBCs"); return 0; } //------------------------------------------------------------------------- void TransientHeatConduction:: newMaterial() { delete material; if (Cmd.isSet("Material","UserTransient")) material = new UserTransMaterial(fileName, spaceDim); else if (Cmd.isSet("Material","StepSource")) material = new StepSource(fileName, spaceDim); else if (Cmd.isSet("Material","DefaultMaterial")) material = new DefaultMaterial(fileName, spaceDim); else if (Cmd.isSet("Material","TransPeakSource")) material = new TransPeakSource(fileName, spaceDim); else MissingParameter("Material"); } //------------------------------------------------------------------------- void TransientHeatConduction:: assembleGlobal(Real time0) { if (transientMode) // initial static solution possible { uPrevOnNewMesh.resize(1,interface->Dim()); solutionToNewMesh(uPrevOnNewMesh); } Problem::assembleGlobal(time0); } //------------------------------------------------------------------------- void TransientHeatConduction:: assemble(const Element& elem, const PATCH& t, const Jacobian& Jac, Matrix& A, Vector& b, const Matrix* pattern, Bool errorEstimatorCall) { if (!transientMode) // initial static Solution { elem.assembleEllip (t,A,Jac,pattern); if (lumpedMass) elem.assembleLumpedMass(t,A,Jac,pattern); else elem.assembleMass(t,A,Jac,pattern); elem.assembleSource(t,b,Jac,pattern,time); if (t.onBoundary()) { elem.assembleCauchyBCs(t,A,b,pattern,time); elem.assembleNeumannBCs(t,b,pattern,time); } //if (Cmd.isTrue("innerBoundary")) elem.assembleInnerBCs(t,b,pattern,time); if (Mesh()->innerBoundary) elem.assembleInnerBCs(t,b,pattern,time); return; } int i, k; Real factor; const int dim = elem.NoOfNodes(); Matrix E(dim,dim); // 'elliptic' sub-matrix Matrix P(dim,dim); // 'parabolic' sub-matrix (mass-matrix) Vector s(dim), s0(dim); for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) E(i,k) = P(i,k) = 0.0; if (!elem.assembleEllip(t,E,Jac,pattern)) missingMaterialTerm("elliptic", t.Class()); if (lumpedMass) elem.assembleLumpedMass(t,E,Jac,pattern); else elem.assembleMass(t,E,Jac,pattern); if (!errorEstimatorCall) { Bool pTerm = False; if (lumpedMass) pTerm = elem.assembleLumpedP(t,P,Jac,pattern); else pTerm = elem.assembleP(t,P,Jac,pattern); if (!pTerm) missingMaterialTerm("mass (heat capacitance)",t.Class()); } else elem.assembleP(t,P,Jac,pattern); // no lumping for error estimator! // -- the contribution of the previous step to the right-hand side: if (!errorEstimatorCall) // ! A is used as working space { Vector nodes(dim); interface->getGlobalNodes(&t,nodes); if (implicitEuler) { if (lumpedMass) FORALL(b,i) b[i] += P(i,i)*uPrevOnNewMesh[nodes[i]]; else { for (i=1; i<=dim; ++i) for (k=1; k< i; ++k) P(k,i) = P(i,k); for (i=1; i<=dim; ++i) for (k=1; k<=dim; ++k) b[i] += P(i,k)*uPrevOnNewMesh[nodes[k]]; } } else { factor = tau*(1.0-theta); for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) { A(i,k) = P(i,k) - factor*E(i,k); A(k,i) = A(i,k); } for (i=1; i<=dim; ++i) for (k=1; k<=dim; ++k) b[i] += A(i,k) * uPrevOnNewMesh[nodes[k]]; } } // -- the stiffness matrix: factor = tau*theta; for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) A(i,k) = P(i,k) + factor*E(i,k); // -- the source term: if (material->SourceTerm(t.Class())) { FORALL(s,i) s[i] = 0.0; if (implicitEuler) elem.assembleSource(t,s,Jac,pattern,time); else if (midPointRule) elem.assembleSource(t,s,Jac,pattern,time-0.5*tau); else { FORALL(s0,i) s0[i] = 0.0; elem.assembleSource(t,s0,Jac,pattern,time-tau); elem.assembleSource(t,s, Jac,pattern,time); factor = 1.0-theta; FORALL(s,i) s[i] = theta*s[i] + factor*s0[i]; } FORALL(s,i) b[i] += tau*s[i]; } // -- the boundary conditions: if (t.onBoundary()) { Bool cauchyBCs = False; Bool neumBCs = False; for (i=1; i<=dim; ++i) { s[i] = 0.0; for (k=1; k<=i; ++k) P(i,k) = E(i,k) = 0.0; } if (implicitEuler) { cauchyBCs = elem.assembleCauchyBCs(t,P,s,pattern,time); neumBCs = elem.assembleNeumannBCs(t,s,pattern, time); } else if (midPointRule) { Real midTime = time - 0.5*tau; cauchyBCs = elem.assembleCauchyBCs(t,P,s,pattern,midTime); neumBCs = elem.assembleNeumannBCs(t,s,pattern, midTime); } else { FORALL(s0,i) s0[i] = 0.0; neumBCs = elem.assembleNeumannBCs(t,s0,pattern,time-tau); neumBCs = elem.assembleNeumannBCs(t,s,pattern, time); cauchyBCs = elem.assembleCauchyBCs(t,E,s0,pattern,time-tau); cauchyBCs = elem.assembleCauchyBCs(t,P,s,pattern, time); factor = 1.0-theta; if (cauchyBCs || neumBCs) s[i] = theta*s[i] + factor*s0[i] ; if (cauchyBCs) { for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) P(i,k) = theta*P(i,k) + factor*E(i,k); } } if (cauchyBCs || neumBCs) FORALL(b,i) b[i] += tau*s[i]; if (cauchyBCs) { for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) A(i,k) += tau*P(i,k); } } if (Mesh()->innerBoundary) { FORALL(s,i) s[i] = 0.0; if (implicitEuler) elem.assembleInnerBCs(t,s,pattern,time); else if (midPointRule) elem.assembleInnerBCs(t,s,pattern,time-0.5*tau); else { FORALL(s0,i) s0[i] = 0.0; elem.assembleInnerBCs(t,s0,pattern,time-tau); elem.assembleInnerBCs(t,s, pattern,time); factor = 1.0-theta; FORALL(s,i) s[i] = theta*s[i] + factor*s0[i]; } FORALL(s,i) b[i] += tau*s[i]; } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // -- assemble right-hand side for time error estimation and // multiplicative defect correction void TransientHeatConduction:: assembleGlobalDefect(MLMatrix& AD, Vector& MD, Vector& bD) { int i, node; PATCH* patch; const int dim = element->NoOfNodes(); Matrix AElem(dim,dim); Vector bElem(dim), MElem(dim); Vector nodes(dim); Jacobian Jac; AD.reset(); FORALL(bD,i) bD[i] = MD[i] = 0.0; Mesh()->resetElemIter(); while ((patch = Mesh()->elemIterAll())) { patch->compJinv(Jac); element->initAb(AElem,bElem); assembleDefect(*element, *patch, Jac, AElem, MElem, bElem); interface->getGlobalNodes(patch, nodes); AD.store(AElem, nodes); FORALL(nodes,i) if ((node=nodes[i])) { bD[node] += bElem[i]; MD[node] += MElem[i]; } } } //------------------------------------------------------------------------- void TransientHeatConduction:: assembleDefect(const Element& elem, const PATCH& t, const Jacobian& Jac, Matrix& AD, Vector& MD, Vector& bD) { int i, k; const int dim = elem.NoOfNodes(); Matrix P(dim,dim); // 'parabolic' sub-matrix (mass-matrix) Vector s0(dim); for (i=1; i<=dim; ++i) for (k=1; k<=i; ++k) P(i,k) = 0.0; elem.assembleEllip(t,AD,Jac,0); if (lumpedMass) { elem.assembleLumpedP(t,P,Jac,0); FORALL(MD,i) MD[i] = P(i,i); } else { elem.assembleP(t,P,Jac,0); for (i=1; i<=dim; ++i) for (k=1; k< i; ++k) P(k,i) = P(i,k); for (i=1; i<=dim; ++i) // lump Mass by row sum { MD[i] = 0.0; for (k=1; k<=dim; ++k) MD[i] += P(i,k); } } if (material->SourceTerm(t.Class())) { FORALL(s0,i) s0[i] = 0.0; elem.assembleSource(t,bD,Jac,0,time); elem.assembleSource(t,s0,Jac,0,time-tau); FORALL(bD,i) bD[i] -= s0[i]; } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- //#include "feplot1.h" //#include "triang1.h" void TransientProblem:: timeErrorByMidPointRule(Real* timeError, Real* UNorm, Real TOL) { int i; *UNorm = compUNorm(u); Vector u2(u.high()); FORALL(u,i) u2[i] = u[i]; const Bool midPointRule0 = midPointRule; const Real theta0 = theta; midPointRule = True; theta = 0.5; Problem::assembleGlobal(time); midPointRule = midPointRule0; theta = theta0; Real precision = sqr(rhoSpace*TOL); precision *= quot(sqr(*UNorm),Energy.Top()); int step = Energy.high(); Ab->solve(u2, 0.0, 0.0, precision, step); FORALL(u,i) u2[i] -= u[i]; *timeError = compUNorm(u2); } //------------------------------------------------------------------------- // -- this routine uses a multiplicative defect correction scheme // for time error estimation void TransientProblem:: compTimeError(Real* timeError, Real* UNorm, Real TOL) { if (Cmd.isSet("TError", "midPointRule")) // for test purposes { timeErrorByMidPointRule(timeError, UNorm, TOL); return; } static Real accTime = 0.0; Timer timer, accTimer; int i; const int dim = u.high(); MLMatrix* AD; if (nComp == 1) AD = new MLSparseMatrix(sym, SpaceDim(), dim); else AD = new MLBlockMatrix (sym, SpaceDim(), dim, nComp); Vector u2(dim), MD(dim), bD(dim), eta(dim); assembleGlobalDefect(*AD,MD,bD); *UNorm = compUNorm(u, &MD); FORALL(bD,i) u2[i] = u[i] - uPrevOnNewMesh[i]; AD->Mult(eta,u2); FORALL(bD,i) bD[i] = 0.5*tau * (eta[i] - bD[i]); // new right hand side FORALL(bD,i) if (dirichletBCs->isSet(i)) bD[i] = 0.0; dirichletBCs->setValuesToZero(); Ab->setRhs(bD); Real precision = sqr(rhoSpace*TOL); precision *= quot(sqr(*UNorm) , Energy.Top()); int step = Energy.high(); FORALL(eta,i) eta[i] = 0.0; Ab->solve(eta, 0.0, 0.0, precision, step); *timeError = compUNorm(eta, &MD); if (Cmd.isTrue("timeTimeError")) { cout << "\n\tTimeError Estimation: "; timer.cpu(); } if (Cmd.isTrue("accTimeTimeError")) { accTime += accTimer.cpu(False); cout << Form("\tAccumulated time: %1.2f sec.\n", accTime); } delete AD; //------------------------- test output ------------------------ /* MESH1 *mesh = (MESH1*) Mesh(); FEPlotMESH1 Plot(mesh, X11, "DefectCorrection", 0.4); Plot.plotElements(); Plot.plotBoundary(); FORALL(bD,i) u2[i] = u[i] + eta[i]; Plot.plotSolution(eta); Pause(); Real eNorm = sqrt(2.0*EnergyNorm(eta)); cout << "\n--- Time Error: eNorm=" << eNorm << " L2Mass= " << *timeError << " E/M = " << quot(eNorm,(*timeError)) << "\n"; AD.Mult(bD,eta); eNorm = sqrt(cdot(bD,eta)); Real tError = sqrt(2.0*L2MassNorm(eta)); cout << "--- Time Error: ellipNorm=" << eNorm << " L2Mass= " << tError << " Ell/M = " << quot(eNorm,tError) << "\n"; AD.Mult(bD,u); eNorm = sqrt(2.0*EllipticNorm(u)); cout << "--- Time Sol: eNorm=" << eNorm << " UNorm= " << *UNorm << " E/M = " << quot(eNorm,(*UNorm)) << "\n"; */ }