]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
First sucessful use of MEDCouplingFieldDiscretizationOnNodesFE::getValueOn on hexa27
authorAnthony Geay <anthony.geay@edf.fr>
Tue, 23 Aug 2022 14:01:44 +0000 (16:01 +0200)
committerAnthony Geay <anthony.geay@edf.fr>
Tue, 23 Aug 2022 14:01:44 +0000 (16:01 +0200)
src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.cxx
src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.hxx
src/INTERP_KERNEL/InterpKernelRootsMultiDim.hxx
src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.cxx
src/MEDCoupling/CMakeLists.txt
src/MEDCoupling/MEDCouplingFieldDiscretizationOnNodesFE.cxx

index 36e61963da7d094a3b9095dcf3d0cb33ff8ff783..61feaf166f99bd60ed650d08bc9107dbaa1a08ca 100644 (file)
@@ -506,6 +506,36 @@ std::vector<double> GaussInfo::GetDefaultReferenceCoordinatesOf(NormalizedCellTy
   THROW_IK_EXCEPTION("Input type " << ct << "is not managed by GetDefaultReferenceCoordinatesOf")
 }
 
+/*!
+ * Returns true if \a ptInRefCoo is in reference cell of type \a ct (regarding GetDefaultReferenceCoordinatesOf)
+ * \sa GetDefaultReferenceCoordinatesOf
+ */
+bool GaussInfo::IsInOrOutForReference(NormalizedCellType ct, const double *ptInRefCoo, double eps)
+{
+  switch(ct)
+  {
+    case INTERP_KERNEL::NORM_SEG2:
+    case INTERP_KERNEL::NORM_SEG3:
+    {
+      return std::fabs(ptInRefCoo[0]) < 1.0+eps;
+    }
+    case INTERP_KERNEL::NORM_QUAD4:
+    case INTERP_KERNEL::NORM_QUAD8:
+    case INTERP_KERNEL::NORM_QUAD9:
+    {
+      return std::find_if(ptInRefCoo,ptInRefCoo+2,[eps](double v){ return std::fabs(v) > 1.0+eps; }) == ptInRefCoo+2;
+    }
+    case INTERP_KERNEL::NORM_HEXA8:
+    case INTERP_KERNEL::NORM_HEXA20:
+    case INTERP_KERNEL::NORM_HEXA27:
+    {
+      return std::find_if(ptInRefCoo,ptInRefCoo+3,[eps](double v){ return std::fabs(v) > 1.0+eps; }) == ptInRefCoo+3;
+    }
+    default:
+      THROW_IK_EXCEPTION("IsInOrOutForReference : not implemented for this geo type !");
+  }
+}
+
 typedef void (*MapToShapeFunction)(GaussInfo& obj);
 
 /*!
index 4497180e21dc47656b744c25af6d86e6ac2aba4c..5afdfa7d293c5a041447ca181a86673c6c050b95 100644 (file)
@@ -64,6 +64,7 @@ namespace INTERP_KERNEL
     
     INTERPKERNEL_EXPORT static std::vector<double> NormalizeCoordinatesIfNecessary(NormalizedCellType ct, int inputDim, const std::vector<double>& inputArray);
     INTERPKERNEL_EXPORT static std::vector<double> GetDefaultReferenceCoordinatesOf(NormalizedCellType ct);
+    INTERPKERNEL_EXPORT static bool IsInOrOutForReference(NormalizedCellType ct, const double *ptInRefCoo, double eps);
   public:
     static const double SEG2A_REF[2];
     static const double SEG2B_REF[2];
index 3fba59fdb2c1aefde2b137f0a3089066489ed13a..721ac00c9610c694bccdd2a188daaff0d48a3734 100644 (file)
@@ -55,7 +55,7 @@ namespace INTERP_KERNEL
     test=0.0;
     for (i=0;i<n;i++)
     {
-      temp=std::abs(p[i])/std::max(std::abs(xold[i]),1.0);
+      temp=std::abs(p[i])/std::fmax(std::abs(xold[i]),1.0);
       if (temp > test) test=temp;
     }
     alamin=TOLX/test;
@@ -93,7 +93,7 @@ namespace INTERP_KERNEL
       }
       alam2=alam;
       f2 = f;
-      alam=std::max(tmplam,0.1*alam);
+      alam=std::fmax(tmplam,0.1*alam);
     }
   }
   template <class T>
@@ -145,6 +145,10 @@ namespace INTERP_KERNEL
     std::vector<double>& getVector() { return fvec; }
   };
 
+  /*!
+   * check is false on normal return.
+   * check is true if the routine has converged to a local minimum.
+   */
   template <class T>
   void SolveWithNewton(std::vector<double> &x, bool &check, T &vecfunc)
   {
@@ -169,7 +173,7 @@ namespace INTERP_KERNEL
     }
     sum=0.0;
     for (i=0;i<n;i++) sum += sqr(x[i]);
-    stpmax=STPMX*std::max(std::sqrt(sum),double(n));
+    stpmax=STPMX*std::fmax(std::sqrt(sum),double(n));
     for (its=0;its<MAXITS;its++)
     {
       fjac=fdjac(x,fvec);
@@ -196,9 +200,9 @@ namespace INTERP_KERNEL
       if (check)
       {
         test=0.0;
-        den=std::max(f,0.5*n);
+        den=std::fmax(f,0.5*double(n));
         for (i=0;i<n;i++) {
-            temp=std::abs(g[i])*std::max(std::abs(x[i]),1.0)/den;
+            temp=std::abs(g[i])*std::fmax(std::abs(x[i]),1.0)/den;
             if (temp > test) test=temp;
         }
         check=(test < TOLMIN);
@@ -207,7 +211,7 @@ namespace INTERP_KERNEL
       test=0.0;
       for (i=0;i<n;i++)
       {
-        temp=(std::abs(x[i]-xold[i]))/std::max(std::abs(x[i]),1.0);
+        temp=(std::abs(x[i]-xold[i]))/std::fmax(std::abs(x[i]),1.0);
         if (temp > test) test=temp;
       }
       if (test < TOLX)
index 78afd9829ac968cb69570398fb2916b9273b678b..e180a9b8a3e7a68c9540be7d1f572e170bf6db57 100644 (file)
@@ -39,7 +39,7 @@ QRDecomp::QRDecomp(const INTERP_KERNEL::DenseMatrix& a): n(a.nrows()), qt(n,n),
        double scale,sigma,sum,tau;
        for (k=0;k<n-1;k++) {
                scale=0.0;
-               for (i=k;i<n;i++) scale=std::max(scale,std::abs(r[i][k]));
+               for (i=k;i<n;i++) scale=std::fmax(scale,std::abs(r[i][k]));
                if (scale == 0.0) {
                        sing=true;
                        c[k]=d[k]=0.0;
index 8dd2592a6f8e431226c37a6ac73a2440855af705..5bd1fccdde9ed920b1b84a77788e53d96563738b 100644 (file)
@@ -37,6 +37,7 @@ INCLUDE_DIRECTORIES(
   ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Geometric2D
   ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/ExprEval
   ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/GaussPoints
+  ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/LinearAlgebra
   )
 
 SET(medcoupling_SOURCES
index db791fadb2ff1e67632330a6f6573d8d0f0ca51b..f769818e9841a33e42a2f95b44d97212b650178f 100755 (executable)
 
 #include "MEDCouplingFieldDiscretizationOnNodesFE.hxx"
 #include "MEDCouplingNormalizedUnstructuredMesh.txx"
+#include "InterpKernelRootsMultiDim.hxx"
 #include "MEDCouplingUMesh.hxx"
 #include "InterpolationHelper.txx"
+#include "InterpKernelGaussCoords.hxx"
 
 #include <sstream>
 
@@ -81,10 +83,67 @@ MEDCouplingFieldDouble *MEDCouplingFieldDiscretizationOnNodesFE::getMeasureField
   throw INTERP_KERNEL::Exception("getMeasureField on MEDCouplingFieldDiscretizationOnNodesFE : not implemented yet !");
 }
 
+class Functor
+{
+private:
+  const MEDCouplingGaussLocalization* _gl;
+  std::size_t _nb_pts_in_cell;
+  const double *_pts_in_cell;
+  const double *_point;
+public:
+  Functor(const MEDCouplingGaussLocalization& gl, std::size_t nbPtsInCell, const double *ptsInCell, const double point[3]):_gl(&gl),_nb_pts_in_cell(nbPtsInCell),
+  _pts_in_cell(ptsInCell),_point(point) { }
+  std::vector<double> operator()(const std::vector<double>& x)
+  {
+    MEDCouplingGaussLocalization gl(_gl->getType(),_gl->getRefCoords(),x,{1.0});
+    MCAuto<DataArrayDouble> shapeFunc = gl.getShapeFunctionValues();
+    const double *shapeFuncPtr( shapeFunc->begin() );
+    std::vector<double> ret(3,0);
+    for(std::size_t iPt = 0; iPt < _nb_pts_in_cell ; ++iPt)
+    {
+      for(short iDim = 0 ; iDim < 3 ; ++iDim)
+        ret[iDim] += shapeFuncPtr[iPt] * _pts_in_cell[3*iPt + iDim];
+    }
+    ret[0] -= _point[0]; ret[1] -= _point[1]; ret[2] -= _point[2];
+    return ret;
+  }
+};
+
 bool IsInside3D(const MEDCouplingGaussLocalization& gl, const std::vector<double>& ptsInCell, const double locInReal[3], double locInRef[3])
 {
-  locInRef[0] = 0; locInRef[1] = 0; locInRef[2] = 0;
-  return true;
+  constexpr double EPS_IN_OUT = 1e-12;
+  std::size_t nbPtsInCell(ptsInCell.size()/3);
+  bool ret(false);
+  const double *refCoo(gl.getRefCoords().data());
+  INTERP_KERNEL::NormalizedCellType ct(gl.getType());
+  Functor func(gl,nbPtsInCell,ptsInCell.data(),locInReal);
+  // loop on refcoords as initialization point for Newton algo.
+  for(std::size_t attemptId = 0 ; attemptId < nbPtsInCell ; ++attemptId)
+  {
+    std::vector<double> vini(refCoo + attemptId*3, refCoo + (attemptId+1)*3);
+    try
+    {
+      bool check(true);
+      INTERP_KERNEL::SolveWithNewton(vini,check,func);
+      ret = (check==false);//looks strange but OK regarding newt (SolveWithNewton) at page 387 of numerical recipes for semantic of check parameter
+    }
+    catch( INTERP_KERNEL::Exception& ex )
+      { ret = false; }// Something get wrong during Newton process
+    if(ret)
+    {//Newton has converged. Now check if it converged to a point inside cell
+      if( ! INTERP_KERNEL::GaussInfo::IsInOrOutForReference(ct,vini.data(),EPS_IN_OUT) )
+      {// converged but detected as outside
+        ret = false;
+      }
+    }
+    if(ret)
+    {
+      locInRef[0] = vini[0]; locInRef[1] = vini[1]; locInRef[2] = vini[2];
+      return ret;
+    }
+  }
+  std::fill(locInRef,locInRef+3,std::numeric_limits<double>::max());
+  return false;
 }
 
 void MEDCouplingFieldDiscretizationOnNodesFE::getValueOn(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, double *res) const
@@ -133,7 +192,7 @@ DataArrayDouble *MEDCouplingFieldDiscretizationOnNodesFE::getValueOnMulti(const
       umesh->getNodeIdsOfCell(*cellId,conn);
       MCAuto<DataArrayDouble> refCoo( MEDCouplingGaussLocalization::GetDefaultReferenceCoordinatesOf(gt) );
       std::vector<double> refCooCpp(refCoo->begin(),refCoo->end());
-      std::vector<double> gsCoo(loc,loc+3); 
+      std::vector<double> gsCoo(loc + iPt*3,loc + (iPt+1)*3); 
       MEDCouplingGaussLocalization gl(gt,refCooCpp,{0,0,0},{1.});
       std::vector<double> ptsInCell; ptsInCell.reserve(conn.size()*gl.getDimension());
       std::for_each( conn.cbegin(), conn.cend(), [coordsOfMesh,&ptsInCell](mcIdType c) { ptsInCell.insert(ptsInCell.end(),coordsOfMesh+c*3,coordsOfMesh+(c+1)*3); } );