diff --git a/Solver/TESTCASES/MultirateAdvection.lua b/Solver/TESTCASES/MultirateAdvection.lua new file mode 100644 index 0000000000000000000000000000000000000000..3316a21e5ae29065903ceaec50c9e7aa85f1d2d5 --- /dev/null +++ b/Solver/TESTCASES/MultirateAdvection.lua @@ -0,0 +1,107 @@ +PI = 3.14159 + +--[[ + Function for initial conditions +--]] +function initial_condition( XYZ, FCT ) + for i=0,XYZ:size1()-1 do + X = XYZ:get(i,0) + Y = XYZ:get(i,1)+0.12 + V = math.exp(-(X*X+Y*Y)*100) + FCT:set(i,0,V) + end +end +function velocity( XYZ, FCT ) + for i=0,XYZ:size1()-1 do + X = XYZ:get(i,0) + Y = XYZ:get(i,1) + FCT:set(i,0,0) + FCT:set(i,1,1) + end +end + +--[[ + Example of a lua program driving the DG code +--]] + +order = 1 +print'*** Loading the mesh and the model ***' +myModel = GModel () + myModel:load ('rect.geo') +if (order == 1) then + myModel:load ('rect.msh') +elseif (order == 2) then + myModel:load ('rect2.msh') +elseif (order == 3) then + myModel:load ('rect3.msh') +elseif (order == 4) then + myModel:load ('rect4.msh') +elseif (order == 5) then + myModel:load ('rect5.msh') +end + +print'*** Create a dg solver ***' +velF = functionLua(2, 'velocity', {'XYZ'}):getName() +law=dgConservationLawAdvectionDiffusion(velF,"") + +g=fullMatrix(1,1); +g:set(0,0,0) +law:addBoundaryCondition('Walls',law:newOutsideValueBoundary(functionConstant(g):getName())) +law:addBoundaryCondition('Top',law:newOutsideValueBoundary(functionConstant(g):getName())) +FS = functionLua(1, 'initial_condition', {'XYZ'}):getName() + +GC=dgGroupCollection(myModel,2,order) +solTmp=dgDofContainer(GC,1) +solTmp:L2Projection(FS) +dt=GC:splitGroupsForMultirate(10,law,solTmp) +GC:buildGroupsOfInterfaces(myModel,2,order) +solution=dgDofContainer(GC,1) +solution:L2Projection(FS) +solution2=dgDofContainer(GC,1) +solution2:L2Projection(FS) +solution:exportGroupIdMsh() + +print'------------------- splitted !!' + +-- limiter = dgSlopeLimiter(law) +-- limiter:apply(solution) + +print'*** setting the initial solution ***' +--print'*** export ***' + +solution:exportMsh(string.format("output/rt-%06d", 0)) +solution2:exportMsh(string.format("outputMultirate/rt-%06d", 0)) + +print'*** solve ***' + +LC = 0.1*.1 +dt=dt +print('DT=',dt) +RK=dgRungeKutta() +multirateRK=dgRungeKuttaMultirate(GC,law) +norm1=solution:norm() +norm2=solution2:norm() +print('Norm: ',norm1,norm2) +dt=dt +time=0 +-- multirateRK:setLimiter(limiter) +--for i=1,1000 +i=0 +while time<0.5 do +-- norm1 = RK:iterate43SchlegelJCAM2009(law,dt,solution) +-- TEST with Explicit Euler multirate !!! + norm2 = multirateRK:iterate(dt,solution2) + time=time+dt + if (i % 10 == 0) then + print('*** ITER ***',i,time,norm2) + end + if (i % 10 == 0) then + solution:exportMsh(string.format("output/rt-%06d", i)) + solution2:exportMsh(string.format("outputMultirate/rt-%06d", i)) + end + i=i+1 +end + +print'*** done ***' + + diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp index 0366c576e59555cacb87affd418b3590f4f9f180..3b6cdeae80e26dd9f0dd97a51a7ed080a5cf960c 100644 --- a/Solver/dgAlgorithm.cpp +++ b/Solver/dgAlgorithm.cpp @@ -88,6 +88,8 @@ void dgAlgorithm::computeElementaryTimeSteps ( //dofManager &dof, // the DOF man dataCacheMap cacheMap; cacheMap.setNbEvaluationPoints(group.getNbIntegrationPoints()); dataCacheDouble &sol = cacheMap.provideData("Solution",1,nbFields); + dataCacheDouble &UVW = cacheMap.provideData("UVW",1,3); + UVW.set(group.getIntegrationPointsMatrix()); dataCacheElement &cacheElement = cacheMap.getElement(); // provided dataCache dataCacheDouble *maxConvectiveSpeed = claw.newMaxConvectiveSpeed(cacheMap); diff --git a/Solver/dgConservationLawAdvection.cpp b/Solver/dgConservationLawAdvection.cpp index 06674dd29fc019fb72a72e142614597c7b82fa22..e9bc0468546ee6280693f5b8da738e761891eb67 100644 --- a/Solver/dgConservationLawAdvection.cpp +++ b/Solver/dgConservationLawAdvection.cpp @@ -22,6 +22,23 @@ class dgConservationLawAdvectionDiffusion::advection : public dataCacheDouble { } } }; + +class dgConservationLawAdvectionDiffusion::maxConvectiveSpeed : public dataCacheDouble { + dataCacheDouble &v; + public: + maxConvectiveSpeed(std::string vFunctionName,dataCacheMap &cacheMap): + dataCacheDouble(cacheMap,1,1), + v(cacheMap.get(vFunctionName,this)) + { + }; + void _eval () { + int nQP = v().size1(); + for(int i=0; i< nQP; i++) { + _value(i,0) = hypot(v(i,0),v(i,1)); + } + } +}; + class dgConservationLawAdvectionDiffusion::riemann : public dataCacheDouble { dataCacheDouble &normals, &solLeft, &solRight,&v; public: @@ -67,6 +84,9 @@ dataCacheDouble *dgConservationLawAdvectionDiffusion::newConvectiveFlux( dataCac else return NULL; } +dataCacheDouble *dgConservationLawAdvectionDiffusion::newMaxConvectiveSpeed( dataCacheMap &cacheMap) const { + return new maxConvectiveSpeed(_vFunctionName,cacheMap); +} dataCacheDouble *dgConservationLawAdvectionDiffusion::newMaximumDiffusivity( dataCacheMap &cacheMap) const { if( !_nuFunctionName.empty()) return &cacheMap.get(_nuFunctionName); @@ -91,7 +111,6 @@ dgConservationLawAdvectionDiffusion::dgConservationLawAdvectionDiffusion(std::st _nuFunctionName = nuFunctionName; _nbf = 1; } - #include "Bindings.h" void dgConservationLawAdvectionDiffusionRegisterBindings (binding *b){ classBinding *cb = b->addClass<dgConservationLawAdvectionDiffusion>("dgConservationLawAdvectionDiffusion"); diff --git a/Solver/dgConservationLawAdvection.h b/Solver/dgConservationLawAdvection.h index 32f6fa58dd7a627c1fb7892d7ca2ff44e42afca9..65316de0587f55601f4b1ed7252539eb89448231 100644 --- a/Solver/dgConservationLawAdvection.h +++ b/Solver/dgConservationLawAdvection.h @@ -8,9 +8,11 @@ class dgConservationLawAdvectionDiffusion : public dgConservationLaw { class advection; class riemann; class diffusion; + class maxConvectiveSpeed; public: dataCacheDouble *newConvectiveFlux( dataCacheMap &cacheMap) const; dataCacheDouble *newMaximumDiffusivity( dataCacheMap &cacheMap) const; + dataCacheDouble *newMaxConvectiveSpeed( dataCacheMap &cacheMap) const; dataCacheDouble *newRiemannSolver( dataCacheMap &cacheMapLeft, dataCacheMap &cacheMapRight) const; dataCacheDouble *newDiffusiveFlux( dataCacheMap &cacheMap) const; dgConservationLawAdvectionDiffusion(std::string vFunctionName, std::string nuFunctionName); diff --git a/Solver/dgDofContainer.cpp b/Solver/dgDofContainer.cpp index 8abc615e793f4efeecaae1ba75d609c7c07d7c26..2b99c79fff2ba2e82e8836819c12f66874d00805 100644 --- a/Solver/dgDofContainer.cpp +++ b/Solver/dgDofContainer.cpp @@ -381,4 +381,6 @@ void dgDofContainer::registerBindings(binding *b){ cm->setArgNames("filename", NULL); cm = cb->addMethod("exportGroupIdMsh",&dgDofContainer::exportGroupIdMsh); cm->setDescription("Export the group ids for gmsh visualization"); + cm = cb->addMethod("norm",&dgDofContainer::norm); + cm->setDescription("Returns the norm of the vector"); } diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp index c23c533b4abc86c5ed19242a28e5c0bfd35709a8..1280771a70842a54f353123f984856c3f1eb5c43 100644 --- a/Solver/dgGroupOfElements.cpp +++ b/Solver/dgGroupOfElements.cpp @@ -570,6 +570,17 @@ void dgGroupOfFaces::mapLeftFromInterface ( int nFields, fullMatrix<double> &vLeft ) { + /*Msg::Info("Left for %p : gL %p %s %s %d, gR %p %s %s %d", + this, + &getGroupLeft(), + getGroupLeft().getIsInnerMultirateBuffer()?"Inner":"", + getGroupLeft().getIsOuterMultirateBuffer()?"Outer":"", + getGroupLeft().getMultirateExponent(), + &getGroupRight(), + getGroupRight().getIsInnerMultirateBuffer()?"Inner":"", + getGroupRight().getIsOuterMultirateBuffer()?"Outer":"", + getGroupRight().getMultirateExponent() + );*/ for(int i=0; i<getNbElements(); i++) { const std::vector<int> &closureRight = getClosureRight(i); const std::vector<int> &closureLeft = getClosureLeft(i); @@ -584,6 +595,19 @@ void dgGroupOfFaces::mapRightFromInterface ( int nFields, fullMatrix<double> &vRight ) { + /*Msg::Info("Right for %p : gL %p %s %s %d, gR %p %s %s %d", + this, + &getGroupLeft(), + getGroupLeft().getIsInnerMultirateBuffer()?"Inner":"", + getGroupLeft().getIsOuterMultirateBuffer()?"Outer":"", + getGroupLeft().getMultirateExponent(), + &getGroupRight(), + getGroupRight().getIsInnerMultirateBuffer()?"Inner":"", + getGroupRight().getIsOuterMultirateBuffer()?"Outer":"", + getGroupRight().getMultirateExponent() + );*/ + if(isBoundary()) + return; for(int i=0; i<getNbElements(); i++) { const std::vector<int> &closureRight = getClosureRight(i); const std::vector<int> &closureLeft = getClosureLeft(i); @@ -939,7 +963,7 @@ void dgGroupCollection::buildGroupsOfInterfaces() { // Split the groups of elements depending on their local time step double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLaw *claw, dgDofContainer *solution){ Msg::Info("Splitting Groups for multirate time stepping"); - maxLevels--; + maxLevels--;// Number becomes maximum id int maxNumElems=getElementGroup(0)->getElement(0)->getGlobalNumber()+1; std::vector<int>oldGroupIds; oldGroupIds.resize(maxNumElems); diff --git a/Solver/dgResidual.cpp b/Solver/dgResidual.cpp index ade2dbbf2883f302cacb7bc67ec7c99e9d36f13a..ed4d206d93bb037acbcda4191a2d417eb705bd72 100644 --- a/Solver/dgResidual.cpp +++ b/Solver/dgResidual.cpp @@ -227,6 +227,17 @@ void dgResidualInterface::compute1Group ( //dofManager &dof, // the DOF manager void dgResidualInterface::computeAndMap1Group (dgGroupOfFaces &faces, dgDofContainer &solution, dgDofContainer &residual) { +/* Msg::Info("Left and Right for %p : gL %p %s %s %d, gR %p %s %s %d", + &faces, + &faces.getGroupLeft(), + faces.getGroupLeft().getIsInnerMultirateBuffer()?"Inner":"", + faces.getGroupLeft().getIsOuterMultirateBuffer()?"Outer":"", + faces.getGroupLeft().getMultirateExponent(), + &faces.getGroupRight(), + faces.getGroupRight().getIsInnerMultirateBuffer()?"Inner":"", + faces.getGroupRight().getIsOuterMultirateBuffer()?"Outer":"", + faces.getGroupRight().getMultirateExponent() + );*/ fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2*_nbFields); fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2*_nbFields); faces.mapToInterface(_nbFields, solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupRight()), solInterface); @@ -337,9 +348,9 @@ void dgResidualBoundary::computeAndMap1Group(dgGroupOfFaces &faces, dgDofContain int _nbFields = _claw.getNbFields(); fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*_nbFields); fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*_nbFields); - faces.mapToInterface(_nbFields, solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupRight()), solInterface); + faces.mapToInterface(_nbFields, solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupLeft()), solInterface); compute1Group(faces,solInterface,solution.getGroupProxy(&faces.getGroupLeft()),residuInterface); - faces.mapFromInterface(_nbFields, residuInterface, residual.getGroupProxy(&faces.getGroupLeft()), residual.getGroupProxy(&faces.getGroupRight())); + faces.mapFromInterface(_nbFields, residuInterface, residual.getGroupProxy(&faces.getGroupLeft()), residual.getGroupProxy(&faces.getGroupLeft())); } void dgResidual::compute(dgGroupCollection &groups, dgDofContainer &solution, dgDofContainer &residual) @@ -349,8 +360,9 @@ void dgResidual::compute(dgGroupCollection &groups, dgDofContainer &solution, dg for (int i=0; i<groups.getNbElementGroups(); i++) residualVolume.computeAndMap1Group(*groups.getElementGroup(i), solution, residual); dgResidualInterface residualInterface(_claw); - for(size_t i=0;i<groups.getNbFaceGroups() ; i++) + for(size_t i=0;i<groups.getNbFaceGroups() ; i++){ residualInterface.computeAndMap1Group(*groups.getFaceGroup(i), solution, residual); + } dgResidualBoundary residualBoundary(_claw); for(size_t i=0;i<groups.getNbBoundaryGroups() ; i++) residualBoundary.computeAndMap1Group(*groups.getBoundaryGroup(i), solution, residual); diff --git a/Solver/dgRungeKutta.cpp b/Solver/dgRungeKutta.cpp index 41eb3b325abc2c3a380d820a881d95624ab61f00..f8391bc00683c606660f5be49cd979a91fa3395f 100644 --- a/Solver/dgRungeKutta.cpp +++ b/Solver/dgRungeKutta.cpp @@ -1,3 +1,4 @@ +#include <stdlib.h> #include "dgRungeKutta.h" #include "dgConservationLaw.h" #include "dgDofContainer.h" @@ -5,6 +6,7 @@ #include "dgResidual.h" #include "dgGroupOfElements.h" #include <stdio.h> +#include <algorithm> double dgRungeKutta::iterateEuler(const dgConservationLaw *claw, double dt, dgDofContainer *solution) { double A[] = {0}; @@ -145,7 +147,7 @@ double dgRungeKutta::nonDiagonalRK(const dgConservationLaw *claw, double dt, dgDofContainer *solution, int nStages, - fullMatrix<double>&A, // c | A + fullMatrix<double>&A, // c | A double *b, // Standard Butcher tableau notation :___|__ double *c // |b^T ) @@ -191,6 +193,7 @@ double dgRungeKutta::nonDiagonalRK(const dgConservationLaw *claw, iMassEl.mult(residuEl,KEl); } } + //Msg::Info("norm %d %0.16e",i,K[i]->norm()); Unp.axpy(*K[i],dt*b[i]); } if (_limiter) _limiter->apply(&Unp); @@ -205,184 +208,6 @@ double dgRungeKutta::nonDiagonalRK(const dgConservationLaw *claw, } -double dgRungeKutta::iterate43Multirate(const dgConservationLaw *claw, double dt, - dgDofContainer *solution) -{ - double A[4][4]={ - {0, 0, 0, 0}, - {1.0/2.0, 0, 0 ,0}, - {-1.0/6.0, 2.0/3.0, 0, 0}, - {1.0/3.0, -1.0/3.0, 1, 0} - }; - double b[4]={1.0/6.0, 1.0/3.0, 1.0/3.0, 1.0/6.0}; - double c[4]={0, 1.0/2.0, 1.0/2.0, 1}; - - dgGroupCollection *groups=solution->getGroups(); - int dtMaxExponent=groups->getDtMaxExponent(); - int nSmallSteps=1; - { - int i=0; - while(i<dtMaxExponent){ - nSmallSteps*=2; - i++; - } - } - - int nbFields = claw->getNbFields(); - dgDofContainer **K; - K=new dgDofContainer*[4]; - for(int i=0;i<4;i++){ - K[i]=new dgDofContainer(groups,nbFields); - K[i]->scale(0.); - } - dgDofContainer Unp (groups,nbFields); - dgDofContainer tmp (groups,nbFields); - dgDofContainer resd(groups,nbFields); - -// axpy for each group to build the right input vector for the residual -// At each stage, update the residual for a std::vector of groups, using residualForSomeGroups - -// K0 for everyone -// K1 K2 K3 for the smallestDt group and its corresponding buffer -// smallestDt can be updated for the first smallset time step -// K4 for the smallest Dt and the buffer and K1 for the larger Dt -// K0 for the smallest Dt, K5 for the buffer, and K2 for the larger Dt -// K1 K2 K3 for the smallestDt and K6 K7 K8 for the buffer -// K4 for the smallest Dt and K9 for the buffer, K3 for the larger Dt -// update for everyone - - - -/* - for(int iStep=0;iStep<nSmallSteps;iStep++){ - for(int iGroup=0; iGroup < groups->getNbElementGroups(); iGroup++) { - for(int iStage=0;iStage<4;iStage++){ - dgGroupOfElements *group=groups->getElementGroup(iGroup); - int groupDtExponent=group->getMultirateExponent(); - } - tmp.scale(0.0); - tmp.axpy(*solution); - for(int j=0;j<i;j++){ - if(fabs(A(i,j))>1e-12){ - tmp.axpy(*K[j],dt*A(i,j)); - } - } - if (_limiter) _limiter->apply(&tmp); - dgAlgorithm::residual(*claw,*groups,tmp,resd); - - // Multiply the spatial residual by the inverse of the mass matrix - int nbNodes = group->getNbNodes(); - for(int j=0;j<group->getNbElements();j++) { - residuEl.setAsProxy(resd.getGroupProxy(k),j*nbFields,nbFields); - KEl.setAsProxy(K[i]->getGroupProxy(k),j*nbFields,nbFields); - iMassEl.setAsProxy(group->getInverseMassMatrix(),j*nbNodes,nbNodes); - iMassEl.mult(residuEl,KEl); - } - } - Unp.axpy(*K[i],dt*b[i]); - } - } - */ -/* - int nStages=10; - // Small step RK43 - double _A1[10][10]={ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/4.0 ,0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-1.0/12.0, 1.0/3.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/6.0, -1.0/6.0, 1.0/2.0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, 0, 0, 0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, 0, 0, 0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, 1.0/4.0, 0, 0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, -1.0/12.0, 1.0/3.0, 0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, 1.0/6.0, -1.0/6.0, 1.0/2.0, 0, 0}, - {1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0, 1.0/12.0, 1.0/6.0, 1.0/6.0, 1.0/12.0, 0} - }; - double b1[10]={1.0/12.0, 1.0/6.0, 1.0/6.0,1.0/12.0,0,1.0/12.0, 1.0/6.0, 1.0/6.0,1.0/12.0,0}; - double c1[10]={0, 1.0/4.0, 1.0/4.0, 1.0/2.0, 1.0/2.0, 1.0/2.0, 3.0/4.0, 3.0/4.0, 1, 1 }; - - // Big step RK43 - double _A2[10][10]={ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/4.0 , 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/4.0 , 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/2.0 , 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0/2.0 , 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-1.0/6.0, 0, 0, 0, 2.0/3.0, 0, 0, 0, 0, 0}, - {1.0/12.0, 0, 0, 0, 1.0/6.0, 1.0/2.0, 0, 0, 0, 0}, - {1.0/12.0, 0, 0, 0, 1.0/6.0, 1.0/2.0, 0, 0, 0, 0}, - {1.0/3.0 , 0, 0, 0, -1.0/3.0, 1, 0, 0, 0, 0}, - {1.0/3.0 , 0, 0, 0, -1.0/3.0, 1, 0, 0, 0, 0}, - }; - double b2[10]={1.0/6.0, 0 , 0 , 0 , 1.0/3.0,1.0/3.0, 0 , 0 , 0 , 1.0/6.0}; - double c2[10]={0, 1.0/4.0, 1.0/4.0, 1.0/2.0, 1.0/2.0, 1.0/2.0, 3.0/4.0, 3.0/4.0, 1, 1 }; - fullMatrix<double> A1(10,10); - fullMatrix<double> A2(10,10); - for(int i=0;i<10;i++){ - for(int j=0;j<10;j++){ - A1(i,j)=_A1[i][j]; - A2(i,j)=_A2[i][j]; - } - } - - - dgGroupCollection *groups=solution->getGroups(); - fullMatrix<double> residuEl, KEl; - fullMatrix<double> iMassEl; - - int nbFields = claw->getNbFields(); - - dgDofContainer **K; - K=new dgDofContainer*[nStages]; - for(int i=0;i<nStages;i++){ - K[i]=new dgDofContainer(groups,nbFields); - K[i]->scale(0.); - } - dgDofContainer Unp (groups,nbFields); - dgDofContainer tmp (groups,nbFields); - dgDofContainer resd(groups,nbFields); - - Unp.scale(0.0); - Unp.axpy(*solution); - for(int i=0; i<nStages;i++){ - tmp.scale(0.0); - tmp.axpy(*solution); - for(int j=0;j<i;j++){ - if(fabs(A(i,j))>1e-12){ - tmp.axpy(*K[j],dt*A(i,j)); - } - } - if (_limiter) _limiter->apply(&tmp); - dgAlgorithm::residual(*claw,*groups,tmp,resd); - - // Multiply the spatial residual by the inverse of the mass matrix - for(int k=0; k < groups->getNbElementGroups(); k++) { - dgGroupOfElements *group = groups->getElementGroup(k); - int nbNodes = group->getNbNodes(); - for(int j=0;j<group->getNbElements();j++) { - residuEl.setAsProxy(resd.getGroupProxy(k),j*nbFields,nbFields); - KEl.setAsProxy(K[i]->getGroupProxy(k),j*nbFields,nbFields); - iMassEl.setAsProxy(group->getInverseMassMatrix(),j*nbNodes,nbNodes); - iMassEl.mult(residuEl,KEl); - } - } - Unp.axpy(*K[i],dt*b[i]); - } - if (_limiter) _limiter->apply(&Unp); - solution->scale(0.); - solution->axpy(Unp); - - for(int i=0;i<nStages;i++){ - delete K[i]; - } - delete []K; - return solution->norm(); -*/ - - return 0.; -} - - dgRungeKutta::dgRungeKutta():_limiter(NULL) {} @@ -415,9 +240,6 @@ void dgRungeKutta::registerBindings(binding *b) { cm = cb->addMethod("iterateRKFehlberg45",&dgRungeKutta::iterateRKFehlberg45); cm->setArgNames("law","dt","solution",NULL); cm->setDescription("update solution by doing a six stage fifth order Runge-Kutta-Fehlberg step of time step dt for the conservation law"); - cm = cb->addMethod("iterate43Multirate",&dgRungeKutta::iterate43Multirate); - cm->setArgNames("law","dt","solution",NULL); - cm->setDescription("update solution by doing a multirate RK43 (from Schlegel et al. Journal of Computational and Applied Mathematics, 2009) step of base time step dt for the conservation law"); cm = cb->addMethod("setLimiter",&dgRungeKutta::setLimiter); cm->setArgNames("limiter",NULL); cm->setDescription("if a limiter is set, it is applied after each RK stage"); @@ -427,6 +249,7 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio _law=law; _residualVolume=new dgResidualVolume(*_law); _residualInterface=new dgResidualInterface(*_law); + _residualBoundary=new dgResidualBoundary(*_law); _K=new dgDofContainer*[10]; for(int i=0;i<10;i++){ _K[i]=new dgDofContainer(gc,_law->getNbFields()); @@ -434,6 +257,8 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio } _currentInput=new dgDofContainer(gc,_law->getNbFields()); _currentInput->setAll(0.0); + _residual=new dgDofContainer(gc,_law->getNbFields()); + _residual->setAll(0.0); _minExponent=INT_MAX; _maxExponent=0; for(int iGroup=0;iGroup<gc->getNbElementGroups();iGroup++){ @@ -453,14 +278,17 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio _bulkGroupsOfElements[ge->getMultirateExponent()].first.push_back(ge); } } +// std::vector<std::set<dgGroupOfFaces*> >bulkFacesSet; +// std::vector<std::set<dgGroupOfFaces*> >innerBufferFacesSet; +// std::vector<std::set<dgGroupOfFaces*> >outerBufferFacesSet; +// bulkFacesSet.resize(_maxExponent+1); +// innerBufferFacesSet.resize(_maxExponent+1); +// outerBufferFacesSet.resize(_maxExponent+1); for(int iGroup=0;iGroup<gc->getNbFaceGroups();iGroup++){ dgGroupOfFaces *gf=gc->getFaceGroup(iGroup); const dgGroupOfElements *ge[2]; ge[0]=&gf->getGroupLeft(); ge[1]=&gf->getGroupRight(); - if(ge[0]==ge[1]){ - _bulkGroupsOfElements[ge[0]->getMultirateExponent()].second.push_back(gf); - } for(int i=0;i<2;i++){ if(ge[i]->getIsInnerMultirateBuffer()){ _innerBufferGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); @@ -472,15 +300,51 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio } } } + for(int iGroup=0;iGroup<gc->getNbBoundaryGroups();iGroup++){ + dgGroupOfFaces *gf=gc->getBoundaryGroup(iGroup); + const dgGroupOfElements *ge[1]; + ge[0]=&gf->getGroupLeft(); + //ge[1]=&gf->getGroupRight(); + for(int i=0;i<1;i++){ + if(ge[i]->getIsInnerMultirateBuffer()){ + _innerBufferGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); + } + else if(ge[i]->getIsOuterMultirateBuffer()){ + _outerBufferGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); + }else{ + _bulkGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); + } + } + } + // Removing duplicate entries + for(int iExp=0;iExp<=_maxExponent;iExp++){ + std::vector<dgGroupOfFaces*>*v[3]; + v[0]=&_innerBufferGroupsOfElements[iExp].second; + v[1]=&_outerBufferGroupsOfElements[iExp].second; + v[2]=&_bulkGroupsOfElements[iExp].second; + for(int i=0;i<3;i++){ + sort(v[i]->begin(),v[i]->end()); + v[i]->erase(unique(v[i]->begin(),v[i]->end()),v[i]->end()); + } + } } dgRungeKuttaMultirate::~dgRungeKuttaMultirate(){ for(int i=0;i>10;i++){ delete _K[i]; } delete []_K; + delete _residual; + delete _currentInput; + delete _residualVolume; + delete _residualInterface; + delete _residualBoundary; } -void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ +void dgRungeKuttaMultirate::computeInputForK(int iK,int exponent,bool isBuffer){ + if(exponent>_maxExponent){ + return; + } + //Msg::Info("Input for K%d at level %d %s",iK,exponent,isBuffer?"Buffer":"Bulk"); double localDt=_dt/pow(2.0,(double)exponent); double _A[4][4]={ {0, 0, 0, 0}, @@ -514,8 +378,6 @@ void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ {1.0/3.0 , 0, 0, 0, -1.0/3.0, 1, 0, 0, 0, 0}, {1.0/3.0 , 0, 0, 0, -1.0/3.0, 1, 0, 0, 0, 0}, }; - if(exponent>_maxExponent) - return; // Msg::Info("K%d, %d, %s",iK,exponent,isBuffer?"Buffer":"Bulk"); // compute K[iK] for this exponent and buffer if(isBuffer){ @@ -527,9 +389,9 @@ void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ _currentInput->axpy(gVo,*_solution,1.0); for(int i=0;i<iK;i++){ if(_AInner[iK][i]!=0.0) - _currentInput->axpy(gVi,*_K[i],_AInner[iK][i]*localDt); + _currentInput->axpy(gVi,*_K[i],_AInner[iK][i]*localDt*2); if(_AOuter[iK][i]!=0.0) - _currentInput->axpy(gVo,*_K[i],_AOuter[iK][i]*localDt); + _currentInput->axpy(gVo,*_K[i],_AOuter[iK][i]*localDt*2); } } else{ @@ -537,47 +399,55 @@ void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ _currentInput->scale(gV,0.0); _currentInput->axpy(gV,*_solution,1.0); for(int i=0;i<iK;i++){ - if(_A[iK][i]!=0.0) + if(_A[iK][i]!=0.0){ _currentInput->axpy(gV,*_K[i],_A[iK][i]*localDt); + } } } - computeResidual(exponent,isBuffer,_currentInput,_K[iK]); - /* - printf("%s%d\t",isBuffer?"B":"N",exponent); - for(int i=0;i<exponent;i++) - printf(" |"); - printf(" K%d\n",iK); - */ + if(!isBuffer){ switch(iK){ case 0: - for(int i=0;i<4;i++){ - computeK(i,exponent+1,true); - } + computeInputForK(0,exponent+1,true); break; case 1: - computeK(4,exponent+1,true); + computeInputForK(4,exponent+1,true); break; case 2: - for(int i=5;i<9;i++){ - computeK(i,exponent+1,true); - } + computeInputForK(5,exponent+1,true); break; case 3: - computeK(9,exponent+1,true); + computeInputForK(9,exponent+1,true); break; } } else{ if( (iK%5)<4 ){ - computeK(iK%5,exponent,false); + computeInputForK(iK%5,exponent,false); } } + computeK(iK,exponent,isBuffer); +// Msg::Info("Multirate %d %0.16e",iK,_K[iK]->norm()); if( (iK==3 && !isBuffer) || (iK==9 && isBuffer) ){ updateSolution(exponent,isBuffer); } + if(!isBuffer){ + switch(iK){ + case 0: + for(int i=1;i<4;i++){ + computeInputForK(i,exponent+1,true); + } + break; + case 2: + for(int i=6;i<9;i++){ + computeInputForK(i,exponent+1,true); + } + break; + } + } } void dgRungeKuttaMultirate::updateSolution(int exponent,bool isBuffer){ + //Msg::Info("Updating solution at level %d %s",exponent,isBuffer?"Buffer":"Bulk"); double localDt=_dt/pow(2.0,(double)exponent); double b[4]={1.0/6.0, 1.0/3.0, 1.0/3.0, 1.0/6.0}; double c[4]={0, 1.0/2.0, 1.0/2.0, 1}; @@ -590,9 +460,9 @@ void dgRungeKuttaMultirate::updateSolution(int exponent,bool isBuffer){ std::vector<dgGroupOfElements *>&gVo=_outerBufferGroupsOfElements[exponent].first; for(int i=0;i<10;i++){ if(bInner[i]!=0.0) - _solution->axpy(gVi,*_K[i],bInner[i]*localDt); + _solution->axpy(gVi,*_K[i],bInner[i]*localDt*2); if(bOuter[i]!=0.0) - _solution->axpy(gVi,*_K[i],bOuter[i]*localDt); + _solution->axpy(gVo,*_K[i],bOuter[i]*localDt*2); } } else{ @@ -603,55 +473,103 @@ void dgRungeKuttaMultirate::updateSolution(int exponent,bool isBuffer){ } } } -void dgRungeKuttaMultirate::computeResidual(int exponent,bool isBuffer,dgDofContainer *solution, dgDofContainer *residual){ +void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ + //Msg::Info("Compute K%d at level %d %s",iK,exponent,isBuffer?"Buffer":"Bulk"); if(isBuffer){ std::vector<dgGroupOfElements *>&vei=_innerBufferGroupsOfElements[exponent].first; std::vector<dgGroupOfElements *>&veo=_outerBufferGroupsOfElements[exponent].first; - residual->scale(vei,0.0); - residual->scale(veo,0.0); + _residual->scale(vei,0.0); + _residual->scale(veo,0.0); for(int i=0;i<vei.size();i++){ - _residualVolume->computeAndMap1Group(*vei[i], *solution, *residual); + _residualVolume->computeAndMap1Group(*vei[i], *_currentInput, *_residual); } for(int i=0;i<veo.size();i++){ - _residualVolume->computeAndMap1Group(*veo[i], *solution, *residual); + _residualVolume->computeAndMap1Group(*veo[i], *_currentInput, *_residual); } std::vector<dgGroupOfFaces *>& vfi=_innerBufferGroupsOfElements[exponent].second; std::vector<dgGroupOfFaces *>& vfo=_outerBufferGroupsOfElements[exponent].second; std::set<dgGroupOfFaces *>gOFSet; gOFSet.insert(vfo.begin(),vfo.end()); + gOFSet.insert(vfi.begin(),vfi.end()); for(std::set<dgGroupOfFaces *>::iterator it=gOFSet.begin();it!=gOFSet.end();it++){ dgGroupOfFaces *faces=*it; - const dgGroupOfElements *gL=&faces->getGroupLeft(); - const dgGroupOfElements *gR=&faces->getGroupRight(); - fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); - fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); - faces->mapToInterface(_law->getNbFields(), solution->getGroupProxy(gL), solution->getGroupProxy(gR), solInterface); - _residualInterface->compute1Group(*faces,solInterface,solution->getGroupProxy(gL), solution->getGroupProxy(gR),residuInterface); - if(gL->getMultirateExponent()==exponent && gL->getIsMultirateBuffer()) - faces->mapLeftFromInterface(_law->getNbFields(), residuInterface,residual->getGroupProxy(gL)); - if(gL->getMultirateExponent()==exponent && gL->getIsMultirateBuffer()) - faces->mapRightFromInterface(_law->getNbFields(), residuInterface,residual->getGroupProxy(gR)); + if(faces->isBoundary()){ + _residualBoundary->computeAndMap1Group(*faces,*_currentInput,*_residual); + //Msg::Info("Buffer face group %p is boundary in multirate",faces); + } + else{ + const dgGroupOfElements *gL=&faces->getGroupLeft(); + const dgGroupOfElements *gR=&faces->getGroupRight(); + fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); + fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); + faces->mapToInterface(_law->getNbFields(), _currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR), solInterface); + _residualInterface->compute1Group(*faces,solInterface,_currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR),residuInterface); + //Msg::Info("Buffer face group %p is mapped left or right in multirate",faces); + if(gL->getMultirateExponent()==exponent && gL->getIsMultirateBuffer()) + faces->mapLeftFromInterface(_law->getNbFields(), residuInterface,_residual->getGroupProxy(gL)); + if(gR->getMultirateExponent()==exponent && gR->getIsMultirateBuffer()) + faces->mapRightFromInterface(_law->getNbFields(), residuInterface,_residual->getGroupProxy(gR)); + } + } + fullMatrix<double> iMassEl, KEl,residuEl; + for(int iGroup=0;iGroup<vei.size();iGroup++){ + dgGroupOfElements *group=vei[iGroup]; + int nbNodes = group->getNbNodes(); + for(int iElem=0;iElem<group->getNbElements();iElem++){ + residuEl.setAsProxy(_residual->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + KEl.setAsProxy(_K[iK]->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + iMassEl.setAsProxy(group->getInverseMassMatrix(),iElem*nbNodes,nbNodes); + iMassEl.mult(residuEl,KEl); + } + } + for(int iGroup=0;iGroup<veo.size();iGroup++){ + dgGroupOfElements *group=veo[iGroup]; + int nbNodes = group->getNbNodes(); + for(int iElem=0;iElem<group->getNbElements();iElem++){ + residuEl.setAsProxy(_residual->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + KEl.setAsProxy(_K[iK]->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + iMassEl.setAsProxy(group->getInverseMassMatrix(),iElem*nbNodes,nbNodes); + iMassEl.mult(residuEl,KEl); + } } } else{ std::vector<dgGroupOfElements *> &ve=_bulkGroupsOfElements[exponent].first; - residual->scale(ve,0.0); + _residual->scale(ve,0.0); for(int i=0;i<ve.size();i++){ - _residualVolume->computeAndMap1Group(*ve[i], *solution, *residual); + _residualVolume->computeAndMap1Group(*ve[i], *_currentInput, *_residual); } std::vector<dgGroupOfFaces *> &vf=_bulkGroupsOfElements[exponent].second; for(int i=0;i<vf.size();i++){ dgGroupOfFaces *faces=vf[i]; - const dgGroupOfElements *gL=&faces->getGroupLeft(); - const dgGroupOfElements *gR=&faces->getGroupRight(); - fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); - fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); - faces->mapToInterface(_law->getNbFields(), solution->getGroupProxy(gL), solution->getGroupProxy(gR), solInterface); - _residualInterface->compute1Group(*faces,solInterface,solution->getGroupProxy(gL), solution->getGroupProxy(gR),residuInterface); - if(gL->getMultirateExponent()==exponent && !gL->getIsMultirateBuffer()) - faces->mapLeftFromInterface(_law->getNbFields(), residuInterface,residual->getGroupProxy(gL)); - if(gL->getMultirateExponent()==exponent && !gL->getIsMultirateBuffer()) - faces->mapRightFromInterface(_law->getNbFields(), residuInterface,residual->getGroupProxy(gR)); + if(faces->isBoundary()){ + _residualBoundary->computeAndMap1Group(*faces,*_currentInput,*_residual); + } + else{ + const dgGroupOfElements *gL=&faces->getGroupLeft(); + const dgGroupOfElements *gR=&faces->getGroupRight(); + fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); + fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields()); + faces->mapToInterface(_law->getNbFields(), _currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR), solInterface); + _residualInterface->compute1Group(*faces,solInterface,_currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR),residuInterface); + if(gL->getMultirateExponent()==exponent && !gL->getIsMultirateBuffer()){ + faces->mapLeftFromInterface(_law->getNbFields(), residuInterface,_residual->getGroupProxy(gL)); + } + if(gR->getMultirateExponent()==exponent && !gR->getIsMultirateBuffer()){ + faces->mapRightFromInterface(_law->getNbFields(), residuInterface,_residual->getGroupProxy(gR)); + } + } + } + fullMatrix<double> iMassEl, KEl,residuEl; + for(int iGroup=0;iGroup<ve.size();iGroup++){ + dgGroupOfElements *group=ve[iGroup]; + int nbNodes = group->getNbNodes(); + for(int iElem=0;iElem<group->getNbElements();iElem++){ + residuEl.setAsProxy(_residual->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + KEl.setAsProxy(_K[iK]->getGroupProxy(group),iElem*_law->getNbFields(),_law->getNbFields()); + iMassEl.setAsProxy(group->getInverseMassMatrix(),iElem*nbNodes,nbNodes); + iMassEl.mult(residuEl,KEl); + } } } } @@ -659,13 +577,10 @@ void dgRungeKuttaMultirate::computeResidual(int exponent,bool isBuffer,dgDofCont double dgRungeKuttaMultirate::iterate(double dt, dgDofContainer *solution){ _solution=solution; _dt=dt; - _currentInput->scale(0.0); - _currentInput->axpy(*solution,1.0); - computeK(0,0,false); - computeK(1,0,false); - computeK(2,0,false); - computeK(3,0,false); - updateSolution(0,false); + computeInputForK(0,0,false); + computeInputForK(1,0,false); + computeInputForK(2,0,false); + computeInputForK(3,0,false); return solution->norm(); } diff --git a/Solver/dgRungeKutta.h b/Solver/dgRungeKutta.h index fa17c931e4731353da8f829ebfc9a6ba54128ebb..fcf4b54c89efe3e3561578bffbe847a7f8dd648a 100644 --- a/Solver/dgRungeKutta.h +++ b/Solver/dgRungeKutta.h @@ -10,6 +10,7 @@ class dgGroupOfElements; class dgGroupOfFaces; class dgResidualVolume; class dgResidualInterface; +class dgResidualBoundary; class binding; #include "fullMatrix.h" class dgRungeKutta { @@ -25,7 +26,6 @@ class dgRungeKutta { double iterate44ThreeEight(const dgConservationLaw *claw, double dt, dgDofContainer *solution); double iterate43SchlegelJCAM2009(const dgConservationLaw *claw, double dt, dgDofContainer *solution); double iterateRKFehlberg45(const dgConservationLaw *claw, double dt, dgDofContainer *solution); - double iterate43Multirate(const dgConservationLaw *claw, double dt, dgDofContainer *solution); static void registerBindings (binding *b); dgRungeKutta(); }; @@ -39,11 +39,14 @@ class dgRungeKuttaMultirate: public dgRungeKutta{ dgDofContainer *_solution; dgDofContainer **_K; dgDofContainer *_currentInput; + dgDofContainer *_residual; dgResidualVolume *_residualVolume; dgResidualInterface *_residualInterface; + dgResidualBoundary *_residualBoundary; std::vector<std::pair<std::vector<dgGroupOfElements*>,std::vector<dgGroupOfFaces*> > >_bulkGroupsOfElements;// int is the multirateExponent std::vector<std::pair<std::vector<dgGroupOfElements*>,std::vector<dgGroupOfFaces*> > >_innerBufferGroupsOfElements;// int is the multirateExponent std::vector<std::pair<std::vector<dgGroupOfElements*>,std::vector<dgGroupOfFaces*> > >_outerBufferGroupsOfElements;// int is the multirateExponent + void computeInputForK(int iK,int exponent,bool isBuffer); void computeK(int iK,int exponent,bool isBuffer); void updateSolution(int exponent,bool isBuffer); void computeResidual(int exponent,bool isBuffer,dgDofContainer *solution, dgDofContainer *residual);