From c851335b29239c32bfb8dd9877a36a9f091f61c2 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Fri, 27 Jan 2012 09:07:38 +0000
Subject: [PATCH] new Frustum field

---
 Mesh/Field.cpp | 213 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 155 insertions(+), 58 deletions(-)

diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp
index 4b6d6f30cb..a60cf2d1aa 100644
--- a/Mesh/Field.cpp
+++ b/Mesh/Field.cpp
@@ -35,13 +35,14 @@
 #include "ANN/ANN.h"
 #endif
 
-Field::~Field() {
-  for(std::map<std::string, FieldOption*>::iterator it = options.begin(); it != options.end(); ++it) {
+Field::~Field()
+{
+  for(std::map<std::string, FieldOption*>::iterator it = options.begin();
+      it != options.end(); ++it)
     delete it->second;
-  }
-  for(std::map<std::string, FieldCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); ++it) {
+  for(std::map<std::string, FieldCallback*>::iterator it = callbacks.begin();
+      it != callbacks.end(); ++it)
     delete it->second;
-  }
 }
 
 void FieldManager::reset()
@@ -127,7 +128,7 @@ class StructuredField : public Field
     text_format = false;
     options["TextFormat"] = new FieldOptionBool
       (text_format, "True for ASCII input files, false for binary files (4 bite "
-       "signed integers for n, double precision floating points for v, D and O)", 
+       "signed integers for n, double precision floating points for v, D and O)",
        &update_needed);
     data = 0;
   }
@@ -331,7 +332,7 @@ class LonLatField : public Field
       (iField, "Index of the field to evaluate.");
     fromStereo = 0;
     stereoRadius = 6371e3;
-    
+
     options["FromStereo"] = new FieldOptionInt
       (fromStereo, "if = 1, the mesh is in stereographic coordinates. "
        "xi = 2Rx/(R+z),  eta = 2Ry/(R+z)");
@@ -388,14 +389,14 @@ class BoxField : public Field
     options["ZMin"] = new FieldOptionDouble
       (z_min, "Minimum Z coordinate of the box");
     options["ZMax"] = new FieldOptionDouble
-      (z_max, "Maximum Z coordinate of the box");    
+      (z_max, "Maximum Z coordinate of the box");
   }
   const char *getName()
   {
     return "Box";
   }
   double operator() (double x, double y, double z, GEntity *ge=0)
-  {    
+  {
     return (x <= x_max && x >= x_min && y <= y_max && y >= y_min && z <= z_max
             && z >= z_min) ? v_in : v_out;
   }
@@ -407,7 +408,7 @@ class CylinderField : public Field
   double xc,yc,zc;
   double xa,ya,za;
   double R;
-  
+
  public:
   std::string getDescription()
   {
@@ -421,7 +422,7 @@ class CylinderField : public Field
   {
     v_in = v_out = xc = yc = zc = xa = ya = R = 0;
     za = 1.;
-    
+
     options["VIn"] = new FieldOptionDouble
       (v_in, "Value inside the cylinder");
     options["VOut"] = new FieldOptionDouble
@@ -434,7 +435,7 @@ class CylinderField : public Field
     options["ZCenter"] = new FieldOptionDouble
       (zc, "Z coordinate of the cylinder center");
 
-    
+
     options["XAxis"] = new FieldOptionDouble
       (xa, "X component of the cylinder axis");
     options["YAxis"] = new FieldOptionDouble
@@ -443,29 +444,124 @@ class CylinderField : public Field
       (za, "Z component of the cylinder axis");
 
     options["Radius"] = new FieldOptionDouble
-      (R,"Radius");    
-    
+      (R,"Radius");
+
   }
   const char *getName()
   {
     return "Cylinder";
   }
   double operator() (double x, double y, double z, GEntity *ge=0)
-  {    
+  {
     double dx = x-xc;
     double dy = y-yc;
     double dz = z-zc;
-    
+
     double adx = (xa * dx + ya * dy + za * dz)/(xa*xa + ya*ya + za*za);
-    
+
     dx -= adx * xa;
     dy -= adx * ya;
     dz -= adx * za;
-    
+
     return ((dx*dx + dy*dy + dz*dz < R*R) && fabs(adx) < 1) ? v_in : v_out;
   }
 };
 
+class FrustumField : public Field
+{
+  double x1,y1,z1;
+  double x2,y2,z2;
+  double r1i,r1o,r2i,r2o;
+  double v1i,v1o,v2i,v2o;
+
+ public:
+  std::string getDescription()
+  {
+    return "This field is an extended cylinder with inner (i) and outer (o) radiuses"
+      "on both endpoints (1 and 2). Length scale is bilinearly interpolated between"
+      "these locations (inner and outer radiuses, endpoints 1 and 2)"
+      "The field values for a point P are given by :"
+      "  u = P1P.P1P2/||P1P2|| "
+      "  r = || P1P - u*P1P2 || "
+      "  Ri = (1-u)*R1i + u*R2i "
+      "  Ro = (1-u)*R1o + u*R2o "
+      "  v = (r-Ri)/(Ro-Ri)"
+      "  lc = (1-v)*( (1-u)*v1i + u*v2i ) + v*( (1-u)*v1o + u*v2o )"
+      "    where (u,v) in [0,1]x[0,1]";
+  }
+  FrustumField()
+  {
+    x1 = y1 = z1 = 0.;
+    x2 = y2 = 0.;
+    z1 = 1.;
+    r1i = r2i = 0.;
+    r1o = r2o = 1.;
+    v1i = v2i = 0.1;
+    v1o = v2o = 1.;
+
+    options["X1"] = new FieldOptionDouble
+      (x1, "X coordinate of endpoint 1");
+    options["Y1"] = new FieldOptionDouble
+      (y1, "Y coordinate of endpoint 1");
+    options["Z1"] = new FieldOptionDouble
+      (z1, "Z coordinate of endpoint 1");
+    options["X2"] = new FieldOptionDouble
+      (x2, "X coordinate of endpoint 2");
+    options["Y2"] = new FieldOptionDouble
+      (y2, "Y coordinate of endpoint 2");
+    options["Z2"] = new FieldOptionDouble
+      (z2, "Z coordinate of endpoint 2");
+
+    options["R1_inner"] = new FieldOptionDouble
+      (r1i, "Inner radius of Frustum at endpoint 1");
+    options["R1_outer"] = new FieldOptionDouble
+      (r1o, "Outer radius of Frustum at endpoint 1");
+    options["R2_inner"] = new FieldOptionDouble
+      (r2i, "Inner radius of Frustum at endpoint 2");
+    options["R2_outer"] = new FieldOptionDouble
+      (r2o, "Outer radius of Frustum at endpoint 2");
+
+    options["V1_inner"] = new FieldOptionDouble
+      (v1i, "Element size at point 1, inner radius");
+    options["V1_outer"] = new FieldOptionDouble
+      (v1o, "Element size at point 1, outer radius");
+    options["V2_inner"] = new FieldOptionDouble
+      (v2i, "Element size at point 2, inner radius");
+    options["V2_outer"] = new FieldOptionDouble
+      (v2o, "Element size at point 2, outer radius");
+
+  }
+  const char *getName()
+  {
+    return "Frustum";
+  }
+  double operator() (double x, double y, double z, GEntity *ge=0)
+  {
+    double dx = x-x1;
+    double dy = y-y1;
+    double dz = z-z1;
+    double x12 = x2-x1;
+    double y12 = y2-y1;
+    double z12 = z2-z1;
+    double l12 = sqrt( x12*x12 + y12*y12 + z12*z12 );
+
+    double l = (dx*x12 + dy*y12 + dz*z12)/l12 ;
+    double r = sqrt( dx*dx+dy*dy+dz*dz - l*l );
+
+    double u = l/l12 ;  // u varies between 0 (P1) and 1 (P2)
+    double ri = (1-u)*r1i + u*r2i ;
+    double ro = (1-u)*r1o + u*r2o ;
+    double v = (r-ri)/(ro-ri) ;  // v varies between 0 (inner) and 1 (outer)
+
+    double lc = MAX_LC ;
+    if( u>=0 && u<=1 && v>=0 && v<=1 ){
+      lc = (1-v)*( (1-u)*v1i + u*v2i ) + v*( (1-u)*v1o + u*v2o );
+    }
+    return lc;
+
+  }
+};
+
 class ThresholdField : public Field
 {
  protected :
@@ -636,7 +732,7 @@ class CurvatureField : public Field
     grad_norm(*field, x, y - delta / 2, z, grad[3]);
     grad_norm(*field, x, y, z + delta / 2, grad[4]);
     grad_norm(*field, x, y, z - delta / 2, grad[5]);
-    return (grad[0][0] - grad[1][0] + grad[2][1] - 
+    return (grad[0][0] - grad[1][0] + grad[2][1] -
             grad[3][1] + grad[4][2] - grad[5][2]) / delta;
   }
 };
@@ -791,8 +887,8 @@ class MathEvalExpression
     }
     std::vector<std::string> expressions(1), variables(3 + _fields.size());
     expressions[0] = f;
-    variables[0] = "x"; 
-    variables[1] = "y"; 
+    variables[0] = "x";
+    variables[1] = "y";
     variables[2] = "z";
     i = 3;
     for(std::set<int>::iterator it = _fields.begin(); it != _fields.end(); it++){
@@ -821,7 +917,7 @@ class MathEvalExpression
       Field *field = GModel::current()->getFields()->get(*it);
       values[i++] = field ? (*field)(x, y, z) : MAX_LC;
     }
-    if(_f->eval(values, res)) 
+    if(_f->eval(values, res))
       return res[0];
     else
       return MAX_LC;
@@ -836,10 +932,10 @@ class MathEvalExpressionAniso
  public:
   MathEvalExpressionAniso()
   {
-    for(int i = 0; i < 6; i++) _f[i] = 0; 
+    for(int i = 0; i < 6; i++) _f[i] = 0;
   }
   ~MathEvalExpressionAniso()
-  { 
+  {
     for(int i = 0; i < 6; i++) if(_f[i]) delete _f[i];
   }
   bool set_function(int iFunction, const std::string &f)
@@ -861,11 +957,11 @@ class MathEvalExpressionAniso
     }
     std::vector<std::string> expressions(1), variables(3 + _fields[iFunction].size());
     expressions[0] = f;
-    variables[0] = "x"; 
-    variables[1] = "y"; 
+    variables[0] = "x";
+    variables[1] = "y";
     variables[2] = "z";
     i = 3;
-    for(std::set<int>::iterator it = _fields[iFunction].begin(); 
+    for(std::set<int>::iterator it = _fields[iFunction].begin();
         it != _fields[iFunction].end(); it++){
       std::ostringstream sstream;
       sstream << "F" << *it;
@@ -892,20 +988,20 @@ class MathEvalExpressionAniso
 	values[1] = y;
 	values[2] = z;
 	int i = 3;
-	for(std::set<int>::iterator it = _fields[iFunction].begin(); 
+	for(std::set<int>::iterator it = _fields[iFunction].begin();
             it != _fields[iFunction].end(); it++){
 	  Field *field = GModel::current()->getFields()->get(*it);
 	  values[i++] = field ? (*field)(x, y, z) : MAX_LC;
 	}
-	if(_f[iFunction]->eval(values, res)) 
+	if(_f[iFunction]->eval(values, res))
 	  metr(index[iFunction][0],index[iFunction][1]) =  res[0];
 	else
 	  metr(index[iFunction][0],index[iFunction][1]) = MAX_LC;
       }
     }
   }
-};  
-  
+};
+
 class MathEvalField : public Field
 {
   MathEvalExpression expr;
@@ -1005,7 +1101,7 @@ class MathEvalFieldAniso : public Field
       }
       update_needed = false;
     }
-    SMetric3 metr; 
+    SMetric3 metr;
     expr.evaluate(x, y, z, metr);
     return metr(0, 0);
   }
@@ -1106,7 +1202,7 @@ class PostViewField : public Field
       return 0;
     }
   }
-  virtual bool isotropic () const 
+  virtual bool isotropic () const
   {
     PView *v = getView();
     if(v && v->getData()->getNumTensors()) return false;
@@ -1306,7 +1402,7 @@ class RestrictField : public Field
 
 #if defined(HAVE_ANN)
 struct AttractorInfo{
-  AttractorInfo (int a=0, int b=0, double c=0, double d=0) 
+  AttractorInfo (int a=0, int b=0, double c=0, double d=0)
     : ent(a),dim(b),u(c),v(d) {
   }
   int ent,dim;
@@ -1320,7 +1416,7 @@ class AttractorAnisoCurveField : public Field {
   ANNdistArray dist;
   std::list<int> edges_id;
   double dMin, dMax, lMinTangent, lMaxTangent, lMinNormal, lMaxNormal;
-  int n_nodes_by_edge;  
+  int n_nodes_by_edge;
   std::vector<SVector3> tg;
   public:
   AttractorAnisoCurveField() : kdtree(0), zeronodes(0)
@@ -1432,7 +1528,7 @@ class AttractorAnisoCurveField : public Field {
     double xyz[3] = { x, y, z };
     kdtree->annkSearch(xyz, 1, index, dist);
     double d = sqrt(dist[0]);
-    double lTg = d < dMin ? lMinTangent : d > dMax ? lMaxTangent : 
+    double lTg = d < dMin ? lMinTangent : d > dMax ? lMaxTangent :
       lMinTangent + (lMaxTangent - lMinTangent) * (d - dMin) / (dMax - dMin);
     double lN = d < dMin ? lMinNormal : d > dMax ? lMaxNormal :
       lMinNormal + (lMaxNormal - lMinNormal) * (d - dMin) / (dMax - dMin);
@@ -1463,7 +1559,7 @@ class AttractorField : public Field
   std::vector<AttractorInfo> _infos;
   int _xFieldId, _yFieldId, _zFieldId;
   Field *_xField, *_yField, *_zField;
-  int n_nodes_by_edge;  
+  int n_nodes_by_edge;
  public:
   AttractorField(int dim, int tag, int nbe)
     : kdtree(0), zeronodes(0), n_nodes_by_edge(nbe)
@@ -1524,7 +1620,7 @@ class AttractorField : public Field
     cy = _yField ? (*_yField)(x, y, z, ge) : y;
     cz = _zField ? (*_zField)(x, y, z, ge) : z;
   }
-  std::pair<AttractorInfo,SPoint3> getAttractorInfo() const 
+  std::pair<AttractorInfo,SPoint3> getAttractorInfo() const
   {
     return std::make_pair(_infos[index[0]], SPoint3(zeronodes[index[0]][0],
                                                     zeronodes[index[0]][1],
@@ -1541,7 +1637,7 @@ class AttractorField : public Field
         annDeallocPts(zeronodes);
         delete kdtree;
       }
-      int totpoints = nodes_id.size() + (n_nodes_by_edge-2) * edges_id.size() + 
+      int totpoints = nodes_id.size() + (n_nodes_by_edge-2) * edges_id.size() +
         n_nodes_by_edge * n_nodes_by_edge * faces_id.size();
       if(totpoints){
         zeronodes = annAllocPts(totpoints, 3);
@@ -1568,7 +1664,7 @@ class AttractorField : public Field
       for(std::list<int>::iterator it = edges_id.begin();
           it != edges_id.end(); ++it) {
         Curve *c = FindCurve(*it);
-	GEdge *e = GModel::current()->getEdgeByTag(*it);	
+	GEdge *e = GModel::current()->getEdgeByTag(*it);
         if(c && !e) {
           for(int i = 1; i < n_nodes_by_edge -1 ; i++) {
             double u = (double)i / (n_nodes_by_edge - 1);
@@ -1622,7 +1718,7 @@ class AttractorField : public Field
                 double t1 = b1.low() + u * (b1.high() - b1.low());
                 double t2 = b2.low() + v * (b2.high() - b2.low());
                 GPoint gp = f->point(t1, t2);
-                getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0], 
+                getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0],
                          zeronodes[k][1], zeronodes[k][2], f);
 		_infos[k++] = AttractorInfo(*it,2,u,v);
               }
@@ -1655,8 +1751,8 @@ BoundaryLayerField::BoundaryLayerField()
   hwall_n = .1;
   hwall_t = .5;
   hfar = 1;
-  ratio = 1.1;    
-  thickness = 1.e-2;    
+  ratio = 1.1;
+  thickness = 1.e-2;
   options["NodesList"] = new FieldOptionList
     (nodes_id, "Indices of nodes in the geometric model", &update_needed);
   options["EdgesList"] = new FieldOptionList
@@ -1701,27 +1797,27 @@ double BoundaryLayerField::operator() (double x, double y, double z, GEntity *ge
 }
 
 void BoundaryLayerField::operator() (AttractorField *cc, double dist,
-                                     double x, double y, double z, 
+                                     double x, double y, double z,
                                      SMetric3 &metr, GEntity *ge)
 {
   // dist = hwall -> lc = hwall * ratio
   // dist = hwall (1+ratio) -> lc = hwall ratio ^ 2
   // dist = hwall (1+ratio+ratio^2) -> lc = hwall ratio ^ 3
-  // dist = hwall (1+ratio+ratio^2+...+ratio^{m-1}) = (ratio^{m} - 1)/(ratio-1) 
+  // dist = hwall (1+ratio+ratio^2+...+ratio^{m-1}) = (ratio^{m} - 1)/(ratio-1)
   // -> lc = hwall ratio ^ m
   // -> find m
   // dist/hwall = (ratio^{m} - 1)/(ratio-1)
   // (dist/hwall)*(ratio-1) + 1 = ratio^{m}
-  // lc =  dist*(ratio-1) + hwall 
+  // lc =  dist*(ratio-1) + hwall
 
   const double ll1   = dist*(ratio-1) + hwall_n;
   double lc_n  = std::min(ll1,hfar);
   const double ll2   = dist*(ratio-1) + hwall_t;
   double lc_t  = std::min(lc_n*CTX::instance()->mesh.anisoMax, std::min(ll2,hfar));
-  
+
   SVector3 t1,t2,t3;
   double L1,L2,L3;
-  
+
   std::pair<AttractorInfo,SPoint3> pp = cc->getAttractorInfo();
   if (pp.first.dim ==0){
     L1 = lc_n;
@@ -1747,7 +1843,7 @@ void BoundaryLayerField::operator() (AttractorField *cc, double dist,
   }
   else if (pp.first.dim ==1){
     GEdge *e = GModel::current()->getEdgeByTag(pp.first.ent);
-    
+
     // the tangent size at this point is the size of the
     // 1D mesh at this point !
     // hack : use curvature
@@ -1759,8 +1855,8 @@ void BoundaryLayerField::operator() (AttractorField *cc, double dist,
       double lc_tb  = std::min(lc_n*CTX::instance()->mesh.anisoMax, std::min(ll2b,hfar));
       lc_t = std::min(lc_t,lc_tb);
       }
-      */      
-    
+      */
+
     if (dist < hwall_t){
       L1 = lc_t;
       L2 = lc_n;
@@ -1793,12 +1889,12 @@ void BoundaryLayerField::operator() (AttractorField *cc, double dist,
       t2.normalize();
       t3 = crossprod(t1,t2);
       t3.normalize();
-      t1 = crossprod(t3,t2);	  
+      t1 = crossprod(t3,t2);
     }
   }
   else {
     GFace *gf = GModel::current()->getFaceByTag(pp.first.ent);
-    
+
     if (dist < hwall_t){
       L1 = lc_n;
       L2 = lc_t;
@@ -1831,13 +1927,13 @@ void BoundaryLayerField::operator() (AttractorField *cc, double dist,
       t2.normalize();
       t3 = crossprod(t1,t2);
       t3.normalize();
-      t1 = crossprod(t3,t2);	  
-    }	
+      t1 = crossprod(t3,t2);
+    }
   }
   metr  = SMetric3(1./(L1*L1), 1./(L2*L2), 1./(L3*L3), t1, t2, t3);
 }
 
-void BoundaryLayerField::operator() (double x, double y, double z, 
+void BoundaryLayerField::operator() (double x, double y, double z,
                                      SMetric3 &metr, GEntity *ge)
 {
   if (update_needed){
@@ -1866,7 +1962,7 @@ void BoundaryLayerField::operator() (double x, double y, double z,
     SPoint3 CLOSEST= (*it)->getAttractorInfo().second;
 
     SMetric3 localMetric;
-    (*this)(*it, cdist,x, y, z, localMetric, ge);      
+    (*this)(*it, cdist,x, y, z, localMetric, ge);
     hop.push_back(localMetric);
     //v = intersection(v,localMetric);
     if (cdist < current_distance){
@@ -1901,6 +1997,7 @@ FieldManager::FieldManager()
 #endif
   map_type_name["Box"] = new FieldFactoryT<BoxField>();
   map_type_name["Cylinder"] = new FieldFactoryT<CylinderField>();
+  map_type_name["Frustum"] = new FieldFactoryT<FrustumField>();
   map_type_name["LonLat"] = new FieldFactoryT<LonLatField>();
 #if defined(HAVE_POST)
   map_type_name["PostView"] = new FieldFactoryT<PostViewField>();
@@ -1928,7 +2025,7 @@ FieldManager::FieldManager()
 
 FieldManager::~FieldManager()
 {
-  for(std::map<std::string, FieldFactory*>::iterator it = map_type_name.begin(); 
+  for(std::map<std::string, FieldFactory*>::iterator it = map_type_name.begin();
       it != map_type_name.end(); it++)
     delete it->second;
 }
-- 
GitLab