From 01ca5b4caafa447c4cc65b6092737895621c2ce3 Mon Sep 17 00:00:00 2001
From: Tuomas Karna <tuomas.karna@uclouvain.be>
Date: Fri, 5 Mar 2010 17:02:52 +0000
Subject: [PATCH] dg: added 2nd order Prism18

---
 Geo/GModel.cpp                   |   2 +-
 Geo/MPrism.cpp                   |   4 +-
 Geo/MPrism.h                     |   9 +--
 Numeric/GaussQuadraturePri.cpp   |   2 +-
 Numeric/polynomialBasis.cpp      | 105 ++++++++++++++++++++-----------
 Solver/TESTCASES/Diffusion3D.lua |  23 +++----
 Solver/TESTCASES/mixed.geo       |   6 +-
 Solver/dgDofContainer.cpp        |   4 ++
 8 files changed, 92 insertions(+), 63 deletions(-)

diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index 5aff9d50c4..346edff76f 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1334,7 +1334,7 @@ void GModel::load(std::string fileName)
 {
   GModel *temp = GModel::current();
   GModel::setCurrent(this);
-  MergeFile(fileName.c_str());
+  MergeFile(fileName.c_str(),true);
   GModel::setCurrent(temp);
 }
 
diff --git a/Geo/MPrism.cpp b/Geo/MPrism.cpp
index dbe7e9b8ac..4728e9d722 100644
--- a/Geo/MPrism.cpp
+++ b/Geo/MPrism.cpp
@@ -37,14 +37,14 @@ const polynomialBasis* MPrism::getFunctionSpace(int o) const
     switch (order) {
     case 1: return &polynomialBases::find(MSH_PRI_6);
     case 2: return &polynomialBases::find(MSH_PRI_18);
-    default: Msg::Error("Order %d tetrahedron function space not implemented", order);
+    default: Msg::Error("Order %d prism function space not implemented", order);
     }
   }
   else { 
     switch (order) {
     case 1: return &polynomialBases::find(MSH_PRI_6);
     case 2: return &polynomialBases::find(MSH_PRI_18);
-    default: Msg::Error("Order %d tetrahedron function space not implemented", order);
+    default: Msg::Error("Order %d prism function space not implemented", order);
     }
   }
   return 0;
diff --git a/Geo/MPrism.h b/Geo/MPrism.h
index 3d1220f472..97a796eb18 100644
--- a/Geo/MPrism.h
+++ b/Geo/MPrism.h
@@ -131,7 +131,7 @@ class MPrism : public MElement {
   }
   virtual const polynomialBasis* getFunctionSpace(int o=-1) const;
   virtual int getVolumeSign();
-  virtual void getShapeFunctions(double u, double v, double w, double s[], int o) 
+/*  virtual void getShapeFunctions(double u, double v, double w, double s[], int o) 
   {
     s[0] = (1. - u - v) * (1. - w) * 0.5;
     s[1] =       u      * (1. - w) * 0.5;
@@ -139,9 +139,10 @@ class MPrism : public MElement {
     s[3] = (1. - u - v) * (1. + w) * 0.5;
     s[4] =       u      * (1. + w) * 0.5;
     s[5] =           v  * (1. + w) * 0.5;
-  }
-  virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o) 
+  }*/
+/*  virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o) 
   {
+    printf("here\n");
     s[0][0] = -0.5 * (1. - w)    ;
     s[0][1] = -0.5 * (1. - w)    ;
     s[0][2] = -0.5 * (1. - u - v);
@@ -160,7 +161,7 @@ class MPrism : public MElement {
     s[5][0] =  0.                ;
     s[5][1] =  0.5 * (1. + w)    ;
     s[5][2] =  0.5 * v           ;
-  }
+  }*/
   virtual bool isInside(double u, double v, double w)
   {
     double tol = _isInsideTolerance;
diff --git a/Numeric/GaussQuadraturePri.cpp b/Numeric/GaussQuadraturePri.cpp
index 3996d29543..7696549480 100644
--- a/Numeric/GaussQuadraturePri.cpp
+++ b/Numeric/GaussQuadraturePri.cpp
@@ -10,7 +10,7 @@
 IntPt *getGQPriPts(int order);
 int getNGQPriPts(int order);
 
-IntPt * GQP[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+IntPt * GQP[28] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
 IntPt *getGQPriPts(int order)
 { 
diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp
index d63c948e43..b2a59a6690 100644
--- a/Numeric/polynomialBasis.cpp
+++ b/Numeric/polynomialBasis.cpp
@@ -244,17 +244,15 @@ static fullMatrix<double> generatePascalPrism(int order)
   int index = 0;
   fullMatrix<double> lineMonoms = generate1DMonomials(order);
   fullMatrix<double> triMonoms = generatePascalTriangle(order);
-//   printf("nb: %d nT: %d %d nL: %d %d\n",nbMonomials,triMonoms.size1(),(order+1)*(order+2)/2,lineMonoms.size1(),order+1);
   for (int j = 0; j < lineMonoms.size1(); j++) {
     for (int i = 0; i < triMonoms.size1(); i++) {
-      monomials(index,0) = triMonoms(i,0);
-      monomials(index,1) = triMonoms(i,1);
-      monomials(index,2) = lineMonoms(j,0);
-      index ++;
-//       printf("%d: %f %f %f\n",index,triMonoms(i,0),triMonoms(i,1),lineMonoms(j,0));
+        monomials(index,0) = triMonoms(i,0);
+        monomials(index,1) = triMonoms(i,1);
+        monomials(index,2) = lineMonoms(j,0);
+        index ++;
     }
   }
-//   monomials.print();
+  monomials.print("Pri monoms");
   return monomials;
 }  
 
@@ -625,26 +623,50 @@ static fullMatrix<double> gmshGeneratePointsTriangle(int order, bool serendip)
 
 static fullMatrix<double> gmshGeneratePointsPrism(int order, bool serendip) 
 {
+  const double prism18Pts[18][3] = {
+    {0, 0, -1}, // 0
+    {1, 0, -1}, // 1
+    {0, 1, -1}, // 2
+    {0, 0, 1},  // 3
+    {1, 0, 1},  // 4
+    {0, 1, 1},  // 5
+    {0.5, 0, -1},  // 6
+    {0, 0.5, -1},  // 7
+    {0, 0, 0},  // 8
+    {0.5, 0.5, -1},  // 9
+    {1, 0, 0},  // 10
+    {0, 1, 0},  // 11
+    {0.5, 0, 1},  // 12
+    {0, 0.5, 1},  // 13
+    {0.5, 0.5, 1},  // 14
+    {0.5, 0, 0},  // 15
+    {0, 0.5, 0},  // 16
+    {0.5, 0.5, 0},  // 17
+  };
+
   int nbPoints = (order + 1)*(order + 1)*(order + 2)/2; 
   fullMatrix<double> point(nbPoints, 3);
   
-  double overOrder = (order == 0 ? 1. : 1. / order);
   int index = 0;
   fullMatrix<double> triPoints = gmshGeneratePointsTriangle(order,false);
   fullMatrix<double> linePoints = generate1DPoints(order);
-//   printf("nb: %d nT: %d %d nL: %d %d\n",nbPoints,triPoints.size1(),(order+1)*(order+2)/2,linePoints.size1(),order+1);
-  for (int j = 0; j < linePoints.size1(); j++) {
-    for (int i = 0; i < triPoints.size1(); i++) {
-      point(index,0) = triPoints(i,0);
-      point(index,1) = triPoints(i,1);
-      point(index,2) = linePoints(j,0);
-      index ++;
-//       printf("%d: %f %f %f\n",index,triPoints(i,0),triPoints(i,1),linePoints(j,0));
+
+  if (order == 2)
+    for (int i =0; i<18; i++)
+      for (int j=0; j<3;j++)
+        point(i,j) = prism18Pts[i][j];
+  else    
+    for (int j = 0; j <linePoints.size1() ; j++) {
+      for (int i = 0; i < triPoints.size1(); i++) {
+        point(index,0) = triPoints(i,0);
+        point(index,1) = triPoints(i,1);
+        point(index,2) = linePoints(j,0);
+        index ++;
+      }
     }
-  }
-//   point.print();
+     
+//   point.print("Pri ipts");
 
-  point.scale(overOrder);  
   return point;
 }
 
@@ -798,26 +820,31 @@ static void generate3dFaceClosure(polynomialBasis::clCont &closure, int order)
 static void getFaceClosurePrism(int iFace, int iSign, int iRotate, std::vector<int> &closure,
                            int order)
 {
-  if (order > 1)
+  if (order > 2)
     Msg::Error("FaceClosure not implemented for prisms of order %d",order);
   bool isTriangle = iFace<2;
   int nNodes = isTriangle ? (order+1)*(order+2)/2 : (order+1)*(order+1);
   closure.clear();
   closure.resize(nNodes);
-  switch (order){
-  case 0:
+  if (order==0) {
     closure[0] = 0;
-    break;
-  default:
-//     int face[4][3] = {{-3, -2, -1}, {1, -6, 4}, {-4, 5, 3}, {6, 2, -5}};
-    int order1node[5][4] = {{0, 2, 1, -1}, {3, 4, 5, -1}, {0, 1, 4, 3}, {0, 3, 5, 2}, {1, 2, 5, 4}};
-    int nVertex = isTriangle ? 3 : 4;
+    return;
+  }
+  int order1node[5][4] = {{0, 2, 1, -1}, {3, 4, 5, -1}, {0, 1, 4, 3}, {0, 3, 5, 2}, {1, 2, 5, 4}};
+  int order2node[5][5] = {{7, 9, 6, -1, -1}, {12, 14, 13, -1, -1}, {6, 10, 12, 8, 15}, {8, 13, 11, 7, 16}, {9, 11, 14, 10, 17}};
+//   int order2node[5][4] = {{7, 9, 6, -1}, {12, 14, 13, -1}, {6, 10, 12, 8}, {8, 13, 11, 7}, {9, 11, 14, 10}};
+  int nVertex = isTriangle ? 3 : 4;
+  for (int i = 0; i < nVertex; ++i){
+    int k = (nVertex + (iSign * i) + iRotate) % nVertex;  //- iSign * iRotate
+    closure[i] = order1node[iFace][k];
+  }
+  if (order==2) {
     for (int i = 0; i < nVertex; ++i){
-      int k;
-        k = (nVertex + (iSign * i) + iRotate) % nVertex;  //- iSign * iRotate
-      closure[i] = order1node[iFace][k];
+      int k = (nVertex + (iSign==-1?-1:0) + (iSign * i) + iRotate) % nVertex;  //- iSign * iRotate
+      closure[nVertex+i] = order2node[iFace][k];
     }
-    break;
+    if (!isTriangle)
+      closure[nNodes-1] = order2node[iFace][4]; // center
   }
 }
 
@@ -828,11 +855,9 @@ static void generate3dFaceClosurePrism(polynomialBasis::clCont &closure, int ord
   for (int iRotate = 0; iRotate < 4; iRotate++){
     for (int iSign = 1; iSign >= -1; iSign -= 2){
       for (int iFace = 0; iFace < 5; iFace++){
-    std::vector<int> closure_face;
-    getFaceClosurePrism(iFace, iSign, iRotate, closure_face, order); 
-    closure.push_back(closure_face);
-//       for(int i=0;i < closure_face.size(); i++) { printf("%d ",closure_face.at(i)); }
-//       printf("\n");
+        std::vector<int> closure_face;
+        getFaceClosurePrism(iFace, iSign, iRotate, closure_face, order); 
+        closure.push_back(closure_face);
       }
     }
   }
@@ -1075,6 +1100,14 @@ const polynomialBasis &polynomialBases::find(int tag)
     break;
   }  
   F.coefficients = generateLagrangeMonomialCoefficients(F.monomials, F.points);
+//   printf("Case: %d coeffs:\n",tag);
+//   for (int i = 0; i<F.coefficients.size1(); i++) {
+//     for (int j = 0; j<F.coefficients.size2(); j++) {
+//       printf("%4.1f ",F.coefficients(i,j));
+//     }
+//     printf("\n");
+//   }
+    
   fs.insert(std::make_pair(tag, F));
   return fs[tag];
 }
diff --git a/Solver/TESTCASES/Diffusion3D.lua b/Solver/TESTCASES/Diffusion3D.lua
index d53fb73abb..ac7550ef65 100644
--- a/Solver/TESTCASES/Diffusion3D.lua
+++ b/Solver/TESTCASES/Diffusion3D.lua
@@ -6,7 +6,7 @@ model = GModel()
 model:load('mixed.geo')
 model:load('mixed.msh')
 dg = dgSystemOfEquations(model)
-dg:setOrder(1)
+dg:setOrder(2)
 
 -- initial condition
 function initial_condition( xyz , f )
@@ -37,17 +37,6 @@ dg:setConservationLaw(law)
 -- boundary condition
 outside=fullMatrix(1,1)
 outside:set(0,0,0.15)
--- freestream=law:newOutsideValueBoundary(functionLua(1,'initial_condition',{'XYZ'}):getName())
-
--- law:addBoundaryCondition('wall',law:new0FluxBoundary())
--- law:addBoundaryCondition('inlet',freestream)
--- law:addBoundaryCondition('outlet',law:newSymmetryBoundary())
--- law:addBoundaryCondition('symmetry',law:newSymmetryBoundary())
-
--- law:addBoundaryCondition('wall',law:new0FluxBoundary())
--- law:addBoundaryCondition('inlet',law:new0FluxBoundary())
--- law:addBoundaryCondition('outlet',law:new0FluxBoundary())
--- law:addBoundaryCondition('symmetry',law:new0FluxBoundary())
 
 law:addBoundaryCondition('side1',law:new0FluxBoundary())
 law:addBoundaryCondition('side2',law:new0FluxBoundary())
@@ -60,10 +49,10 @@ dg:setup()
 
 dg:L2Projection(functionLua(1,'initial_condition',{'XYZ'}):getName())
 
-dt = 0.4
+dt = 0.0001
 --CFL = 20 -- good for lc=0.1 mesh
-CFL = 10
-dt = CFL*dg:computeInvSpectralRadius()
+CFL = 1
+-- dt = CFL*dg:computeInvSpectralRadius()
 -- export_interval = 5*dt
 export_interval = 0.05
 end_time = 3
@@ -78,11 +67,13 @@ export_count = 0
 io.write(string.format('Export: %d iter: %4d t: %.6f n: %.8f dt:%.8f\n',export_count,0,0,0,dt))
 dg:exportSolution(output_pattern .. string.format("%05d",export_count))
 for i=1,10000 do
-  dt = CFL*dg:computeInvSpectralRadius()
+--   dt = CFL*dg:computeInvSpectralRadius()
   norm = dg:RK44(dt)
   time = i*dt
   io.write('.')
   io.flush()
+--     io.write('\n')
+--     io.write(string.format('Export: %d iter: %4d t: %.6f n: %.8f dt:%.8f\n',export_count,i,time,norm,dt))
   if (time >= next_export_time) then
     export_count = export_count +1
     io.write('\n')
diff --git a/Solver/TESTCASES/mixed.geo b/Solver/TESTCASES/mixed.geo
index f5c0427daf..c129eea5fb 100644
--- a/Solver/TESTCASES/mixed.geo
+++ b/Solver/TESTCASES/mixed.geo
@@ -2,7 +2,7 @@
 C = 1;
 Lup = 1;
 L = 1.;
-lc = .3;
+lc = 0.3;
 
 Point(1) = {0.0, 0.0, -Lup, lc};
 Point(2) = {C  , 0.0, -Lup, lc};
@@ -23,7 +23,7 @@ outtet[] = Extrude {0,0,0.7*L} { Surface{6};};
 // Printf("volume = %g", outtet[1]);
 // Printf("side surfaces = %g %g %g %g", outtet[2], outtet[3], outtet[4], outtet[5]);
 
-outpri[]= Extrude {0,0,0.5*L}{ Surface{outtet[0]}; Layers{4};Recombine;};
+outpri[]= Extrude {0,0,0.5*L}{ Surface{outtet[0]}; Layers{Ceil(0.5*L/lc)};Recombine;};
 // outv[]= Extrude {0,0,0.5*L}{ Surface{7}; Layers{5};Recombine;};
 // Printf("top surface = %g", outpri[0]);
 // Printf("volume = %g", outpri[1]);
@@ -32,7 +32,7 @@ outpri[]= Extrude {0,0,0.5*L}{ Surface{outtet[0]}; Layers{4};Recombine;};
 Mesh.Algorithm3D=4; // frontal [lobes]
 
 Physical Surface("top") = {outpri[0]};
-Physical Surface("bottom") = {5};
+Physical Surface("bottom") = {6};
 Physical Surface("side1") = {outpri[2],outtet[2]};
 Physical Surface("side2") = {outpri[3],outtet[3]};
 Physical Surface("side3") = {outpri[4],outtet[4]};
diff --git a/Solver/dgDofContainer.cpp b/Solver/dgDofContainer.cpp
index 271b347ad6..b976dd25f3 100644
--- a/Solver/dgDofContainer.cpp
+++ b/Solver/dgDofContainer.cpp
@@ -304,6 +304,10 @@ void dgDofContainer::exportMsh(const std::string name)
     if(Msg::GetCommSize()>1)
       name_oss<<"_"<<Msg::GetCommRank();
     FILE *f = fopen (name_oss.str().c_str(),"w");
+    if(!f){
+      Msg::Error("Unable to open export file '%s'", name.c_str());
+    }
+
     int COUNT = 0;
     for (int i=0;i < _groups.getNbElementGroups() ;i++){
       COUNT += _groups.getElementGroup(i)->getNbElements();
-- 
GitLab