From 23f7f0e823d2a91fe5a3c889e8112b8bd4441cc4 Mon Sep 17 00:00:00 2001
From: Konstantin Kutscher <kutscher@irmb.tu-bs.de>
Date: Tue, 24 May 2016 16:26:00 +0000
Subject: [PATCH] PID controller implemented in AdjustForcingCoProcessor

---
 source/Applications/FNG/fng.cpp               | 74 ++++++++--------
 .../pChannel/configBombadilpChannel.cfg       | 14 ++--
 source/Applications/pChannel/pChannel.cpp     | 11 ++-
 .../CoProcessors/AdjustForcingCoProcessor.cpp | 84 ++++++++++++++-----
 .../CoProcessors/AdjustForcingCoProcessor.h   | 22 ++++-
 .../TimeAveragedValuesCoProcessor.cpp         |  2 +-
 6 files changed, 134 insertions(+), 73 deletions(-)

diff --git a/source/Applications/FNG/fng.cpp b/source/Applications/FNG/fng.cpp
index 8be1bb26d..620aeb85f 100644
--- a/source/Applications/FNG/fng.cpp
+++ b/source/Applications/FNG/fng.cpp
@@ -8,50 +8,56 @@
 using namespace std;
 
 
-void setup(const char *cstr1, const char *cstr2)
+void run(string configname)
 {
    try
    {
-      //Sleep(30000);
-
-      ConfigFileReader cf(cstr1);
-      if ( !cf.read() )
-      {
-         std::string exceptionText = "Unable to read configuration file\n";
-         throw exceptionText;
-      }
-
-      //parameters from config file
-      string machine = cf.getValue("machine");
-      string pathname = cf.getValue("path");
-      string geoFile = cf.getValue("geoFile");
-      int numOfThreads = UbSystem::stringTo<int>(cf.getValue("numOfThreads"));
-      double availMem = UbSystem::stringTo<double>(cf.getValue("availMem"));
-      int refineLevel = UbSystem::stringTo<int>(cf.getValue("refineLevel"));
-      int blocknx = UbSystem::stringTo<int>(cf.getValue("blocknx"));
+      ConfigurationFile   config;
+      config.load(configname);
+
+      string          pathname = config.getString("pathname");
+      string          pathGeo = config.getString("pathGeo");
+      string          geoFile1 = config.getString("geoFile1");
+      string          geoFile2 = config.getString("geoFile2");
+      int             numOfThreads = config.getInt("numOfThreads");
+      vector<int>     blocknx = config.getVector<int>("blocknx");
+      double          u_LB = config.getDouble("u_LB");
+      double          restartStep = config.getDouble("restartStep");
+      double          restartStepStart = config.getDouble("restartStepStart");
+      double          endTime = config.getDouble("endTime");
+      double          outTime = config.getDouble("outTime");
+      double          availMem = config.getDouble("availMem");
+      int             refineLevel = config.getInt("refineLevel");
+      bool            logToFile = config.getBool("logToFile");
 
       CommunicatorPtr comm = MPICommunicator::getInstance();
       int myid = comm->getProcessID();
 
-      if(machine == "Bombadil") int dumy=0; 
-      else if(machine == "Ludwig" || machine == "HLRN")      
+      if (logToFile)
       {
-         if(myid ==0)
+#if defined(__unix__)
+         if (myid == 0)
+         {
+            const char* str = pathname.c_str();
+            mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+         }
+#endif 
+
+         if (myid == 0)
          {
             stringstream logFilename;
-            logFilename <<  pathname + "/logfile"+UbSystem::toString(UbSystem::getTimeStamp())+".txt";
+            logFilename << pathname + "/logfile" + UbSystem::toString(UbSystem::getTimeStamp()) + ".txt";
             UbLog::output_policy::setStream(logFilename.str());
          }
       }
-      else throw UbException(UB_EXARGS, "unknown machine");
 
-      GbTriFaceMesh3DPtr geo (GbTriFaceMesh3DCreator::getInstance()->readMeshFromSTLFile(geoFile,"geo"));
+      GbTriFaceMesh3DPtr geo (GbTriFaceMesh3DCreator::getInstance()->readMeshFromSTLFile(geoFile1,"geo"));
       if(myid == 0) GbSystem3D::writeGeoObject(geo.get(), pathname+"/geo/geo", WbWriterVtkXmlASCII::getInstance());
 
       double dx = (fabs(geo->getX3Maximum()-geo->getX3Minimum())*10e-3)*(double)(1<<refineLevel);
       dx /= 4.0;
 
-      double blockLength = blocknx*dx;
+      double blockLength = blocknx[0]*dx;
 
       double offsetX1 = fabs(geo->getX1Maximum()-geo->getX1Minimum());
       double h = fabs(geo->getX3Maximum()-geo->getX3Minimum());
@@ -69,18 +75,18 @@ void setup(const char *cstr1, const char *cstr2)
       //##########################################################################
       //## physical parameters
       //##########################################################################
-      double Re            = 1e6;
+      double Re       = 1e6;
 
       double rhoLB    = 0.0;
-      double rhoReal  = 1.0;
-      double nueReal  = 0.000015;//0.015;
+      double rhoReal  = 1.2041; //(kg/m3)
+      double nueReal  = 153.5e-7; //m^2/s
 
-      double lReal    =  3.0;//<-m     ;//Profile laenge in cm(! cm nicht m !)
+      double lReal    = 3.0;//m
       double uReal    = Re*nueReal/lReal;
 
       //##Machzahl:
       //#Ma     = uReal/csReal
-      double Ma      = 0.1;//Ma-Real!
+      double Ma      = 0.15;//Ma-Real!
       double csReal  = uReal/Ma;
       double hLB     = lReal/dx;
 
@@ -98,7 +104,7 @@ void setup(const char *cstr1, const char *cstr2)
       //////////////////////////////////////////////////////////////////////////
       Grid3DPtr grid(new Grid3D(comm));
       grid->setDeltaX(dx);
-      grid->setBlockNX(blocknx, blocknx, blocknx);
+      grid->setBlockNX(blocknx[0], blocknx[1], blocknx[2]);
       
       GbObject3DPtr gridCube(new GbCuboid3D(g_minX1, g_minX2, g_minX3, g_maxX1, g_maxX2, g_maxX3));
       //gridCube->setCenterCoordinates(geo->getX1Centroid(), geo->getX2Centroid(), geo->getX3Centroid());
@@ -115,7 +121,7 @@ void setup(const char *cstr1, const char *cstr2)
 
       UbSchedulerPtr rSch(new UbScheduler());
       rSch->addSchedule(50,50,50);
-      RestartPostprocessorPtr rp(new RestartPostprocessor(grid, rSch, comm, pathname+"/checkpoints", RestartPostprocessor::TXT));
+      RestartCoProcessorPtr rp(new RestartCoProcessor(grid, rSch, comm, pathname+"/checkpoints", RestartCoProcessor::TXT));
       
 
       std::string opt;
@@ -399,9 +405,9 @@ int main(int argc, char* argv[])
 
    if ( argv != NULL )
    {
-      if (argc > 1)
+      if (argv[1] != NULL)
       {
-         setup(argv[1], argv[2]);
+         run(string(argv[1]));
       }
       else
       {
diff --git a/source/Applications/pChannel/configBombadilpChannel.cfg b/source/Applications/pChannel/configBombadilpChannel.cfg
index 548e8ca59..c1ae0bf88 100644
--- a/source/Applications/pChannel/configBombadilpChannel.cfg
+++ b/source/Applications/pChannel/configBombadilpChannel.cfg
@@ -2,7 +2,7 @@
 #Simulation parameters for porous channel
 #
 
-pathname = d:/temp/pChannel5
+pathname = d:/temp/pChannel6
 pathGeo = d:/Projects/SFB880/GeometrienPoroeseMedien/PA80-110
 numOfThreads = 4
 availMem = 4e9
@@ -66,7 +66,7 @@ blocknx = 10 10 10
 #blocknx = 32 40 20
 lengthFactor = 4
 thinWall = false
-forcing = 1e-6
+forcing = 7.83841e-09
 changeQs = false
 
 channelHigh = 0.002
@@ -82,15 +82,15 @@ channelHigh = 0.002
 # for DLRF-15 Re = 102000/2
 Re = 51000
 #real velocity is 54.95 m/s
-u_LB = 0.1
+u_LB = 0.01
 
-restartStep = 3
-restartStepStart = 3
+restartStep = 500
+restartStepStart = 500
 
-timeAvStart = 2
+timeAvStart = 1
 timeAvStop = 5
 
-endTime = 5
+endTime = 1000
 outTime = 1000
  
 
diff --git a/source/Applications/pChannel/pChannel.cpp b/source/Applications/pChannel/pChannel.cpp
index 03b985410..6552f9866 100644
--- a/source/Applications/pChannel/pChannel.cpp
+++ b/source/Applications/pChannel/pChannel.cpp
@@ -372,11 +372,14 @@ void run(string configname)
          grid->accept(bcVisitor);
 
          mu::Parser inflowProfile;
-     //inflowProfile.SetExpr("x3 < h ? 0.0 : uLB+1*x1-1*x2");
+       //inflowProfile.SetExpr("x3 < h ? 0.0 : uLB+1*x1-1*x2");
 		   //inflowProfile.SetExpr("uLB+1*x1-1*x2");
          inflowProfile.SetExpr("uLB");
-         inflowProfile.DefineConst("uLB", u_LB);
-         inflowProfile.DefineConst("h", pmL[2]);
+         //inflowProfile.DefineConst("uLB", u_LB);
+         inflowProfile.DefineConst("uLB", 0.0116);
+         //inflowProfile.DefineConst("h", pmL[2]);
+
+         //inflowProfile = Utilities::getDuctParaboloidX(g_maxX2/2.0, g_maxX2, pmL[2]+channelHigh/2.0, channelHigh, 0.116);
 
          D3Q27ETInitDistributionsBlockVisitor initVisitor(nu_LB, rho_LB);
          initVisitor.setVx1(inflowProfile);
@@ -490,7 +493,7 @@ void run(string configname)
 
 
       UbSchedulerPtr AdjForcSch(new UbScheduler());
-      AdjForcSch->addSchedule(1, 0, 10000000);
+      AdjForcSch->addSchedule(10, 0, 10000000);
       D3Q27IntegrateValuesHelperPtr intValHelp(new D3Q27IntegrateValuesHelper(grid, comm,
          coord[0], coord[1], coord[2],
          coord[3], coord[4], coord[5]));
diff --git a/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.cpp b/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.cpp
index a233a680b..f60c7c1ef 100644
--- a/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.cpp
+++ b/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.cpp
@@ -2,7 +2,7 @@
 * D3Q27AdjustForcingCoProcessor.cpp
 *
 *  
-*  Author: Sonja Uphoff
+*  Author: Konstantin Kutscher
 */
 
 #include "AdjustForcingCoProcessor.h"
@@ -19,18 +19,17 @@ using namespace std;
 AdjustForcingCoProcessor::AdjustForcingCoProcessor(Grid3DPtr grid, UbSchedulerPtr s,
                                                                  const std::string& path,
                                                                  D3Q27IntegrateValuesHelperPtr integrateValues, 
-                                                                 double vTarged,
-                                                                 double forcing,
+                                                                 double vTarged, double forcing,
                                                                  CommunicatorPtr comm)
 
                                                                  : CoProcessor(grid, s),
                                                                  path(path),
                                                                  integrateValues(integrateValues),
                                                                  comm(comm),
-                                                                 vTarged(vTarged),
+                                                                 vx1Targed(vTarged),
                                                                  forcing(forcing)
 {
-   cnodes = integrateValues->getCNodes();
+   //cnodes = integrateValues->getCNodes();
    if (comm->getProcessID() == comm->getRoot())
    {
       std::string fname = path+"/forcing/forcing.csv";
@@ -43,9 +42,37 @@ AdjustForcingCoProcessor::AdjustForcingCoProcessor(Grid3DPtr grid, UbSchedulerPt
          if (path.size()>0) { UbSystem::makeDirectory(path); ostr.open(fname.c_str(), std::ios_base::out | std::ios_base::app); }
          if (!ostr) throw UbException(UB_EXARGS, "couldn't open file "+fname);
       }
-      ostr << "step;volume;vx1average;factor;forcing\n";
+      ostr << "step;volume;vx1average;forcing\n";
       ostr.close();
    }
+   
+   Ta = scheduler->getMaxStep();
+
+   Kpcrit = 3.0 / Ta;// 0.3;
+   Tcrit = 3.0 * Ta; // 30.0;
+   Tn = 0.5 * Tcrit;
+   Tv = 0.12 * Tcrit;
+    
+   Kp = 0.6 * Kpcrit;
+   Ki = Kp / Tn;
+   Kd = Kp * Tv;
+   
+   y = 0;
+   e = 0;
+   esum = 0;
+   //////////////////////////////////////////////////////////////////////////////////////////////////
+   //temporere Lösung
+   std::string fNameCfg = path + "/forcing/forcing.cfg";
+   std::ifstream istr2;
+   istr2.open(fNameCfg.c_str(), std::ios_base::in);
+   if (istr2)
+   {
+      istr2 >> forcing;
+      istr2 >> esum;
+      istr2 >> eold;
+   }
+   istr2.close();
+   ////////////////////////////////////////////////////////////////////////////////////////////////////////
 }
 //////////////////////////////////////////////////////////////////////////
 AdjustForcingCoProcessor::~AdjustForcingCoProcessor() 
@@ -60,6 +87,22 @@ void AdjustForcingCoProcessor::process(double step)
 //////////////////////////////////////////////////////////////////////////
 void AdjustForcingCoProcessor::collectData(double step)
 {
+   //////////////////////////////////////////////////////////////////////////////////////////////////
+   //temporere Lösung
+   std::string fNameCfg = path + "/forcing/forcing.cfg";
+   std::ofstream ostr2;
+   ostr2.open(fNameCfg.c_str(), std::ios_base::out);
+   if (!ostr2)
+   {
+      ostr2.clear();
+      string path = UbSystem::getPathFromString(fNameCfg);
+      if (path.size() > 0) { UbSystem::makeDirectory(path); ostr2.open(fNameCfg.c_str(), std::ios_base::out); }
+      if (!ostr2) throw UbException(UB_EXARGS, "couldn't open file " + fNameCfg);
+   }
+   ostr2 << forcing << " " << esum << " " << eold;
+   ostr2.close();
+   ////////////////////////////////////////////////////////////////////////////////////////////////////////
+
    integrateValues->calculateMQ();
 
    UBLOG(logDEBUG3, "D3Q27AdjustForcingCoProcessor::update:" << step);
@@ -72,24 +115,17 @@ void AdjustForcingCoProcessor::collectData(double step)
    double vx1 = integrateValues->getVx1();
    double vx1Average = (vx1/cellsVolume);
 
-   //double C = 5.0; //0.7 //P; //free parameter [0.1, 1]
-   //double factor = 1.0 - ((vx1average - vTarged) / vTarged)*C;
-   
-   double factor = vTarged / vx1Average;
-   //forcing *= factor;
-   
-   //forcing = UbMath::max(forcing, 0.0);
-   //forcing = UbMath::min(forcing, 5e-3);
+//////////////////////////////////////////////////////////////////////////
+//PID-Controller (PID-Regler)
+   e = vx1Targed - vx1Average;
+   esum = esum + e;
+   y = Kp * e + Ki * Ta * esum + Kd * (e - eold) / Ta;
+   eold = e;
 
-   if (vTarged > vx1Average)
-   {
-      forcing = fabs(factor*forcing);
-   } 
-   else
-   {
-      forcing = -fabs(factor*forcing);
-   }
+   forcing = forcing + y;
+//////////////////////////////////////////////////////////////////////////
 
+   //////////////////////////////////////////////////////////////////////////
    mu::Parser fctForcingX1, fctForcingX2, fctForcingX3;
    fctForcingX1.SetExpr("Fx1");
    fctForcingX1.DefineConst("Fx1", forcing);
@@ -124,7 +160,9 @@ void AdjustForcingCoProcessor::collectData(double step)
          if (!ostr) throw UbException(UB_EXARGS, "couldn't open file "+fname);
       }
       int istep = static_cast<int>(step);
-      ostr << istep << ";" << cellsVolume << ";" << vx1Average << "; " << factor << "; " << forcing << "\n";
+      
+      ostr << istep << ";" << cellsVolume << ";" << vx1Average << "; " << forcing << "\n";
       ostr.close();
+
    }
 }
diff --git a/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.h b/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.h
index c7e99ecf4..8eb785843 100644
--- a/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.h
+++ b/source/VirtualFluidsCore/CoProcessors/AdjustForcingCoProcessor.h
@@ -10,8 +10,9 @@
 class AdjustForcingCoProcessor;
 typedef boost::shared_ptr<AdjustForcingCoProcessor> AdjustForcingCoProcessorPtr;
 
-//! \brief   Computes Forcing such that a given velocity (vxZiel) is reached inside an averaging domain (h1). 
-//! \details Integrate values helper, scheduler must be set in test case. Example usage: bKanal.cpp
+//! \brief   Computes forcing such that a given velocity (vx1Targed) is reached inside an averaging domain (h1). 
+//! \details Algorithm based on PID controller (proportional–integral–derivative controller). The parameters of PID controller estimation based on Ziegler–Nichols method. 
+//!          Integrate values helper, scheduler must be set in test case.
 //! \author: Konstantin Kutscher
 
 class AdjustForcingCoProcessor: public CoProcessor {
@@ -30,9 +31,22 @@ protected:
 	void collectData(double step);  
    CommunicatorPtr comm;
 private:
-   double vTarged; //!< target velocity.
+   double vx1Targed; //!< target velocity.
    double forcing; //!< forcing at previous update step. 
-   std::vector<CalcNodes> cnodes;
+
+   double Kpcrit; //Kp critical
+   double Tcrit;  //the oscillation period 
+   double Tn;
+   double Tv;
+   double e;
+   double Ta;
+   double Kp;
+   double Ki;
+   double Kd;
+   double y;
+   double esum;
+   double eold;
+   //std::vector<CalcNodes> cnodes;
    std::string path;
 };
 
diff --git a/source/VirtualFluidsCore/CoProcessors/TimeAveragedValuesCoProcessor.cpp b/source/VirtualFluidsCore/CoProcessors/TimeAveragedValuesCoProcessor.cpp
index 910ec8721..294b6464e 100644
--- a/source/VirtualFluidsCore/CoProcessors/TimeAveragedValuesCoProcessor.cpp
+++ b/source/VirtualFluidsCore/CoProcessors/TimeAveragedValuesCoProcessor.cpp
@@ -112,7 +112,7 @@ void TimeAveragedValuesCoProcessor::process(double step)
    if (scheduler->isDue(step))
    {
       //DEBUG/////////////////////
-      UBLOG(logINFO, "step = " << step << ", lcounter = " << lcounter << ", fineStep = " << fineStep << ", maxFineStep = " << maxFineStep << ", numberOfFineSteps = " << numberOfFineSteps);
+      //UBLOG(logINFO, "step = " << step << ", lcounter = " << lcounter << ", fineStep = " << fineStep << ", maxFineStep = " << maxFineStep << ", numberOfFineSteps = " << numberOfFineSteps);
       ////////////////////////////
 
       calculateSubtotal();
-- 
GitLab