From b21cb2e63fcbfacd91542325f9cdee2c14d6dbf8 Mon Sep 17 00:00:00 2001
From: Richard Comblen <richard.comblen@uclouvain.be>
Date: Thu, 4 Mar 2010 09:58:53 +0000
Subject: [PATCH] Tools to integrate a function

---
 Common/LuaBindings.cpp                  |  2 +
 Solver/CMakeLists.txt                   |  1 +
 Solver/TESTCASES/MultirateAdvection.lua | 11 ++++
 Solver/dgFunctionIntegrator.cpp         | 53 +++++++++++++++++
 Solver/dgFunctionIntegrator.h           | 10 ++++
 Solver/dgGroupOfElements.cpp            | 78 +++++++++++++++++--------
 6 files changed, 131 insertions(+), 24 deletions(-)
 create mode 100644 Solver/dgFunctionIntegrator.cpp
 create mode 100644 Solver/dgFunctionIntegrator.h

diff --git a/Common/LuaBindings.cpp b/Common/LuaBindings.cpp
index d5dd74b077..ba9f190a70 100644
--- a/Common/LuaBindings.cpp
+++ b/Common/LuaBindings.cpp
@@ -23,6 +23,7 @@
 #include "dgRungeKuttaMultirate.h"
 #include "dgSystemOfEquations.h"
 #include "dgLimiter.h"
+#include "dgFunctionIntegrator.h"
 #include "Bindings.h"
 #include "dgResidual.h"
 
@@ -347,6 +348,7 @@ binding::binding(){
   dgRungeKuttaMultirate43::registerBindings(this);
   dgSlopeLimiterRegisterBindings(this);
   dgSystemOfEquations::registerBindings(this);
+  dgFunctionIntegrator::registerBindings(this);
   fullMatrix<double>::registerBindings(this);
   function::registerBindings(this);
   function::registerDefaultFunctions();
diff --git a/Solver/CMakeLists.txt b/Solver/CMakeLists.txt
index 1ce5fa3a7b..6aa81f0fe1 100644
--- a/Solver/CMakeLists.txt
+++ b/Solver/CMakeLists.txt
@@ -29,6 +29,7 @@ set(SRC
   functionDerivator.cpp
   luaFunction.cpp
   functionSpace.cpp
+  dgFunctionIntegrator.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_SOURCE_DIR}/Solver *.h) 
diff --git a/Solver/TESTCASES/MultirateAdvection.lua b/Solver/TESTCASES/MultirateAdvection.lua
index 6ec63c036e..47636aa8ba 100644
--- a/Solver/TESTCASES/MultirateAdvection.lua
+++ b/Solver/TESTCASES/MultirateAdvection.lua
@@ -20,6 +20,13 @@ function velocity( XYZ, FCT )
   end
 end
 
+function toIntegrate( XYZ, FCT )
+  for i=0,XYZ:size1()-1 do
+    X = XYZ:get(i,0)
+    Y = XYZ:get(i,1)
+    FCT:set(i,0,X*X) 
+  end
+end
 --[[ 
      Example of a lua program driving the DG code
 --]]
@@ -87,6 +94,7 @@ time=0
 -- multirateRK:setLimiter(limiter)
 --for i=1,1000
 i=0
+integrator=dgFunctionIntegrator(functionLua(1, 'toIntegrate', {'XYZ'}):getName())
 while time<0.2 do
 --     norm1 = RK:iterate43SchlegelJCAM2009(law,dt,solution)
 -- TEST with Explicit Euler multirate !!!
@@ -94,6 +102,9 @@ while time<0.2 do
     time=time+dt
     if (i % 10 == 0) then 
        print('*** ITER ***',i,time,norm2)
+       v=fullMatrix(1,1);
+       integrator:compute(solution2,v);
+       print('integral : ',v:get(0,0,0))
     end
     if (i % 10 == 0) then 
   --     solution:exportMsh(string.format("output/rt-%06d", i)) 
diff --git a/Solver/dgFunctionIntegrator.cpp b/Solver/dgFunctionIntegrator.cpp
new file mode 100644
index 0000000000..58822d6b87
--- /dev/null
+++ b/Solver/dgFunctionIntegrator.cpp
@@ -0,0 +1,53 @@
+#include "function.h"
+#include "dgFunctionIntegrator.h"
+#include "dgDofContainer.h"
+#include "fullMatrix.h"
+#include "dgGroupOfElements.h"
+
+#include <stdio.h>
+
+dgFunctionIntegrator::dgFunctionIntegrator(std::string fName):_fName(fName){}
+
+void dgFunctionIntegrator::compute(dgDofContainer *sol,fullMatrix<double> &result){
+  int nbFields=sol->getNbFields();
+  dataCacheMap cacheMap;
+  dataCacheDouble &UVW=cacheMap.provideData("UVW", 1, 3);
+  dataCacheDouble &solutionQPe=cacheMap.provideData("Solution", 1, nbFields);
+  dataCacheElement &cacheElement=cacheMap.getElement();
+  function *f=function::get(_fName);
+  dataCacheDouble *F=f->newDataCache(&cacheMap);
+  int nbRowResult=result.size1();
+  result.scale(0.0);
+  for(int iGroup=0;iGroup<sol->getGroups()->getNbElementGroups();iGroup++){
+    dgGroupOfElements &group=*sol->getGroups()->getElementGroup(iGroup);
+    fullMatrix<double> &solProxy=sol->getGroupProxy(&group);
+    cacheMap.setNbEvaluationPoints(group.getNbIntegrationPoints());
+    UVW.set(group.getIntegrationPointsMatrix());
+    fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields);
+    group.getCollocationMatrix().mult(solProxy  , solutionQP); 
+    fullMatrix<double> IPMatrix = group.getIntegrationPointsMatrix();
+    for (int iElement=0 ; iElement<group.getNbElements() ;++iElement) {
+      solutionQPe.setAsProxy(solutionQP, iElement*nbFields, nbFields );
+      cacheElement.set(group.getElement(iElement));
+      for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) {
+        const double detJ = group.getDetJ (iElement, iPt);
+        for (int k=0;k<nbRowResult;k++){
+          result(0,k) += (*F)(iPt,k)*detJ*IPMatrix(iPt,3);
+        }
+      }
+    }
+  }
+}
+
+#include "Bindings.h"
+void dgFunctionIntegrator::registerBindings(binding *b){
+  classBinding *cb = b->addClass<dgFunctionIntegrator>("dgFunctionIntegrator");
+  cb->setDescription("Integrates a function, using the compute function");
+  methodBinding *mb;
+  mb = cb->setConstructor<dgFunctionIntegrator,std::string>();
+  mb->setArgNames("functionName",NULL);
+  mb->setDescription("a new dgFunctionIntegrator, get the solution using the compute method");
+  mb = cb->addMethod("compute", &dgFunctionIntegrator::compute);
+  mb->setArgNames("dofContainer","result",NULL);
+  mb->setDescription("compute the integral of the function");
+}
diff --git a/Solver/dgFunctionIntegrator.h b/Solver/dgFunctionIntegrator.h
new file mode 100644
index 0000000000..ebbb803764
--- /dev/null
+++ b/Solver/dgFunctionIntegrator.h
@@ -0,0 +1,10 @@
+#include <string>
+class dgDofContainer;
+class binding;
+class dgFunctionIntegrator{
+  std::string _fName;
+  public:
+  dgFunctionIntegrator(std::string fName);
+  void compute(dgDofContainer *sol,fullMatrix<double> &result);
+  static void registerBindings(binding *b);
+};
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index b9aceb8445..854e23e1aa 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -1052,6 +1052,12 @@ void dgGroupCollection::buildGroupsOfInterfaces()
 
 // Split the groups of elements depending on their local time step
 double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLaw *claw, dgDofContainer *solution) {
+  // What are the levels/layers:
+  // bulk: elements that are time stepped using the "normal" 4 stage Runge-Kutta
+  // innerBuffer: elements that use the small time step but talks to elements using the big time step
+  // outerBuffer: elements that use the big time step but talks to elements using the small time step
+
+
   Msg::Info("Splitting Groups for multirate time stepping");
   maxLevels--;// Number becomes maximum id
 
@@ -1059,8 +1065,14 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
   std::vector<dgMiniInterface> *miniInterfaceV=_createMiniInterfaces(*this);
   // elementToNeighbors[oldGroupId][oldElementId][neighborId (i.e. 0 to 2 for triangles)]<neighborOldGroupId,neighborOldElementId>
   std::vector<std::vector<std::vector<std::pair<int,int> > > >elementToNeighbors;
-
+  // id of the new group, indexed by [oldGroupId][oldElementId]
+  // -1 if the element is not yet in a new group
+  // -2 if the element is in a new group whose id is not determined yet
   std::vector<std::vector<int> >newGroupIds;
+  std::vector< dgGroupOfElements* >newGroups;// indexed by newGroupId
+  // localDt[oldGroupId][oldElementId]
+  std::vector<std::vector<double> >localDt;
+
   newGroupIds.resize(getNbElementGroups());
   elementToNeighbors.resize(getNbElementGroups());
   for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){
@@ -1068,6 +1080,8 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
     elementToNeighbors[iGroup].resize(g->getNbElements());
     newGroupIds[iGroup].assign(g->getNbElements(),-1);
   }
+
+  // Build elementToNeighbors table (needed to have random access to the neighbors)
   for(int iInterface=0;iInterface<miniInterfaceV->size();iInterface++){
     dgMiniInterface &interface=miniInterfaceV->at(iInterface);
     for(int iConn=0;iConn<interface.connectedElements.size();iConn++){
@@ -1082,10 +1096,9 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
     }
   }
 
-  // find the range of time steps
+  // Compute the time step constrain per element
   double dtMin = DBL_MAX;
   double dtMax = 0;
-  std::vector<std::vector<double> >localDt;
   localDt.resize(getNbElementGroups());
   for (int i=0;i<getNbElementGroups();i++){
     dgAlgorithm::computeElementaryTimeSteps(*claw, *getElementGroup(i), solution->getGroupProxy(i), localDt[i]);
@@ -1102,12 +1115,16 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
   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.
 
   Msg::Info("Time step for standard RK should be %e",dtMin);
   Msg::Info("Multirate base time step should be %e",dtMax);
 
+
+
+  // We take the base time step as 80% of the largest elementary time-step.
+  // This is arbitrary and should be optimized (maybe on the fly...)
   double 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)
@@ -1117,30 +1134,38 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
     dtMaxExponent=maxLevels;
   }
   _dtMaxExponent=dtMaxExponent;
-  std::vector<MElement *>currentNewGroup;
-  std::vector< dgGroupOfElements* >newGroups;// indexed by newGroupId
 
+
+  // Bounds to be able to access elements at the previous level (to add the neighbors in the current group)
   int lowerLevelGroupIdStart=-1;
   int lowerLevelGroupIdEnd=-1;
 
   bool isOuterBufferLayer=false;
   int currentNewGroupId=0;
   int loopId=0;
+
+  // We pass two times by each exponent level: one for the normal(bulk) + innerBuffer groups, and one for the outerBuffer groups
   for(int currentExponent=dtMaxExponent;currentExponent>=0;(!isOuterBufferLayer)?currentExponent--:currentExponent=currentExponent){
     double currentDt=dtRef/pow(2.0,(double)currentExponent);
-    std::map<int,std::vector<std::pair<int,int> > >mapNewGroups;
+    // element for the new groups at this level:
+    // mapNewGroups[oldGroupId][oldElementId]
+    std::map<int,std::vector<int> >mapNewGroups;
     if(lowerLevelGroupIdStart==-1){
       lowerLevelGroupIdStart=0;
     }
     else{
 
       // Add the neighbors elements to the new groups
+      // For buffer AND non buffer layers
       int _lowerLevelGroupIdStart=lowerLevelGroupIdStart;
       int _lowerLevelGroupIdEnd=lowerLevelGroupIdEnd;
       lowerLevelGroupIdStart=lowerLevelGroupIdEnd;
       for(int iInterface=0;iInterface<miniInterfaceV->size();iInterface++){
         dgMiniInterface &interface=miniInterfaceV->at(iInterface);
         bool toAdd=false;
+        // if one of the elements adjacent to the interface is mapped to the previous level
+        // we check all elements adjacent to this interface, and add those that does not
+        // already have a new group to the current new group
         for(int iConn=0;iConn<interface.connectedElements.size();iConn++){
           int gId=interface.connectedElements[iConn].first;
           int eId=interface.connectedElements[iConn].second;
@@ -1156,7 +1181,7 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
             int eId=interface.connectedElements[iConn].second;
             int newGroupId=newGroupIds[gId][eId];
             if(newGroupId==-1){
-              mapNewGroups[gId].push_back(std::pair<int,int>(gId,eId));
+              mapNewGroups[gId].push_back(eId);
               newGroupIds[gId][eId]=-2;
             }
           }
@@ -1164,27 +1189,29 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
       }
     }
     if(!isOuterBufferLayer){
+      // We add all the elements that are stable with the current time step, but not with twice that time step
       for(int iGroup=0;iGroup<getNbElementGroups();iGroup++){
         dgGroupOfElements *elGroup=getElementGroup(iGroup);
         for(int iElement=0;iElement<elGroup->getNbElements();iElement++){
           if(localDt[iGroup][iElement]>=currentDt && (localDt[iGroup][iElement]<currentDt*2 || currentExponent==0)){
             if(newGroupIds[iGroup][iElement]==-1){
-              mapNewGroups[iGroup].push_back(std::pair<int,int>(iGroup,iElement));
+              mapNewGroups[iGroup].push_back(iElement);
               newGroupIds[iGroup][iElement]=-2;
             }
           }
         }
       }
+
+      // We split those elements into bulk and innerBuffer (i.e. those who have a neighbor with a bigger time step)
       lowerLevelGroupIdStart=currentNewGroupId;
-      for (std::map<int, std::vector<std::pair<int,int> > >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){
+      for (std::map<int, std::vector<int> >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){
         if(!it->second.empty()){
-          std::vector<std::pair<int,int> >forBulk;
-          std::vector<std::pair<int,int> >forInnerBuffer;
+          std::vector<int>forBulk;
+          std::vector<int>forInnerBuffer;
           for(int i=0;i<it->second.size();i++){
             bool inInnerBuffer=false;
-  //std::vector<std::vector<std::vector<std::pair<int,int> > > >elementToNeighbors;
-            int oldGId=it->second[i].first;
-            int oldEId=it->second[i].second;
+            int oldGId=it->first;
+            int oldEId=it->second[i];
             for(int iNeighbor=0;iNeighbor<elementToNeighbors[oldGId][oldEId].size();iNeighbor++){
               std::pair<int,int> neighIds=elementToNeighbors[oldGId][oldEId][iNeighbor];
               if(newGroupIds[neighIds.first][neighIds.second]==-1){
@@ -1193,21 +1220,21 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
               }
             }
             if(inInnerBuffer){
-              forInnerBuffer.push_back(std::pair<int,int>(oldGId,oldEId));
+              forInnerBuffer.push_back(oldEId);
             }
             else{
-              forBulk.push_back(std::pair<int,int>(oldGId,oldEId));
+              forBulk.push_back(oldEId);
             }
           }
           for(int i=0;i<forBulk.size();i++){
-            newGroupIds[forBulk[i].first][forBulk[i].second]=currentNewGroupId;
+            newGroupIds[it->first][forBulk[i]]=currentNewGroupId;
           }
           dgGroupOfElements *oldGroup=getElementGroup(it->first);
           dgGroupOfElements *newGroup;
           if(!forBulk.empty()){
             std::vector<MElement*>forBulkV;
             for(int i=0;i<forBulk.size();i++){
-              forBulkV.push_back(getElementGroup(forBulk[i].first)->getElement(forBulk[i].second));
+              forBulkV.push_back(getElementGroup(it->first)->getElement(forBulk[i]));
             }
             newGroup=new dgGroupOfElements(forBulkV,oldGroup->getOrder(),oldGroup->getGhostPartition());
             newGroup->copyPrivateDataFrom(oldGroup);
@@ -1222,7 +1249,7 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
           if(!forInnerBuffer.empty()){
             std::vector<MElement*>forInnerBufferV;
             for(int i=0;i<forInnerBuffer.size();i++){
-              forInnerBufferV.push_back(getElementGroup(forInnerBuffer[i].first)->getElement(forInnerBuffer[i].second));
+              forInnerBufferV.push_back(getElementGroup(it->first)->getElement(forInnerBuffer[i]));
             }
             newGroup=new dgGroupOfElements(forInnerBufferV,oldGroup->getOrder(),oldGroup->getGhostPartition());
             newGroup->copyPrivateDataFrom(oldGroup);
@@ -1239,17 +1266,17 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
       }
     }
     else{
-      for (std::map<int, std::vector<std::pair<int,int> > >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){
+      for (std::map<int, std::vector<int> >::iterator it = mapNewGroups.begin(); it !=mapNewGroups.end() ; ++it){
         if(!it->second.empty()){
           for(int i=0;i<it->second.size();i++){
-            int oldGId=it->second[i].first;
-            int oldEId=it->second[i].second;
+            int oldGId=it->first;
+            int oldEId=it->second[i];
             newGroupIds[oldGId][oldEId]=currentNewGroupId;
           }
           dgGroupOfElements *oldGroup=getElementGroup(it->first);
           std::vector<MElement *>newGroupV;
           for(int i=0;i<it->second.size();i++){
-            newGroupV.push_back(getElementGroup(it->second[i].first)->getElement(it->second[i].second));
+            newGroupV.push_back(getElementGroup(it->first)->getElement(it->second[i]));
           }
           dgGroupOfElements *newGroup=new dgGroupOfElements(newGroupV,oldGroup->getOrder(),oldGroup->getGhostPartition());
           newGroup->copyPrivateDataFrom(oldGroup);
@@ -1267,6 +1294,9 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
     lowerLevelGroupIdEnd=currentNewGroupId;
     isOuterBufferLayer=!isOuterBufferLayer;
   }
+
+
+  // Some stats
   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());
-- 
GitLab