Salome HOME
Merge from V6_main 11/02/2013
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingRemapper.cxx
index 3c5fa11f23cffa0d2084fc7ab4d3506ab56a16c9..0e120ce1017c95a179dd5f2c0726ca24c41896ff 100644 (file)
@@ -16,6 +16,7 @@
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+// Author : Anthony Geay (CEA/DEN)
 
 #include "MEDCouplingRemapper.hxx"
 #include "MEDCouplingMemArray.hxx"
@@ -23,7 +24,9 @@
 #include "MEDCouplingFieldTemplate.hxx"
 #include "MEDCouplingFieldDiscretization.hxx"
 #include "MEDCouplingExtrudedMesh.hxx"
+#include "MEDCouplingCMesh.hxx"
 #include "MEDCouplingNormalizedUnstructuredMesh.txx"
+#include "MEDCouplingNormalizedCartesianMesh.txx"
 
 #include "Interpolation1D.txx"
 #include "Interpolation2DCurve.hxx"
@@ -32,6 +35,8 @@
 #include "Interpolation3DSurf.hxx"
 #include "Interpolation2D1D.txx"
 #include "Interpolation3D2D.txx"
+#include "InterpolationCU.txx"
+#include "InterpolationCC.txx"
 
 using namespace ParaMEDMEM;
 
@@ -54,6 +59,12 @@ int MEDCouplingRemapper::prepare(const MEDCouplingMesh *srcMesh, const MEDCoupli
     {
     case 85://Unstructured-Unstructured
       return prepareUU(method);
+    case 87://Unstructured-Cartesian
+      return prepareUC(method);
+    case 117://Cartesian-Unstructured
+      return prepareCU(method);
+    case 119://Cartesian-Cartesian
+      return prepareCC(method);
     case 136://Extruded-Extruded
       return prepareEE(method);
     default:
@@ -231,7 +242,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce
       INTERP_KERNEL::Interpolation3D interpolation(*this);
       std::vector<std::map<int,double> > matrixTmp;
       nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method);
-      reverseMatrix(matrixTmp,nbCols,_matrix);
+      ReverseMatrix(matrixTmp,nbCols,_matrix);
       nbCols=matrixTmp.size();
     }
   else if(srcMeshDim==2 && trgMeshDim==1 && srcSpaceDim==2)
@@ -250,7 +261,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce
           INTERP_KERNEL::Interpolation2D1D interpolation(*this);
           std::vector<std::map<int,double> > matrixTmp;
           nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method);
-          reverseMatrix(matrixTmp,nbCols,_matrix);
+          ReverseMatrix(matrixTmp,nbCols,_matrix);
           nbCols=matrixTmp.size();
           INTERP_KERNEL::Interpolation2D1D::DuplicateFacesType duplicateFaces=interpolation.retrieveDuplicateFaces();
           if(!duplicateFaces.empty())
@@ -274,7 +285,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce
           INTERP_KERNEL::Interpolation2D interpolation(*this);
           std::vector<std::map<int,double> > matrixTmp;
           nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method);
-          reverseMatrix(matrixTmp,nbCols,_matrix);
+          ReverseMatrix(matrixTmp,nbCols,_matrix);
           nbCols=matrixTmp.size();
         }
       else
@@ -321,7 +332,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce
       INTERP_KERNEL::Interpolation3D2D interpolation(*this);
       std::vector<std::map<int,double> > matrixTmp;
       nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method);
-      reverseMatrix(matrixTmp,nbCols,_matrix);
+      ReverseMatrix(matrixTmp,nbCols,_matrix);
       nbCols=matrixTmp.size();
       INTERP_KERNEL::Interpolation3D2D::DuplicateFacesType duplicateFaces=interpolation.retrieveDuplicateFaces();
       if(!duplicateFaces.empty())
@@ -425,6 +436,163 @@ int MEDCouplingRemapper::prepareEE(const char *method) throw(INTERP_KERNEL::Exce
   return 1;
 }
 
+int MEDCouplingRemapper::prepareUC(const char *method) throw(INTERP_KERNEL::Exception)
+{
+  std::string methodCpp(method);
+  if(methodCpp!="P0P0")
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : only P0P0 interpolation supported for the moment !");
+  INTERP_KERNEL::Interpolation<INTERP_KERNEL::Interpolation3D>::checkAndSplitInterpolationMethod(method,_src_method,_target_method);
+  MEDCouplingUMesh *src_mesh=static_cast<MEDCouplingUMesh *>(_src_mesh);
+  MEDCouplingCMesh *target_mesh=static_cast<MEDCouplingCMesh *>(_target_mesh);
+  const int srcMeshDim=src_mesh->getMeshDimension();
+  const int srcSpceDim=src_mesh->getSpaceDimension();
+  const int trgMeshDim=target_mesh->getMeshDimension();
+  if(srcMeshDim!=srcSpceDim || srcMeshDim!=trgMeshDim)
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : space dim of src unstructured should be equal to mesh dim of src unstructured and should be equal also equal to trg cartesian dimension !");
+  std::vector<std::map<int,double> > res;
+  switch(srcMeshDim)
+    {
+    case 1:
+      {
+        MEDCouplingNormalizedCartesianMesh<1> targetWrapper(target_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<1,1> sourceWrapper(src_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0");
+        break;
+      }
+    case 2:
+      {
+        MEDCouplingNormalizedCartesianMesh<2> targetWrapper(target_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<2,2> sourceWrapper(src_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0");
+        break;
+      }
+    case 3:
+      {
+        MEDCouplingNormalizedCartesianMesh<3> targetWrapper(target_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<3,3> sourceWrapper(src_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0");
+        break;
+      }
+    default:
+      throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : only dimension 1 2 or 3 supported !");
+    }
+  ReverseMatrix(res,target_mesh->getNumberOfCells(),_matrix);
+  nullifiedTinyCoeffInCrudeMatrixAbs(0.);
+  //
+  _deno_multiply.clear();
+  _deno_multiply.resize(_matrix.size());
+  _deno_reverse_multiply.clear();
+  _deno_reverse_multiply.resize(src_mesh->getNumberOfCells());
+  declareAsNew();
+  return 1;
+}
+
+int MEDCouplingRemapper::prepareCU(const char *method) throw(INTERP_KERNEL::Exception)
+{
+  std::string methodCpp(method);
+  if(methodCpp!="P0P0")
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : only P0P0 interpolation supported for the moment !");
+  INTERP_KERNEL::Interpolation<INTERP_KERNEL::Interpolation3D>::checkAndSplitInterpolationMethod(method,_src_method,_target_method);
+  MEDCouplingCMesh *src_mesh=static_cast<MEDCouplingCMesh *>(_src_mesh);
+  MEDCouplingUMesh *target_mesh=static_cast<MEDCouplingUMesh *>(_target_mesh);
+  const int srcMeshDim=src_mesh->getMeshDimension();
+  const int trgMeshDim=target_mesh->getMeshDimension();
+  const int trgSpceDim=target_mesh->getSpaceDimension();
+  if(trgMeshDim!=trgSpceDim || trgMeshDim!=srcMeshDim)
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : space dim of target unstructured should be equal to mesh dim of target unstructured and should be equal also equal to source cartesian dimension !");
+  switch(srcMeshDim)
+    {
+    case 1:
+      {
+        MEDCouplingNormalizedCartesianMesh<1> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<1,1> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    case 2:
+      {
+        MEDCouplingNormalizedCartesianMesh<2> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<2,2> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    case 3:
+      {
+        MEDCouplingNormalizedCartesianMesh<3> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedUnstructuredMesh<3,3> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCU myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    default:
+      throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : only dimension 1 2 or 3 supported !");
+    }
+  nullifiedTinyCoeffInCrudeMatrixAbs(0.);
+  //
+  _deno_multiply.clear();
+  _deno_multiply.resize(_matrix.size());
+  _deno_reverse_multiply.clear();
+  _deno_reverse_multiply.resize(src_mesh->getNumberOfCells());
+  declareAsNew();
+  return 1;
+}
+
+int MEDCouplingRemapper::prepareCC(const char *method) throw(INTERP_KERNEL::Exception)
+{
+  std::string methodCpp(method);
+  if(methodCpp!="P0P0")
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : only P0P0 interpolation supported for the moment !");
+  INTERP_KERNEL::Interpolation<INTERP_KERNEL::Interpolation3D>::checkAndSplitInterpolationMethod(method,_src_method,_target_method);
+  MEDCouplingCMesh *src_mesh=static_cast<MEDCouplingCMesh *>(_src_mesh);
+  MEDCouplingCMesh *target_mesh=static_cast<MEDCouplingCMesh *>(_target_mesh);
+  const int srcMeshDim=src_mesh->getMeshDimension();
+  const int trgMeshDim=target_mesh->getMeshDimension();
+  if(trgMeshDim!=srcMeshDim)
+    throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : dim of target cartesian should be equal to dim of source cartesian dimension !");
+  switch(srcMeshDim)
+    {
+    case 1:
+      {
+        MEDCouplingNormalizedCartesianMesh<1> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedCartesianMesh<1> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCC myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    case 2:
+      {
+        MEDCouplingNormalizedCartesianMesh<2> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedCartesianMesh<2> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCC myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    case 3:
+      {
+        MEDCouplingNormalizedCartesianMesh<3> sourceWrapper(src_mesh);
+        MEDCouplingNormalizedCartesianMesh<3> targetWrapper(target_mesh);
+        INTERP_KERNEL::InterpolationCC myInterpolator(*this);
+        myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0");
+        break;
+      }
+    default:
+      throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : only dimension 1 2 or 3 supported !");
+    }
+  nullifiedTinyCoeffInCrudeMatrixAbs(0.);
+  //
+  _deno_multiply.clear();
+  _deno_multiply.resize(_matrix.size());
+  _deno_reverse_multiply.clear();
+  _deno_reverse_multiply.resize(src_mesh->getNumberOfCells());
+  declareAsNew();
+  return 1;
+}
+
 void MEDCouplingRemapper::updateTime() const
 {
 }
@@ -493,13 +661,13 @@ void MEDCouplingRemapper::computeDenoFromScratch(NatureOfField nat, const MEDCou
     {
     case ConservativeVolumic:
       {
-        computeRowSumAndColSum(_matrix,_deno_multiply,_deno_reverse_multiply);
+        ComputeRowSumAndColSum(_matrix,_deno_multiply,_deno_reverse_multiply);
         break;
       }
     case Integral:
       {
-        MEDCouplingFieldDouble *deno=srcField->getDiscretization()->getMeasureField(srcField->getMesh(),true);
-        MEDCouplingFieldDouble *denoR=trgField->getDiscretization()->getMeasureField(trgField->getMesh(),true);
+        MEDCouplingFieldDouble *deno=srcField->getDiscretization()->getMeasureField(srcField->getMesh(),getMeasureAbsStatus());
+        MEDCouplingFieldDouble *denoR=trgField->getDiscretization()->getMeasureField(trgField->getMesh(),getMeasureAbsStatus());
         const double *denoPtr=deno->getArray()->getConstPointer();
         const double *denoRPtr=denoR->getArray()->getConstPointer();
         if(trgField->getMesh()->getMeshDimension()==-1)
@@ -525,13 +693,13 @@ void MEDCouplingRemapper::computeDenoFromScratch(NatureOfField nat, const MEDCou
       }
     case IntegralGlobConstraint:
       {
-        computeColSumAndRowSum(_matrix,_deno_multiply,_deno_reverse_multiply);
+        ComputeColSumAndRowSum(_matrix,_deno_multiply,_deno_reverse_multiply);
         break;
       }
     case RevIntegral:
       {
-        MEDCouplingFieldDouble *deno=trgField->getDiscretization()->getMeasureField(trgField->getMesh(),true);
-        MEDCouplingFieldDouble *denoR=srcField->getDiscretization()->getMeasureField(srcField->getMesh(),true);
+        MEDCouplingFieldDouble *deno=trgField->getDiscretization()->getMeasureField(trgField->getMesh(),getMeasureAbsStatus());
+        MEDCouplingFieldDouble *denoR=srcField->getDiscretization()->getMeasureField(srcField->getMesh(),getMeasureAbsStatus());
         const double *denoPtr=deno->getArray()->getConstPointer();
         const double *denoRPtr=denoR->getArray()->getConstPointer();
         if(trgField->getMesh()->getMeshDimension()==-1)
@@ -606,7 +774,7 @@ void MEDCouplingRemapper::computeReverseProduct(const double *inputPointer, int
       std::fill(resPointer+idx*inputNbOfCompo,resPointer+(idx+1)*inputNbOfCompo,dftValue);
 }
 
-void MEDCouplingRemapper::reverseMatrix(const std::vector<std::map<int,double> >& matIn, int nbColsMatIn, std::vector<std::map<int,double> >& matOut)
+void MEDCouplingRemapper::ReverseMatrix(const std::vector<std::map<int,double> >& matIn, int nbColsMatIn, std::vector<std::map<int,double> >& matOut)
 {
   matOut.resize(nbColsMatIn);
   int id=0;
@@ -615,7 +783,7 @@ void MEDCouplingRemapper::reverseMatrix(const std::vector<std::map<int,double> >
       matOut[(*iter2).first][id]=(*iter2).second;
 }
 
-void MEDCouplingRemapper::computeRowSumAndColSum(const std::vector<std::map<int,double> >& matrixDeno,
+void MEDCouplingRemapper::ComputeRowSumAndColSum(const std::vector<std::map<int,double> >& matrixDeno,
                                                  std::vector<std::map<int,double> >& deno, std::vector<std::map<int,double> >& denoReverse)
 {
   std::map<int,double> values;
@@ -639,7 +807,7 @@ void MEDCouplingRemapper::computeRowSumAndColSum(const std::vector<std::map<int,
     }
 }
 
-void MEDCouplingRemapper::computeColSumAndRowSum(const std::vector<std::map<int,double> >& matrixDeno,
+void MEDCouplingRemapper::ComputeColSumAndRowSum(const std::vector<std::map<int,double> >& matrixDeno,
                                                  std::vector<std::map<int,double> >& deno, std::vector<std::map<int,double> >& denoReverse)
 {
   std::map<int,double> values;
@@ -705,3 +873,74 @@ const std::vector<std::map<int,double> >& MEDCouplingRemapper::getCrudeMatrix()
 {
   return _matrix;
 }
+
+/*!
+ * This method is supposed to be called , if needed, right after MEDCouplingRemapper::prepare or MEDCouplingRemapper::prepareEx.
+ * If not the behaviour is unpredictable.
+ * This method works on precomputed \a this->_matrix. All coefficients in the matrix is lower than \a maxValAbs this coefficient is
+ * set to 0. That is to say that its entry disappear from the map storing the corresponding row in the data storage of sparse crude matrix.
+ * This method is useful to correct at a high level some problems linked to precision. Indeed, with some \ref NatureOfField "natures of field" some threshold effect
+ * can occur.
+ *
+ * \param [in] maxValAbs is a limit behind which a coefficient is set to 0. \a maxValAbs is expected to be positive, if not this method do nothing.
+ * \return a positive value that tells the number of coefficients put to 0. The 0 returned value means that the matrix has remained unchanged.
+ * \sa MEDCouplingRemapper::nullifiedTinyCoeffInCrudeMatrix
+ */
+int MEDCouplingRemapper::nullifiedTinyCoeffInCrudeMatrixAbs(double maxValAbs) throw(INTERP_KERNEL::Exception)
+{
+  int ret=0;
+  std::vector<std::map<int,double> > matrixNew(_matrix.size());
+  int i=0;
+  for(std::vector<std::map<int,double> >::const_iterator it1=_matrix.begin();it1!=_matrix.end();it1++,i++)
+    {
+      std::map<int,double>& rowNew=matrixNew[i];
+      for(std::map<int,double>::const_iterator it2=(*it1).begin();it2!=(*it1).end();it2++)
+        {
+          if(fabs((*it2).second)>maxValAbs)
+            rowNew[(*it2).first]=(*it2).second;
+          else
+            ret++;
+        }
+    }
+  if(ret>0)
+    _matrix=matrixNew;
+  return ret;
+}
+
+/*!
+ * This method is supposed to be called , if needed, right after MEDCouplingRemapper::prepare or MEDCouplingRemapper::prepareEx.
+ * If not the behaviour is unpredictable.
+ * This method works on precomputed \a this->_matrix. All coefficients in the matrix is lower than delta multiplied by \a scaleFactor this coefficient is
+ * set to 0. That is to say that its entry disappear from the map storing the corresponding row in the data storage of sparse crude matrix.
+ * delta is the value returned by MEDCouplingRemapper::getMaxValueInCrudeMatrix method.
+ * This method is useful to correct at a high level some problems linked to precision. Indeed, with some \ref NatureOfField "natures of field" some threshold effect
+ * can occur.
+ *
+ * \param [in] scaleFactor is the scale factor from which coefficients lower than \a scaleFactor times range width of coefficients are set to zero.
+ * \return a positive value that tells the number of coefficients put to 0. The 0 returned value means that the matrix has remained unchanged. If -1 is returned it means
+ *         that all coefficients are null.
+ * \sa MEDCouplingRemapper::nullifiedTinyCoeffInCrudeMatrixAbs
+ */
+int MEDCouplingRemapper::nullifiedTinyCoeffInCrudeMatrix(double scaleFactor) throw(INTERP_KERNEL::Exception)
+{
+  double maxVal=getMaxValueInCrudeMatrix();
+  if(maxVal==0.)
+    return -1;
+  return nullifiedTinyCoeffInCrudeMatrixAbs(scaleFactor*maxVal);
+}
+
+/*!
+ * This method is supposed to be called , if needed, right after MEDCouplingRemapper::prepare or MEDCouplingRemapper::prepareEx.
+ * If not the behaviour is unpredictable.
+ * This method returns the maximum of the absolute values of coefficients into the sparse crude matrix.
+ * The returned value is positive.
+ */
+double MEDCouplingRemapper::getMaxValueInCrudeMatrix() const throw(INTERP_KERNEL::Exception)
+{
+  double ret=0.;
+  for(std::vector<std::map<int,double> >::const_iterator it1=_matrix.begin();it1!=_matrix.end();it1++)
+    for(std::map<int,double>::const_iterator it2=(*it1).begin();it2!=(*it1).end();it2++)
+      if(fabs((*it2).second)>ret)
+        ret=fabs((*it2).second);
+  return ret;
+}