From eed986f556c08cfe5b2267c5783a5151fb4471c7 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 21 Jul 2010 09:59:54 +0000
Subject: [PATCH]

---
 Numeric/cartesian.h               | 118 +++++++++++++++---------------
 doc/CREDITS.txt                   |   2 +-
 utils/api_demos/mainCartesian.cpp |  83 +++++++++++----------
 3 files changed, 102 insertions(+), 101 deletions(-)

diff --git a/Numeric/cartesian.h b/Numeric/cartesian.h
index bd6f0d238e..68b82937b7 100644
--- a/Numeric/cartesian.h
+++ b/Numeric/cartesian.h
@@ -8,50 +8,57 @@
 #include "SVector3.h"
 #include "SPoint3.h"
 
-// This is a cartesian mesh that encompasses an oriented box with NXI
-// * NETA * NZETA hexaderal cells, with values stored at vertices
-
-/*
-  2-D example:
-
-               j
-   +---+---+---+---+---+---+
-   |   |   |   |ij |   |   |
- i +---+---+---+---+---+---+
-   |   |   |   |   |   |   |
-   +---+---+---+---+---+---+
-
-   Nodal values/active cells are stored and referenced by node/cell
-   index, i.e., i+N*j
-
-   The ij cell has nodes i;j , i+1;j , i+1;j+1, i;j+1
-*/
-
+// A cartesian grid that encompasses an oriented 3-D box, with values
+// stored at vertices:
+//
+//               j
+//   +---+---+---+---+---+---+
+//   |   |   |   |   |   |   |
+// i +---+---+-(i,j)-+---+---+
+//   |   |   |   |   |   |   |
+//   +---+---+---+---+---+---+
+//
+//   Nodal values and active hexahedral cells are stored and
+//   referenced by a linear index (i + N * j)
+//   
+//   The (i,j) cell has nodes (i,j), (i+1,j), (i+1,j+1) and (i,j+1)
 template <class scalar>
 class cartesianBox {
  private:  
+  // number of subdivisions along the xi-, eta- and zeta-axis
   int _Nxi, _Neta, _Nzeta;  
+  // origin of the grid and spacing along xi, eta and zeta
   double _X, _Y, _Z, _dxi, _deta, _dzeta;
+  // xi-, eta- and zeta-axis directions
   SVector3 _xiAxis, _etaAxis, _zetaAxis;
+  // set of active cells; the value stored for cell (i,j,k) is the
+  // linear index (i + _Nxi * j + _Nxi *_Neta * k)
   std::set<int> _activeCells;
+  // map of stored nodal values, index by the linear index
+  // (i + (_Nxi+1) * j + (_Nxi+1) * (_Neta+1) * k)
   typename std::map<int, scalar> _nodalValues;
+  // mapping from linear node index to unique node tags
+  std::map<int, int> _nodeTags;
+  // level of the box (coarset box has highest level; finest box has
+  // level==1)
   int _level;
+  // pointer to a finer (refined by 2) level box (if any)
   cartesianBox<scalar> *_childBox;
  public:
   cartesianBox(double X, double Y, double Z, 
-               const SVector3 &DXI, const SVector3 &DETA, const SVector3 &DZETA, 
-               int NXI, int NETA, int NZETA, int level=1)
+               const SVector3 &dxi, const SVector3 &deta, const SVector3 &dzeta, 
+               int Nxi, int Neta, int Nzeta, int level=1)
     : _X(X), _Y(Y), _Z(Z), 
-      _dxi(norm(DXI)), _deta(norm(DETA)), _dzeta(norm(DZETA)), 
-      _xiAxis(DXI), _etaAxis(DETA), _zetaAxis(DZETA),
-      _Nxi(NXI), _Neta(NETA), _Nzeta(NZETA), _level(level), _childBox(0)
+      _dxi(norm(dxi)), _deta(norm(deta)), _dzeta(norm(dzeta)), 
+      _xiAxis(dxi), _etaAxis(deta), _zetaAxis(dzeta),
+      _Nxi(Nxi), _Neta(Neta), _Nzeta(Nzeta), _level(level), _childBox(0)
   {
     _xiAxis.normalize();
     _etaAxis.normalize();
     _zetaAxis.normalize();
     if(level > 1)
-      _childBox = new cartesianBox<scalar>(X, Y, Z, DXI, DETA, DZETA,
-                                           2 * NXI, 2 * NETA, 2 * NZETA,
+      _childBox = new cartesianBox<scalar>(X, Y, Z, dxi, deta, dzeta,
+                                           2 * Nxi, 2 * Neta, 2 * Nzeta,
                                            level - 1);
   }  
   int getNxi(){ return _Nxi; }
@@ -66,38 +73,25 @@ class cartesianBox {
   valIter nodalValuesBegin(){ return _nodalValues.begin(); }
   valIter nodalValuesEnd(){ return _nodalValues.end(); }
   void setNodalValue(int i, scalar s){ _nodalValues[i] = s; }
-  void getNodalValues(const int &t, std::vector<scalar> &ls_values)
+  void getCellValues(int t, std::vector<scalar> &values)
   {
-    // perhaps not optimal (lot of searches...)
     int i, j, k;
     getCellIJK(t, i, j, k);
-    typename std::map<int, scalar>::iterator itNode;
-
-    itNode = _nodalValues.find(getNodeIndex(i, j, k));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i+1,j,k));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i+1,j+1,k));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i,j+1,k));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i,j,k+1));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i+1,j,k+1));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i+1,j+1,k+1));
-    ls_values.push_back(itNode->second);
-
-    itNode = _nodalValues.find(getNodeIndex(i,j+1,k+1));
-    ls_values.push_back(itNode->second);
+    for(int I = 0; I < 2; I++)
+      for(int J = 0; J < 2; J++)
+        for(int K = 0; K < 2; K++){
+          typename std::map<int, scalar>::iterator it = 
+            _nodalValues.find(getNodeIndex(i + I, j + J, k + K));
+          if(it != _nodalValues.end())
+            values.push_back(it->second);
+          else{
+            Msg::Error("Could not find value i,j,k=%d,%d,%d for cell %d\n", 
+                       i + I, j + J, k + K, t);
+            values.push_back(0.);
+          }
+        }
   }
-  inline int getCellContainingPoint(double x, double y, double z) const
+  int getCellContainingPoint(double x, double y, double z) const
   {
     // P = P_0 + xi * _vdx + eta * _vdy + zeta *vdz
     // DP = P-P_0 * _vdx = xi
@@ -113,7 +107,7 @@ class cartesianBox {
     if (k < 0) k = 0; if (k >= _Nzeta) k = _Nzeta - 1;
     return getCellIndex(i, j, k);
   }
-  inline SPoint3 getNodeCoordinates(const int &t) const
+  SPoint3 getNodeCoordinates(const int &t) const
   {
     int i, j, k;
     getNodeIJK(t, i, j, k);
@@ -130,27 +124,27 @@ class cartesianBox {
   {
     return (_activeCells.find(t) != _activeCells.end()); 
   }
-  inline int getCellIndex(int i, int j, int k) const 
+  int getCellIndex(int i, int j, int k) const 
   {
     return i + _Nxi * j + _Nxi *_Neta * k;
   }
-  inline int getNodeIndex(int i, int j, int k) const 
+  int getNodeIndex(int i, int j, int k) const 
   {
     return i + (_Nxi+1) * j + (_Nxi+1) * (_Neta+1) * k;
   }
-  inline void getCellIJK(int index, int &i, int &j, int &k) const 
+  void getCellIJK(int index, int &i, int &j, int &k) const 
   {
     k = index / (_Nxi * _Neta);
     j = (index - k * (_Nxi * _Neta)) / _Nxi;
     i = (index - k * (_Nxi * _Neta) - j * _Nxi);
   }
-  inline void getNodeIJK(int index, int &i, int &j, int &k) const
+  void getNodeIJK(int index, int &i, int &j, int &k) const
   {
     k = index / ((_Nxi + 1) * (_Neta + 1));
     j = (index - k * ((_Nxi + 1) * (_Neta + 1))) / (_Nxi + 1);
     i = (index - k * ((_Nxi + 1) * (_Neta + 1)) - j * (_Nxi + 1));
   }
-  inline void createNodalValues()
+  void createNodalValues()
   {
     std::set<int>::const_iterator it = _activeCells.begin();
     for( ; it != _activeCells.end() ; ++it){
@@ -168,6 +162,10 @@ class cartesianBox {
                 bool writeNodalValues=true) const
   {
     FILE *f = fopen(filename.c_str(), "w");
+    if(!f){
+      Msg::Error("Could not open file '%s'", filename.c_str());
+      return;
+    }
     fprintf(f, "$MeshFormat\n2.1 0 8\n$EndMeshFormat\n");
     {
       fprintf(f, "$Nodes\n%d\n", (int)_nodalValues.size());
diff --git a/doc/CREDITS.txt b/doc/CREDITS.txt
index 3d30a59d72..41e60ebb27 100644
--- a/doc/CREDITS.txt
+++ b/doc/CREDITS.txt
@@ -1,4 +1,4 @@
-             Gmsh is copyright (C) 1997-2009
+             Gmsh is copyright (C) 1997-2010
 
                    Christophe Geuzaine
                  <cgeuzaine at ulg.ac.be>
diff --git a/utils/api_demos/mainCartesian.cpp b/utils/api_demos/mainCartesian.cpp
index 052ce22e35..386fa294fe 100644
--- a/utils/api_demos/mainCartesian.cpp
+++ b/utils/api_demos/mainCartesian.cpp
@@ -77,8 +77,7 @@ void fillPointCloud(GEdge *ge, double sampling, std::vector<SPoint3> &points)
   for(int i = 0; i < N; i++) {
     double t = t_min + (double)i / (double)(N - 1) * (t_max - t_min);
     GPoint p = ge->point(t);
-    double x = p.x(), y = p.y(), z = p.z();
-    points.push_back(SPoint3(x, y, z));
+    points.push_back(SPoint3(p.x(), p.y(), p.z()));
   }
 }
 
@@ -143,10 +142,32 @@ void removeParentCellsWithChildren(cartesianBox<double> *box)
   removeParentCellsWithChildren(box->getChildBox());
 }
 
+void removeOutsideCells(cartesianBox<double> *box)
+{
+  if(!box) return;
+  int nbErased = 0;
+  for(cartesianBox<double>::cellIter it = box->activeCellsBegin(); 
+      it != box->activeCellsEnd();){
+    std::vector<double> vals;
+    box->getCellValues(*it, vals);
+    double lsmax = *std::max_element(vals.begin(), vals.end());
+    double lsmin = *std::min_element(vals.begin(), vals.end());
+    double change_sign = lsmax * lsmin;
+    double epsilon = 1.e-10;
+    if(change_sign > 0 && lsmax < -epsilon) { 
+      box->eraseActiveCell(*(it++));
+      nbErased++;
+    }
+    else ++it;
+  }
+  Msg::Info("  number of cells erased after filtering: %d", nbErased);
+  removeOutsideCells(box->getChildBox());
+}
+
 int main(int argc,char *argv[])
 {
   if(argc < 6){
-    printf("Usage: %s file lx ly lz rmax [levels=1] [filter]\n", argv[0]);
+    printf("Usage: %s file lx ly lz rmax [levels=1]\n", argv[0]);
     printf("where\n");
     printf("  'file' contains a CAD model\n");
     printf("  'lx', 'ly' and 'lz' are the sizes of the elements along the"
@@ -154,8 +175,6 @@ int main(int argc,char *argv[])
     printf("  'rmax' is the radius of the largest sphere that can be inscribed"
            " in the structure\n");
     printf("  'levels' sets the number of levels in the grid\n");
-    printf("  'filter' selects if only cells inside the body are saved in the"
-           " mesh\n");
     return -1;
   }
 
@@ -165,10 +184,9 @@ int main(int argc,char *argv[])
   double lx = atof(argv[2]), ly = atof(argv[3]), lz = atof(argv[4]);
   double rmax = atof(argv[5]);
   int levels = (argc > 6) ? atof(argv[6]) : 1;
-  int filter = (argc > 7) ? atoi(argv[7]) : 0;
 
   // minimum distance between points in the cloud at the coarsest level
-  double sampling = std::min(lx, std::min(ly, lz)) / 2.;
+  double sampling = std::min(rmax, std::min(lx, std::min(ly, lz))) / 2.;
 
   // radius of the "tube" created around edges at the coarsest level
   double rtube = std::max(lx, std::max(ly, lz)) * 2.;
@@ -176,17 +194,17 @@ int main(int argc,char *argv[])
   GModel *gm = GModel::current();
   
   std::vector<SPoint3> points;
-  Msg::Info("Filling point clould on surfaces");
+  Msg::Info("Filling point cloud on surfaces");
   for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
     (*fit)->fillPointCloud(sampling, &points);
   Msg::Info("  %d points in the surface cloud", (int)points.size());
 
   std::vector<SPoint3> edgePoints;
   if(levels > 1){
-    Msg::Info("Filling point clould on curves");
+    Msg::Info("Filling point cloud on curves");
     for (GModel::eiter eit = gm->firstEdge(); eit != gm->lastEdge(); eit++)
       fillPointCloud(*eit, sampling / pow(2., levels - 1), edgePoints);
-    Msg::Info("  %d points in the curvee cloud", (int)edgePoints.size());
+    Msg::Info("  %d points in the curve cloud", (int)edgePoints.size());
   }
 
   SBoundingBox3d bb;
@@ -201,10 +219,11 @@ int main(int argc,char *argv[])
   if(NY < 2) NY = 2;
   if(NZ < 2) NZ = 2;
 
-  Msg::Info("  bb Min= %g %g %g -- bb Max= %g %g %g -- NX %d NY %d NZ %d",
+  Msg::Info("  bounding box min: %g %g %g -- max: %g %g %g",
             bb.min().x(), bb.min().y(), bb.min().z(),
-            bb.max().x(), bb.max().y(), bb.max().z(), NX, NY, NZ);
-
+            bb.max().x(), bb.max().y(), bb.max().z());
+  Msg::Info("  Nx=%d Ny=%d Nz=%d", NX, NY, NZ);
+  
   cartesianBox<double> box(bb.min().x(), bb.min().y(), bb.min().z(), 
                            SVector3(range.x(), 0, 0),
                            SVector3(0, range.y(), 0),
@@ -222,43 +241,27 @@ int main(int argc,char *argv[])
     parent = child;
   }
 
-  Msg::Info("Removing cells to match X-FEM mesh topology constraints");
   // remove child cells that do not entirely fill parent cell or for
-  // which there is no parent neighbor
+  // which there is no parent neighbor; then remove parent cells that
+  // have children
+  Msg::Info("Removing cells to match X-FEM mesh topology constraints");
   removeOrphanChildCells(&box);
-  // remove parent cells that have children
   removeParentCellsWithChildren(&box);
 
-  // TODO: 
-  //  * remove child nodes which exist in parent grid
-  //  * offset of node numbers depending on box level to write a single mesh
-
+  // we generate duplicate nodes at this point so we can easily access
+  // cell values at each level; we will clean up by renumbering after
+  // filtering
   Msg::Info("Initializing nodal values in the cartesian grid");
   box.createNodalValues();
 
   Msg::Info("Computing levelset on the cartesian grid");  
   computeLevelset(gm, box);
 
-  if(filter){
-    Msg::Info("Filtering result -- *** TODO THIS NEEDS TO BE ADAPTED FOR MULTILEVEL");
-    int nbErased = 0;
-    //Coup de menage avant d'exporter le maillage
-    for(cartesianBox<double>::cellIter it = box.activeCellsBegin(); 
-        it != box.activeCellsEnd();){
-      std::vector<double> ls_vals;
-      box.getNodalValues(*it, ls_vals);
-      double lsmax = *std::max_element(ls_vals.begin(), ls_vals.end());
-      double lsmin = *std::min_element(ls_vals.begin(), ls_vals.end());
-      double change_sign = lsmax * lsmin ;
-      double epsilon = 1.e-10;
-      if(change_sign > 0 && lsmax < -epsilon) { 
-        box.eraseActiveCell(*(it++));
-        nbErased++;
-      }
-      else ++it;
-    }
-    Msg::Info("  number of erased cells after filtering: %d", nbErased);
-  }
+  Msg::Info("Removing cells outside the structure");
+  removeOutsideCells(&box);
+
+  Msg::Info("Renumbering mesh vertices across levels");
+  
   
   Msg::Info("Writing results to disk");
   box.writeMSH("yeah.msh");
-- 
GitLab