diff --git a/Solver/TESTCASES/MultirateAdvection.lua b/Solver/TESTCASES/MultirateAdvection.lua index 34dfde0c54fdda6796c9583fe67055ed5cf3028b..e876a9b2bf5b9f4740ed7afd855bbeb1e96d5a21 100644 --- a/Solver/TESTCASES/MultirateAdvection.lua +++ b/Solver/TESTCASES/MultirateAdvection.lua @@ -24,7 +24,7 @@ end Example of a lua program driving the DG code --]] -order = 1 +order = 2 print'*** Loading the mesh and the model ***' myModel = GModel () myModel:load ('rect.geo') @@ -53,7 +53,7 @@ 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) +dt=GC:splitGroupsForMultirate(1,law,solTmp) GC:buildGroupsOfInterfaces(myModel,2,order) solution=dgDofContainer(GC,1) solution:L2Projection(FS) @@ -87,7 +87,7 @@ time=0 -- multirateRK:setLimiter(limiter) --for i=1,1000 i=0 -while time<0.5 do +while time<0.1 do -- norm1 = RK:iterate43SchlegelJCAM2009(law,dt,solution) -- TEST with Explicit Euler multirate !!! norm2 = multirateRK:iterate(dt,solution2) @@ -95,10 +95,10 @@ while time<0.5 do 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 + -- 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 diff --git a/Solver/dgRungeKuttaMultirate.cpp b/Solver/dgRungeKuttaMultirate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5686bdecb34ad90310fc1c43843c986a171c357 --- /dev/null +++ b/Solver/dgRungeKuttaMultirate.cpp @@ -0,0 +1,380 @@ +#include "dgRungeKuttaMultirate.h" +#include "Bindings.h" +#include "dgResidual.h" +#include "dgConservationLaw.h" +#include "dgDofContainer.h" +#include "dgGroupOfElements.h" +#include <algorithm> + +dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservationLaw *law, int nStages){ + _law=law; + _residualVolume=new dgResidualVolume(*_law); + _residualInterface=new dgResidualInterface(*_law); + _residualBoundary=new dgResidualBoundary(*_law); + _K=new dgDofContainer*[nStages]; + for(int i=0;i<nStages;i++){ + _K[i]=new dgDofContainer(gc,_law->getNbFields()); + _K[i]->setAll(0.0); + } + _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++){ + dgGroupOfElements *ge=gc->getElementGroup(iGroup); + _minExponent=std::min(_minExponent,ge->getMultirateExponent()); + _maxExponent=std::max(_maxExponent,ge->getMultirateExponent()); + _innerBufferGroupsOfElements.resize(_maxExponent+1); + _outerBufferGroupsOfElements.resize(_maxExponent+1); + _bulkGroupsOfElements.resize(_maxExponent+1); + if(ge->getIsInnerMultirateBuffer()){ + _innerBufferGroupsOfElements[ge->getMultirateExponent()].first.push_back(ge); + } + else if(ge->getIsOuterMultirateBuffer()){ + _outerBufferGroupsOfElements[ge->getMultirateExponent()].first.push_back(ge); + } + else{ + _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(); + for(int i=0;i<2;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); + } + } + } + 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){ + //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); + for(int i=0;i<vei.size();i++){ + _residualVolume->computeAndMap1Group(*vei[i], *_currentInput, *_residual); + } + for(int i=0;i<veo.size();i++){ + _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; + 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); + for(int i=0;i<ve.size();i++){ + _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]; + 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); + } + } + } +} + +void dgRungeKuttaMultirate::registerBindings(binding *b) { +/* + classBinding *cb = b->addClass<dgRungeKuttaMultirate>("dgRungeKuttaMultirate"); + cb->setDescription("Multirate explicit Runge-Kutta"); + methodBinding *cm; + cm = cb->setConstructor<dgRungeKuttaMultirate,dgGroupCollection *,dgConservationLaw*>(); + cm->setArgNames("groupCollection","law",NULL); + cm->setDescription("A new multirate explicit runge kutta, pass parameters to the iterate function"); + cm = cb->addMethod("iterate",&dgRungeKuttaMultirate::iterate); + cm->setArgNames("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"); + cb->setParentClass<dgRungeKutta>(); + */ +} + +dgRungeKuttaMultirate43::dgRungeKuttaMultirate43(dgGroupCollection *gc,dgConservationLaw* law):dgRungeKuttaMultirate(gc,law,10){} + + +double dgRungeKuttaMultirate43::iterate(double dt, dgDofContainer *solution){ + _solution=solution; + _dt=dt; + computeInputForK(0,0,false); + computeInputForK(1,0,false); + computeInputForK(2,0,false); + computeInputForK(3,0,false); + + return solution->norm(); +} + +void dgRungeKuttaMultirate43::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}, + {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 _AInner[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} + }; + + // Big step RK43 + double _AOuter[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}, + }; +// Msg::Info("K%d, %d, %s",iK,exponent,isBuffer?"Buffer":"Bulk"); + // compute K[iK] for this exponent and buffer + if(isBuffer){ + std::vector<dgGroupOfElements *>&gVi=_innerBufferGroupsOfElements[exponent].first; + std::vector<dgGroupOfElements *>&gVo=_outerBufferGroupsOfElements[exponent].first; + _currentInput->scale(gVi,0.0); + _currentInput->scale(gVo,0.0); + _currentInput->axpy(gVi,*_solution,1.0); + _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*2); + if(_AOuter[iK][i]!=0.0) + _currentInput->axpy(gVo,*_K[i],_AOuter[iK][i]*localDt*2); + } + } + else{ + std::vector<dgGroupOfElements *> &gV=_bulkGroupsOfElements[exponent].first; + _currentInput->scale(gV,0.0); + _currentInput->axpy(gV,*_solution,1.0); + for(int i=0;i<iK;i++){ + if(_A[iK][i]!=0.0){ + _currentInput->axpy(gV,*_K[i],_A[iK][i]*localDt); + } + } + } + + if(!isBuffer){ + switch(iK){ + case 0: + computeInputForK(0,exponent+1,true); + break; + case 1: + computeInputForK(4,exponent+1,true); + break; + case 2: + computeInputForK(5,exponent+1,true); + break; + case 3: + computeInputForK(9,exponent+1,true); + break; + } + } + else{ + if( (iK%5)<4 ){ + 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 dgRungeKuttaMultirate43::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}; + double bInner[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 cInner[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 }; + double bOuter[10]={1.0/6.0, 0 , 0 , 0 , 1.0/3.0,1.0/3.0, 0 , 0 , 0 , 1.0/6.0}; + double cOuter[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 }; + if(isBuffer){ + std::vector<dgGroupOfElements *>&gVi=_innerBufferGroupsOfElements[exponent].first; + 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*2); + if(bOuter[i]!=0.0) + _solution->axpy(gVo,*_K[i],bOuter[i]*localDt*2); + } + } + else{ + std::vector<dgGroupOfElements *>&gV=_bulkGroupsOfElements[exponent].first; + for(int i=0;i<4;i++){ + if(b[i]!=0.0) + _solution->axpy(gV,*_K[i],b[i]*localDt); + } + } +} + + +void dgRungeKuttaMultirate43::registerBindings(binding *b) { + classBinding *cb = b->addClass<dgRungeKuttaMultirate43>("dgRungeKuttaMultirate43"); + cb->setDescription("Multirate explicit Runge-Kutta with SchlegelJCAM2009 4 stages 3rd order method"); + methodBinding *cm; + cm = cb->setConstructor<dgRungeKuttaMultirate43,dgGroupCollection *,dgConservationLaw*>(); + cm->setArgNames("groupCollection","law",NULL); + cm->setDescription("A new multirate explicit runge kutta, pass parameters to the iterate function"); + cm = cb->addMethod("iterate",&dgRungeKuttaMultirate43::iterate); + cm->setArgNames("dt","solution",NULL); + cm->setDescription("update the 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"); +} diff --git a/Solver/dgRungeKuttaMultirate.h b/Solver/dgRungeKuttaMultirate.h new file mode 100644 index 0000000000000000000000000000000000000000..c65f02690a25411eb5c02b7a5ec9f9639e0a8a7d --- /dev/null +++ b/Solver/dgRungeKuttaMultirate.h @@ -0,0 +1,39 @@ +#include "dgRungeKutta.h" + +class dgRungeKuttaMultirate: public dgRungeKutta{ + protected: + int _maxExponent; + int _minExponent; + double _dt; + dgConservationLaw *_law; + 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 + virtual void computeInputForK(int iK,int exponent,bool isBuffer)=0; + void computeK(int iK,int exponent,bool isBuffer); + virtual void updateSolution(int exponent,bool isBuffer)=0; + void computeResidual(int exponent,bool isBuffer,dgDofContainer *solution, dgDofContainer *residual); + public: + dgRungeKuttaMultirate(dgGroupCollection *gc,dgConservationLaw* law, int nStages); + virtual ~dgRungeKuttaMultirate(); + + + virtual double iterate(double dt, dgDofContainer *solution)=0; + static void registerBindings(binding *b); +}; + +class dgRungeKuttaMultirate43: public dgRungeKuttaMultirate{ + void computeInputForK(int iK,int exponent,bool isBuffer); + void updateSolution(int exponent,bool isBuffer); + public: + double iterate(double dt, dgDofContainer *solution); + dgRungeKuttaMultirate43(dgGroupCollection *gc,dgConservationLaw *law); + static void registerBindings(binding *b); +};