diff --git a/Common/LuaBindings.cpp b/Common/LuaBindings.cpp index 0011274ee36142c3784c687412ef70059be0c106..347a7b6784f0206275c623357fe5003b3ba7e532 100644 --- a/Common/LuaBindings.cpp +++ b/Common/LuaBindings.cpp @@ -343,6 +343,7 @@ binding::binding(){ dgPerfectGasLaw2dRegisterBindings(this); dgResidual::registerBindings(this); dgRungeKutta::registerBindings(this); + dgRungeKuttaMultirate::registerBindings(this); dgSlopeLimiterRegisterBindings(this); dgSystemOfEquations::registerBindings(this); fullMatrix<double>::registerBindings(this); diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp index 73f512ba6d916413f231c0dda2a529a8890926d9..61a846627520c9d6c6fd3cba1a8d3e1983169a55 100644 --- a/Mesh/HighOrder.cpp +++ b/Mesh/HighOrder.cpp @@ -996,7 +996,7 @@ static void checkHighOrderTetrahedron(const char* cc, GModel *m, minGGlob, avg / (count ? count : 1)); } -extern double mesh_functional_distorsion(MTriangle *t, double u, double v); +extern double mesh_functional_distorsion(MElement *t, double u, double v); static void printJacobians(GModel *m, const char *nm) { diff --git a/Solver/TESTCASES/rect.geo b/Solver/TESTCASES/rect.geo index 9ab82d5364eb20af385cf148029a3365bec7b0da..6f581ea1d64723210792af9058832d22aad94c69 100644 --- a/Solver/TESTCASES/rect.geo +++ b/Solver/TESTCASES/rect.geo @@ -18,8 +18,8 @@ Plane Surface(11) = {10}; Physical Surface("sprut") = {11, 9}; Physical Line("Walls") = {5, 7, 3, 4, 1}; Physical Line("Top") = {6}; -Transfinite Line {5, 7, 1, 3} = 50 Using Progression 1; -Transfinite Line {6, 4, 2} = 25 Using Progression 1; -Transfinite Surface {9} Alternated; -Transfinite Surface {11} Alternated; -Recombine Surface {9, 11}; +//Recombine Surface {9, 11}; + +Field[1] = MathEval; +Field[1].F = "0.01*1+0.01*1.7*y"; +Background Field = 1; diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp index 4246e56c1ca33ed786a51a7cf05d205795b088e0..0366c576e59555cacb87affd418b3590f4f9f180 100644 --- a/Solver/dgAlgorithm.cpp +++ b/Solver/dgAlgorithm.cpp @@ -19,6 +19,64 @@ // works for any number of groups +/* +void dgAlgorithm::residualForSomeGroups( const dgConservationLaw &claw, + std::vector<dgGroupOfElements *>groups, + dgGroupCollection &groupCollection, + dgDofContainer &solution, + dgDofContainer &residu) +{ + solution.scatter(); + int nbFields=claw.getNbFields(); + //volume term + std::set<dgGroupOfFaces *>groupOfInternalFacesToUpdate; + std::vector<dgGroupOfFaces *>groupOfBoundaryFacesToUpdate; + for(size_t i=0;i<groups.size() ; i++) { + int groupId=groups[i]->getId(); + residu.getGroupProxy(groupId).scale(0); + residualVolume(claw,*groups[i],solution.getGroupProxy(groupId),residu.getGroupProxy(groupId)); + groupOfInternalFacesToUpdate.insert(groups[i]->getGroupsOfNeighboringFaces()->begin(),groups[i]->getGroupsOfNeighboringFaces()->end()); + groupOfBoundaryFacesToUpdate.insert(groupOfBoundaryFacesToUpdate.end(),groups[i]->getGroupsOfBoundaryFaces()->begin(),groups[i]->getGroupsOfBoundaryFaces()->end()); + groupOfInternalFacesToUpdate.insert(groups[i]->getGroupOfInsideFaces()); + } + for(std::set<dgGroupOfFaces *>::iterator it=groupOfInternalFacesToUpdate.begin();it!=groupOfInternalFacesToUpdate.end();it++) { + dgGroupOfFaces *faces = *it; + int iGroupLeft = -1, iGroupRight = -1; + for(size_t j=0;j<groupCollection.getNbElementGroups(); j++) { + dgGroupOfElements *groupj = groupCollection.getElementGroup(j); + if (groupj == &faces->getGroupLeft()) iGroupLeft = j; + if (groupj == &faces->getGroupRight()) iGroupRight= j; + } + for(size_t j=0;j<groupCollection.getNbGhostGroups(); j++) { + dgGroupOfElements *groupj = groupCollection.getGhostGroup(j); + if (groupj == &faces->getGroupLeft()) iGroupLeft = j; + if (groupj == &faces->getGroupLeft())iGroupLeft = j + groupCollection.getNbElementGroups(); + if (groupj == &faces->getGroupRight())iGroupRight= j + groupCollection.getNbElementGroups(); + } + fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*nbFields); + fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*nbFields); + faces->mapToInterface(nbFields, solution.getGroupProxy(iGroupLeft), solution.getGroupProxy(iGroupRight), solInterface); + residualInterface(claw,*faces,solInterface,solution.getGroupProxy(iGroupLeft), solution.getGroupProxy(iGroupRight),residuInterface); + faces->mapFromInterface(nbFields, residuInterface,residu.getGroupProxy(iGroupLeft), residu.getGroupProxy(iGroupRight)); + } + //boundaries + for(size_t i=0;i<groupOfBoundaryFacesToUpdate.size() ; i++) { + dgGroupOfFaces *faces = groupOfBoundaryFacesToUpdate[i]; + int iGroupLeft = -1, iGroupRight = -1; + for(size_t j=0;j<groupCollection.getNbElementGroups(); j++) { + dgGroupOfElements *groupj = groupCollection.getElementGroup(j); + if (groupj == &faces->getGroupLeft())iGroupLeft = j; + if (groupj == &faces->getGroupRight())iGroupRight= j; + } + fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*nbFields); + fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*nbFields); + faces->mapToInterface(nbFields, solution.getGroupProxy(iGroupLeft), solution.getGroupProxy(iGroupRight), solInterface); + residualBoundary(claw,*faces,solInterface,solution.getGroupProxy(iGroupLeft),residuInterface); + faces->mapFromInterface(nbFields, residuInterface, residu.getGroupProxy(iGroupLeft), residu.getGroupProxy(iGroupRight)); + } +} +*/ + void dgAlgorithm::computeElementaryTimeSteps ( //dofManager &dof, // the DOF manager (maybe useless here) const dgConservationLaw &claw, // the conservation law const dgGroupOfElements & group, diff --git a/Solver/dgDofContainer.cpp b/Solver/dgDofContainer.cpp index 7a2b0d0cf6a1da41a2ca8908a1e77b1e1838a917..2f63ec8fd30a3828ea68b9ba1dfd6bb40ff42a65 100644 --- a/Solver/dgDofContainer.cpp +++ b/Solver/dgDofContainer.cpp @@ -166,6 +166,14 @@ void dgDofContainer::axpy(dgDofContainer &x, double a) _data->axpy(*x._data,a); _ghostData->axpy(*x._ghostData,a); } +void dgDofContainer::axpy(std::vector<dgGroupOfElements*>groupsVector,dgDofContainer &x, double a){ + for(int i=0;i<groupsVector.size();i++){ + dgGroupOfElements *g=groupsVector[i]; + fullMatrix<double> &proxy=getGroupProxy(g); + fullMatrix<double> &xProxy=x.getGroupProxy(g); + proxy.add(xProxy,a); + } +} double dgDofContainer::norm() { double localNorm = _data->norm(); @@ -213,6 +221,70 @@ void dgDofContainer::L2Projection(std::string functionName){ } } +void dgDofContainer::exportGroupIdMsh(){ + // the elementnodedata::export does not work !! + + std::ostringstream name_oss; + name_oss<<"groups.msh"; + if(Msg::GetCommSize()>1) + name_oss<<"_"<<Msg::GetCommRank(); + FILE *f = fopen (name_oss.str().c_str(),"w"); + int COUNT = 0; + for (int i=0;i < _groups.getNbElementGroups() ;i++){ + COUNT += _groups.getElementGroup(i)->getNbElements(); + } + fprintf(f,"$MeshFormat\n2.1 0 8\n$EndMeshFormat\n"); + fprintf(f,"$ElementNodeData\n"); + fprintf(f,"1\n"); + fprintf(f,"\"%s\"\n","GroupsIds"); + fprintf(f,"1\n"); + fprintf(f,"0.0\n"); + fprintf(f,"%d\n", Msg::GetCommSize() > 1 ? 4 : 3); + fprintf(f,"0\n 1\n %d\n",COUNT); + if(Msg::GetCommSize() > 1) fprintf(f,"%d\n", Msg::GetCommRank()); + for (int i=0;i < _groups.getNbElementGroups() ;i++){ + dgGroupOfElements *group = _groups.getElementGroup(i); + for (int iElement=0 ; iElement< group->getNbElements() ;++iElement) { + MElement *e = group->getElement(iElement); + int num = e->getNum(); + fullMatrix<double> sol(getGroupProxy(i), iElement*_nbFields,_nbFields); + fprintf(f,"%d %d",num,sol.size1()); + for (int k=0;k<sol.size1();++k) { + fprintf(f," %.16E ",i*1.0); + } + fprintf(f,"\n"); + } + } + fprintf(f,"$EndElementNodeData\n"); + fclose(f); + return; + // we should discuss that : we do a copy of the solution, this should + // be avoided ! + + /*std::map<int, std::vector<double> > data; + + for (int i=0;i < _groups.getNbElementGroups() ;i++){ + dgGroupOfElements *group = _groups.getElementGroup(i); + for (int iElement=0 ; iElement< group->getNbElements() ;++iElement) { + MElement *e = group->getElement(iElement); + int num = e->getNum(); + fullMatrix<double> sol(getGroupProxy(i), iElement*_nbFields,_nbFields); + std::vector<double> val; + // val.resize(sol.size2()*sol.size1()); + val.resize(sol.size1()); + int counter = 0; + // for (int iC=0;iC<sol.size2();iC++) + printf("%g %g %g\n",sol(0,0),sol(1,0),sol(2,0)); + for (int iR=0;iR<sol.size1();iR++)val[counter++] = sol(iR,0); + data[num] = val; + } + } + + PView *pv = new PView (name, "ElementNodeData", _gm, data, 0.0, 1); + pv->getData()->writeMSH(name+".msh", false); + delete pv; + */ +} void dgDofContainer::exportMsh(const std::string name) { @@ -236,7 +308,7 @@ void dgDofContainer::exportMsh(const std::string name) fprintf(f,"1\n"); fprintf(f,"%d\n", _mshStep); // should print actual time here fprintf(f,"%d\n", Msg::GetCommSize() > 1 ? 4 : 3); - fprintf(f,"%d\n 1\n %d\n", _mshStep, COUNT); + fprintf(f,"%d\n 1\n %d\n", 0/*_mshStep*/, COUNT); if(Msg::GetCommSize() > 1) fprintf(f,"%d\n", Msg::GetCommRank()); for (int i=0;i < _groups.getNbElementGroups() ;i++){ dgGroupOfElements *group = _groups.getElementGroup(i); @@ -300,4 +372,6 @@ void dgDofContainer::registerBindings(binding *b){ cm = cb->addMethod("exportMsh",&dgDofContainer::exportMsh); cm->setDescription("Export the dof for gmsh visualization"); cm->setArgNames("filename", NULL); + cm = cb->addMethod("exportGroupIdMsh",&dgDofContainer::exportGroupIdMsh); + cm->setDescription("Export the group ids for gmsh visualization"); } diff --git a/Solver/dgDofContainer.h b/Solver/dgDofContainer.h index 12094bf1ad11d47429c7f8686bcd1b818a7d6c50..6c3f15ac14f305b70a4ff8b3e8973921ce461a09 100644 --- a/Solver/dgDofContainer.h +++ b/Solver/dgDofContainer.h @@ -28,6 +28,7 @@ public: void scale(double f); double norm(); void axpy(dgDofContainer &x, double a=1.); + void axpy(std::vector<dgGroupOfElements*>groups,dgDofContainer &x, double a=1.); inline fullMatrix<double> &getGroupProxy(int gId){ return *(_dataProxys[gId]); } inline fullMatrix<double> &getGroupProxy(const dgGroupOfElements* g){ return *(_dataProxys[_groupId[g]]); } dgDofContainer (dgGroupCollection *groups, int nbFields); @@ -41,6 +42,7 @@ public: void L2Projection(std::string functionName); void Mesh2Mesh_L2Projection(dgDofContainer &other); void exportMsh(const std::string name); + void exportGroupIdMsh(); static void registerBindings(binding *b); inline dgGroupCollection *getGroups() { return &_groups; } diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp index c21ccaf325f7af74111c244e99859be4fb4a60ad..48b36559f1970c48d63340d4ebcbbb90fa32718d 100644 --- a/Solver/dgGroupOfElements.cpp +++ b/Solver/dgGroupOfElements.cpp @@ -1,5 +1,5 @@ -#include <iostream> #include "GmshConfig.h" +#include "GmshMessage.h" #include "dgGroupOfElements.h" #include "dgConservationLaw.h" #include "dgDofContainer.h" @@ -131,6 +131,10 @@ dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, } } +void dgGroupOfElements::copyPrivateDataFrom(const dgGroupOfElements *from){ +// Msg::Error("dgGroupOfElements::copyPrivateDataFrom not yet implemented, ask Richard"); +} + dgGroupOfElements::~dgGroupOfElements(){ delete _integration; delete _redistributionFluxes[0]; @@ -622,6 +626,36 @@ void dgGroupOfFaces::mapFromInterface ( int nFields, } } } +void dgGroupOfFaces::mapLeftFromInterface ( int nFields, + const fullMatrix<double> &v, + fullMatrix<double> &vLeft + ) +{ + for(int i=0; i<getNbElements(); i++) { + const std::vector<int> &closureRight = getClosureRight(i); + const std::vector<int> &closureLeft = getClosureLeft(i); + for (int iField=0; iField<nFields; iField++){ + for(size_t j =0; j < closureLeft.size(); j++) + vLeft(closureLeft[j], _left[i]*nFields + iField) += v(j, i*2*nFields + iField); + } + } +} +void dgGroupOfFaces::mapRightFromInterface ( int nFields, + const fullMatrix<double> &v, + fullMatrix<double> &vRight + ) +{ + for(int i=0; i<getNbElements(); i++) { + const std::vector<int> &closureRight = getClosureRight(i); + const std::vector<int> &closureLeft = getClosureLeft(i); + for (int iField=0; iField<nFields; iField++){ + for(size_t j =0; j < closureRight.size(); j++) + vRight(closureRight[j], _right[i]*nFields + iField) += v(j, (i*2+1)*nFields + iField); + } + } +} + + /* void dgAlgorithm::buildGroupsOfFaces(GModel *model, int dim, int order, @@ -675,8 +709,11 @@ void dgGroupCollection::buildGroupsOfElements(GModel *model, int dim, int order) } // do a group of elements for every element type in the mesh + int id=_elementGroups.size(); for (std::map<int, std::vector<MElement *> >::iterator it = localElements.begin(); it !=localElements.end() ; ++it){ - _elementGroups.push_back(new dgGroupOfElements(it->second,order)); + dgGroupOfElements *newGroup=new dgGroupOfElements(it->second,order); + _elementGroups.push_back(newGroup); + id++; } } @@ -745,7 +782,7 @@ void dgGroupCollection::buildGroupsOfInterfaces() { for (int i=0;i<_elementGroups.size();i++){ - // create a group of faces on the boundary for every group ef elements + // create a group of faces on the boundary for every group of elements switch(dim) { case 1 : { std::map<const std::string, std::set<MVertex*> >::iterator mapIt; @@ -782,7 +819,11 @@ void dgGroupCollection::buildGroupsOfInterfaces() { } } // create a group of faces for every face that is common to elements of the same group - _faceGroups.push_back(new dgGroupOfFaces(*_elementGroups[i],order)); + dgGroupOfFaces *gof=new dgGroupOfFaces(*_elementGroups[i],order); + if(gof->getNbElements()) + _faceGroups.push_back(gof); + else + delete gof; // create a groupe of d for (int j=i+1;j<_elementGroups.size();j++){ dgGroupOfFaces *gof = new dgGroupOfFaces(*_elementGroups[i],*_elementGroups[j],order); @@ -795,7 +836,11 @@ void dgGroupCollection::buildGroupsOfInterfaces() { //create ghost groups for(int i=0;i<Msg::GetCommSize();i++){ for (std::map<int, std::vector<MElement *> >::iterator it = ghostElements[i].begin(); it !=ghostElements[i].end() ; ++it){ - _ghostGroups.push_back(new dgGroupOfElements(it->second,order,i)); + dgGroupOfElements *gof=new dgGroupOfElements(it->second,order,i); + if (gof->getNbElements()) + _ghostGroups.push_back(gof); + else + delete gof; } } //create face group for ghostGroups @@ -875,30 +920,283 @@ void dgGroupCollection::buildGroupsOfInterfaces() { // Split the groups of elements depending on their local time step -void dgGroupCollection::splitGroupsForMultirate(double refDt,dgConservationLaw *claw){ - // 1) find the element with the smallest stable time step - double sr = DBL_MAX; - dgDofContainer *solution = new dgDofContainer((this),claw->getNbFields()); - solution->scale(0.); +void dgGroupCollection::splitGroupsForMultirate(double dtRef,dgConservationLaw *claw, dgDofContainer *solution){ + Msg::Info("Splitting Groups for multirate time stepping"); + int maxNumElems=getElementGroup(0)->getElement(0)->getGlobalNumber()+1; + std::vector<int>oldGroupIds; + oldGroupIds.resize(maxNumElems); + std::vector<MElement*>allElements; + allElements.resize(maxNumElems); + for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){ + dgGroupOfElements *elGroup=getElementGroup(iGroup); + for(int iElement=0;iElement<elGroup->getNbElements();iElement++){ + MElement *el=elGroup->getElement(iElement); + oldGroupIds[el->getNum()]=iGroup; + allElements[el->getNum()]=el; + } + } + + std::vector<int>newGroupIds; + newGroupIds.assign(maxNumElems,-1); + + std::vector<std::vector<int> >elementToNeighbors; + elementToNeighbors.resize(maxNumElems); + + switch(getElementGroup(0)->getElement(0)->getDim()){ + case 1: + { + std::map<MVertex*,int> vertexMap; + for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){ + dgGroupOfElements *elGroup=getElementGroup(iGroup); + for(int iElement=0; iElement<elGroup->getNbElements(); iElement++){ + MElement *el = elGroup->getElement(iElement); + for (int iVertex=0; iVertex<el->getNumVertices(); iVertex++){ + MVertex* vertex = el->getVertex(iVertex); + if(vertexMap.find(vertex) == vertexMap.end()){ + vertexMap[vertex] = el->getNum(); + }else{ + elementToNeighbors[vertexMap[vertex]].push_back(el->getNum()); + elementToNeighbors[el->getNum()].push_back(vertexMap[vertex]); + } + } + } + } + vertexMap.clear(); + } + break; + case 2: + { + std::map<MEdge,int,Less_Edge> edgeMap; + for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){ + dgGroupOfElements *elGroup=getElementGroup(iGroup); + for(int iElement=0; iElement<elGroup->getNbElements(); iElement++){ + MElement *el = elGroup->getElement(iElement); + for (int iEdge=0; iEdge<el->getNumEdges(); iEdge++){ + MEdge edge = el->getEdge(iEdge); + if(edgeMap.find(edge) == edgeMap.end()){ + edgeMap[edge] = el->getNum(); + }else{ + elementToNeighbors[edgeMap[edge]].push_back(el->getNum()); + elementToNeighbors[el->getNum()].push_back(edgeMap[edge]); + } + } + } + } + edgeMap.clear(); + } + break; + case 3: + { + std::map<MFace,int,Less_Face> faceMap; + for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){ + dgGroupOfElements *elGroup=getElementGroup(iGroup); + for(int iElement=0; iElement<elGroup->getNbElements(); iElement++){ + MElement *el = elGroup->getElement(iElement); + for (int iFace=0; iFace<el->getNumFaces(); iFace++){ + MFace face = el->getFace(iFace); + if(faceMap.find(face) == faceMap.end()){ + faceMap[face] = el->getNum(); + }else{ + elementToNeighbors[faceMap[face]].push_back(el->getNum()); + elementToNeighbors[el->getNum()].push_back(faceMap[face]); + } + } + } + } + faceMap.clear(); + } + break; + default: + break; + } + + // find the range of time steps + double dtMin = DBL_MAX; + double dtMax = 0; + std::vector<double> *DTS=new std::vector<double>[getNbElementGroups()]; for (int i=0;i<getNbElementGroups();i++){ - std::vector<double> DTS; - dgAlgorithm::computeElementaryTimeSteps(*claw, *getElementGroup(i), solution->getGroupProxy(i), DTS); - for (int k=0;k<DTS.size();k++){ - std::cout << "SR: " << DTS[k] << std::endl; - sr = std::min(sr,DTS[k]); + dgAlgorithm::computeElementaryTimeSteps(*claw, *getElementGroup(i), solution->getGroupProxy(i), DTS[i]); + for (int k=0;k<DTS[i].size();k++){ + dtMin = std::min(dtMin,DTS[i][k]); + dtMax = std::max(dtMax,DTS[i][k]); } } - delete solution; - #ifdef HAVE_MPI - double sr_min; - MPI_Allreduce((void *)&sr, &sr_min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); - sr=sr_min; - #endif - // sr is the time step for the most constrained element. - std::cout << "SR: " << sr << std::endl; + std::vector<double>localDt; + localDt.resize(maxNumElems); + for (int i=0;i<getNbElementGroups();i++){ + dgGroupOfElements *elGroup=getElementGroup(i); + for(int j=0;j<DTS[i].size();j++){ + MElement *el=elGroup->getElement(j); + localDt[el->getNum()]=DTS[i][j]; + } + } + delete []DTS; +#ifdef HAVE_MPI + double dtMin_min; + MPI_Allreduce((void *)&dtMin, &dtMin_min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + dtMin=dtMin_min; + double dtMax_max; + MPI_Allreduce((void *)&dtMax, &dtMax_max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + dtMax=dtMax_max; +#endif + // dtMin is the time step for the most constrained element. + if(dtRef<=dtMin){ + Msg::Info("No multirate, the reference time step is stable for all elements."); + return; + } + + Msg::Info("Time step for standard RK should be %e",dtMin); + Msg::Info("Multirate base time step should be %e",dtMax); + + dtRef=dtMax*0.8; + // time steps are dtRef*2^(-dtExponent), with dtExponent ranging in [0:dtMaxExponent] + int dtMaxExponent=0; + while(dtRef/pow(2.0,(double)dtMaxExponent)>dtMin) + dtMaxExponent++; + _dtMaxExponent=dtMaxExponent; + std::vector<MElement *>currentNewGroup; + std::vector< dgGroupOfElements* >newGroups;// indexed by newGroupId + std::map<int,int>oldToNewGroupsMap;// oldGroupId to newGroupId + + int lowerLevelGroupIdStart=-1; + int lowerLevelGroupIdEnd=-1; + + bool isOuterBufferLayer=false; + int currentNewGroupId=0; + int loopId=0; + for(int currentExponent=dtMaxExponent;currentExponent>=0;(!isOuterBufferLayer)?currentExponent--:currentExponent=currentExponent){ + double currentDt=dtRef/pow(2.0,(double)currentExponent); + std::map<int,std::vector<MElement*> >mapNewGroups; + if(lowerLevelGroupIdStart==-1){ + lowerLevelGroupIdStart=0; + } + else{ + // Add the neighbors elements to the new groups + int _lowerLevelGroupIdStart=lowerLevelGroupIdStart; + int _lowerLevelGroupIdEnd=lowerLevelGroupIdEnd; + lowerLevelGroupIdStart=lowerLevelGroupIdEnd; + for(int iNewGroup=_lowerLevelGroupIdStart;iNewGroup<_lowerLevelGroupIdEnd;iNewGroup++){ + for(int iElement=0; iElement<newGroups[iNewGroup]->getNbElements(); iElement++){ + MElement *el = newGroups[iNewGroup]->getElement(iElement); + for(int iNeighbor=0;iNeighbor<elementToNeighbors[el->getNum()].size();iNeighbor++){ + int neighId=elementToNeighbors[el->getNum()][iNeighbor]; + if(newGroupIds[neighId]==-1){ + mapNewGroups[oldGroupIds[neighId]].push_back(allElements[neighId]); + newGroupIds[neighId]=-2; + } + } + } + } + } + if(!isOuterBufferLayer){ + for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){ + dgGroupOfElements *elGroup=getElementGroup(iGroup); + for(int iElement=0;iElement<elGroup->getNbElements();iElement++){ + MElement *el=elGroup->getElement(iElement); + if(localDt[el->getNum()]>=currentDt && localDt[el->getNum()]<currentDt*2){ + if(newGroupIds[el->getNum()]==-1){ + mapNewGroups[iGroup].push_back(el); + newGroupIds[el->getNum()]=-2; + } + } + } + } + lowerLevelGroupIdStart=currentNewGroupId; + for (std::map<int, std::vector<MElement *> >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){ + if(!it->second.empty()){ + std::vector<MElement *>forBulk; + std::vector<MElement *>forInnerBuffer; + for(int i=0;i<it->second.size();i++){ + MElement* el=it->second[i]; + bool inInnerBuffer=false; + for(int iNeighbor=0;iNeighbor<elementToNeighbors[el->getNum()].size();iNeighbor++){ + int neighId=elementToNeighbors[el->getNum()][iNeighbor]; + if(newGroupIds[neighId]==-1){ + inInnerBuffer=true; + continue; + } + } + if(inInnerBuffer){ + forInnerBuffer.push_back(el); + } + else{ + forBulk.push_back(el); + } + } + for(int i=0;i<forBulk.size();i++){ + newGroupIds[it->second[i]->getNum()]=currentNewGroupId; + } + dgGroupOfElements *oldGroup=getElementGroup(it->first); + dgGroupOfElements *newGroup; + if(!forBulk.empty()){ + newGroup=new dgGroupOfElements(forBulk,oldGroup->getOrder(),oldGroup->getGhostPartition()); + newGroup->copyPrivateDataFrom(oldGroup); + newGroup->_multirateExponent=currentExponent; + newGroup->_multirateOuterBuffer=false; + newGroup->_multirateInnerBuffer=false; + newGroups.resize(currentNewGroupId+1); + newGroups[currentNewGroupId]=newGroup; + oldToNewGroupsMap[it->first]=currentNewGroupId; + currentNewGroupId++; + } + if(!forInnerBuffer.empty()){ + newGroup=new dgGroupOfElements(forInnerBuffer,oldGroup->getOrder(),oldGroup->getGhostPartition()); + newGroup->copyPrivateDataFrom(oldGroup); + newGroup->_multirateExponent=currentExponent; + newGroup->_multirateOuterBuffer=false; + newGroup->_multirateInnerBuffer=true; + newGroups.resize(currentNewGroupId+1); + newGroups[currentNewGroupId]=newGroup; + oldToNewGroupsMap[it->first]=currentNewGroupId; + currentNewGroupId++; + } + } + else + Msg::Info("Empty Group !!!!!!!!!!!!!!!!!!"); + } + } + else{ + for (std::map<int, std::vector<MElement *> >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){ + if(!it->second.empty()){ + for(int i=0;i<it->second.size();i++){ + newGroupIds[it->second[i]->getNum()]=currentNewGroupId; + } + dgGroupOfElements *oldGroup=getElementGroup(it->first); + dgGroupOfElements *newGroup=new dgGroupOfElements(it->second,oldGroup->getOrder(),oldGroup->getGhostPartition()); + newGroup->copyPrivateDataFrom(oldGroup); + newGroup->_multirateExponent=currentExponent; + newGroup->_multirateOuterBuffer=true; + newGroup->_multirateInnerBuffer=false; + newGroups.resize(currentNewGroupId+1); + newGroups[currentNewGroupId]=newGroup; + oldToNewGroupsMap[it->first]=currentNewGroupId; + currentNewGroupId++; + } + else + Msg::Info("Empty Group !!!!!!!!!!!!!!!!!!"); + } + } + lowerLevelGroupIdEnd=currentNewGroupId; + isOuterBufferLayer=!isOuterBufferLayer; + } + int count=0; + for(int i=0;i<newGroups.size();i++){ + Msg::Info("%d New group # %d has %d elements",newGroups[i]->getMultirateExponent(),i,newGroups[i]->getNbElements()); + if(newGroups[i]->getIsInnerMultirateBuffer()) + Msg::Info("InnerBuffer"); + else if(newGroups[i]->getIsOuterMultirateBuffer()) + Msg::Info("OuterBuffer"); + else + Msg::Info("Not Buffer"); + count+=newGroups[i]->getNbElements(); + } + Msg::Info("That makes a total of %d elements",count); + _elementGroups.clear(); + _elementGroups=newGroups; } + dgGroupCollection::dgGroupCollection() { _groupsOfElementsBuilt=false;_groupsOfInterfacesBuilt=false; @@ -945,7 +1243,7 @@ void dgGroupCollection::registerBindings(binding *b){ cm->setDescription("Build the group of interfaces, i.e. boundary interfaces and inter-element interfaces"); cm = cb->addMethod("splitGroupsForMultirate",&dgGroupCollection::splitGroupsForMultirate); cm->setDescription("Split the groups according to their own stable time step"); - cm->setArgNames("refDt","claw",NULL); + cm->setArgNames("refDt","claw","solution",NULL); cm = cb->addMethod("getNbElementGroups", &dgGroupCollection::getNbElementGroups); cm->setDescription("return the number of dgGroupOfElements"); cm = cb->addMethod("getNbFaceGroups", &dgGroupCollection::getNbFaceGroups); diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h index 41c6f46450d61d9d12ed016a5ae609f363453bf8..f108b15c06dbf89e40f098d002084e4ecff9844b 100644 --- a/Solver/dgGroupOfElements.h +++ b/Solver/dgGroupOfElements.h @@ -22,6 +22,7 @@ class GModel; class binding; class dgConservationLaw; +class dgDofContainer; class dgElement { @@ -40,10 +41,13 @@ public: MElement *element() const { return _element;} }; +class dgGroupOfFaces; + // store topological and geometrical data for 1 group for 1 discretisation class dgGroupOfElements { int _ghostPartition; // -1 : this is not a ghosted group, otherwise the id of the parent partition + // N elements in the group std::vector<MElement*> _elements; // inverse map that gives the index of an element in the group @@ -79,7 +83,16 @@ class dgGroupOfElements { // forbid the copy // dgGroupOfElements (const dgGroupOfElements &e, int order) {} // dgGroupOfElements & operator = (const dgGroupOfElements &e) {} +protected: + int _multirateExponent; + bool _multirateInnerBuffer; + bool _multirateOuterBuffer; public: + + inline int getMultirateExponent() const {return _multirateExponent;} + inline int getIsInnerMultirateBuffer() const {return _multirateInnerBuffer;} + inline int getIsOuterMultirateBuffer() const {return _multirateOuterBuffer;} + inline int getIsMultirateBuffer()const {return _multirateInnerBuffer || _multirateOuterBuffer;} dgGroupOfElements (const std::vector<MElement*> &e, int pOrder,int ghostPartition=-1); virtual ~dgGroupOfElements (); inline int getNbElements() const {return _elements.size();} @@ -101,11 +114,13 @@ public: inline const fullMatrix<double> getMapping (int iElement) const {return fullMatrix<double>(*_mapping, iElement, 1);} inline int getOrder() const {return _order;} inline int getGhostPartition() const {return _ghostPartition;} + void copyPrivateDataFrom(const dgGroupOfElements *from); inline int getIndexOfElement (MElement *e) const { std::map<MElement*,int>::const_iterator it = element_to_index.find(e); if (it == element_to_index.end())return -1; return it->second; } + friend class dgGroupCollection; }; class dgGroupOfFaces { @@ -191,6 +206,8 @@ public: //keep this outside the Algorithm because this is the only place where data overlap void mapToInterface(int nFields, const fullMatrix<double> &vLeft, const fullMatrix<double> &vRight, fullMatrix<double> &v); void mapFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vLeft, fullMatrix<double> &vRight); + void mapLeftFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vLeft); + void mapRightFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vRight); const polynomialBasis * getPolynomialBasis() const {return _fsFace;} }; @@ -205,7 +222,12 @@ class dgGroupCollection { std::vector< std::vector<std::pair<int,int> > >_elementsToSend; bool _groupsOfElementsBuilt; bool _groupsOfInterfacesBuilt; + + // Multirate stuff + int _dtMaxExponent; + public: + inline int getDtMaxExponent() const {return _dtMaxExponent;} inline GModel* getModel() {return _model;} inline int getNbElementGroups() const {return _elementGroups.size();} inline int getNbFaceGroups() const {return _faceGroups.size();} @@ -223,7 +245,7 @@ class dgGroupCollection { void buildGroupsOfElements (GModel *model,int dimension, int order); void buildGroupsOfInterfaces (); - void splitGroupsForMultirate(double refDt,dgConservationLaw *claw); + void splitGroupsForMultirate(double refDt,dgConservationLaw *claw, dgDofContainer *solution); void find (MElement *elementToFind, int &iGroup, int &ithElementOfGroup); diff --git a/Solver/dgRungeKutta.cpp b/Solver/dgRungeKutta.cpp index 2e6898738a1b3b466359ad04369c93af5b45a56d..a1b03cbdc3714b53888bd6adff1fcf517c0bfaea 100644 --- a/Solver/dgRungeKutta.cpp +++ b/Solver/dgRungeKutta.cpp @@ -203,6 +203,181 @@ double dgRungeKutta::nonDiagonalRK(const dgConservationLaw *claw, return solution->norm(); } + +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(); +*/ +} + + dgRungeKutta::dgRungeKutta():_limiter(NULL) {} @@ -235,7 +410,229 @@ 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"); } + +dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservationLaw *law){ + _law=law; + _residualVolume=new dgResidualVolume(*_law); + _residualInterface=new dgResidualInterface(*_law); + _K=new dgDofContainer*[10]; + for(int i=0;i>10;i++){ + _K[i]=new dgDofContainer(gc,_law->getNbFields()); + _K[i]->setAll(0.0); + } + _currentInput=new dgDofContainer(gc,_law->getNbFields()); + _currentInput->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); + } + } + 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); + } + else if(ge[i]->getIsOuterMultirateBuffer()){ + _outerBufferGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); + }else{ + _bulkGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf); + } + } + } +} +dgRungeKuttaMultirate::~dgRungeKuttaMultirate(){ + for(int i=0;i>10;i++){ + delete _K[i]; + } + delete []_K; +} + +void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){ + 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} + }; + 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 }; + + // 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}, + }; + 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(exponent>_maxExponent) + return; + // compute K[iK] for this exponent and buffer + _currentInput->scale(0.0); + if(isBuffer){ + std::vector<dgGroupOfElements *>gVi=_innerBufferGroupsOfElements[exponent].first; + std::vector<dgGroupOfElements *>gVo=_outerBufferGroupsOfElements[exponent].first; + _currentInput->axpy(gVi,*_solution,1.0); + _currentInput->axpy(gVo,*_solution,1.0); + for(int i=0;i<iK;i++){ + _currentInput->axpy(gVi,*_K[i],_AInner[iK][i]); + _currentInput->axpy(gVo,*_K[i],_AOuter[iK][i]); + } + } + else{ + std::vector<dgGroupOfElements *>gV=_bulkGroupsOfElements[exponent].first; + _currentInput->axpy(gV,*_solution,1.0); + for(int i=0;i<iK;i++){ + _currentInput->axpy(gV,*_K[i],_A[iK][i]); + } + } + if(!isBuffer){ + switch(iK){ + case 0: + for(int i=0;i<4;i++){ + computeK(i,exponent+1,true); + } + break; + case 1: + computeK(4,exponent+1,true); + break; + case 2: + for(int i=5;i<9;i++){ + computeK(i,exponent+1,true); + } + break; + case 3: + computeK(9,exponent+1,true); + break; + } + } + else{ + if( (iK%5)<4 ){ + computeK(iK%5,exponent+1,false); + } + } + if( (iK==3 && !isBuffer) || (iK==9 && isBuffer) ){ + updateSolution(exponent,isBuffer); + } +} +void dgRungeKuttaMultirate::updateSolution(int exponent,bool isBuffer){} +void dgRungeKuttaMultirate::computeResidual(int exponent,bool isBuffer,dgDofContainer *solution, dgDofContainer *residual){ + if(isBuffer){ + std::vector<dgGroupOfElements *>*vei=&_innerBufferGroupsOfElements[exponent].first; + std::vector<dgGroupOfElements *>*veo=&_outerBufferGroupsOfElements[exponent].first; + for(int i=0;i<vei->size();i++){ + _residualVolume->computeAndMap1Group(*(*vei)[i], *solution, *residual); + } + for(int i=0;i<veo->size();i++){ + _residualVolume->computeAndMap1Group(*(*veo)[i], *solution, *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()); + 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)); + } + } + else{ + std::vector<dgGroupOfElements *> *ve=&_bulkGroupsOfElements[exponent].first; + for(int i=0;i<ve->size();i++){ + _residualVolume->computeAndMap1Group(*(*ve)[i], *solution, *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)); + } + } +} + +double dgRungeKuttaMultirate::iterate(double dt, dgDofContainer *solution){ + _solution=solution; + computeK(0,0,false); + computeK(1,0,false); + computeK(2,0,false); + computeK(3,0,false); + updateSolution(0,false); + + return solution->norm(); +} + +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>(); +} diff --git a/Solver/dgRungeKutta.h b/Solver/dgRungeKutta.h index 09a19cd2a963ec216a8286b098c4724462a7262e..4168dd6ad0fb61a6c0d4629969c25b5f4bfcc62e 100644 --- a/Solver/dgRungeKutta.h +++ b/Solver/dgRungeKutta.h @@ -1,8 +1,15 @@ #ifndef _DG_RUNGE_KUTTA_H_ #define _DG_RUNGE_KUTTA_H_ +#include <vector> +#include <map> class dgConservationLaw; class dgDofContainer; class dgLimiter; +class dgGroupCollection; +class dgGroupOfElements; +class dgGroupOfFaces; +class dgResidualVolume; +class dgResidualInterface; class binding; #include "fullMatrix.h" class dgRungeKutta { @@ -18,7 +25,33 @@ 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(); }; + +class dgRungeKuttaMultirate: public dgRungeKutta{ + private: + int _maxExponent; + int _minExponent; + dgConservationLaw *_law; + dgDofContainer *_solution; + dgDofContainer **_K; + dgDofContainer *_currentInput; + dgResidualVolume *_residualVolume; + dgResidualInterface *_residualInterface; + 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 computeK(int iK,int exponent,bool isBuffer); + void updateSolution(int exponent,bool isBuffer); + void computeResidual(int exponent,bool isBuffer,dgDofContainer *solution, dgDofContainer *residual); + public: + dgRungeKuttaMultirate(dgGroupCollection *gc,dgConservationLaw* law); + ~dgRungeKuttaMultirate(); + + + double iterate(double dt, dgDofContainer *solution); + static void registerBindings(binding *b); +}; #endif