Salome HOME
[bos #38048] [EDF] (2023-T3) PARAMEDMEM Ergonomy.
[tools/medcoupling.git] / src / ParaMEDMEM / InterpKernelDEC.cxx
index 0027a853c385a04d5453ac3725759c965b278eb2..f4494f489a64877a22e5e44bb242c497bf17d12b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2014  CEA/DEN, EDF R&D
+// Copyright (C) 2007-2024  CEA, EDF
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 #include "InterpKernelDEC.hxx"
 #include "ElementLocator.hxx"
 
-namespace ParaMEDMEM
-{  
-
-  /*!
-    \defgroup interpkerneldec InterpKernelDEC
-
-    \section overview Overview
-
-    The InterpKernelDEC enables the \ref conservativeremapping of fields between two parallel codes. This remapping is based on the computation of intersection volumes between elements from code A and elements from code B. The computation is possible for 3D meshes, 2D meshes, and 3D-surface meshes. Dimensions must be similar for code A and code B (for instance, though it could be desirable, it is not yet possible to couple 3D surfaces with 2D surfaces).
-
-    In the present version, only fields lying on elements are considered.
-
-    \image html NonCoincident_small.png "Example showing the transfer from a field based on a quadrangular mesh to a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, the values on quadrangles are weighted by their intersection area and summed."
-
-    \image latex NonCoincident_small.eps "Example showing the transfer from a field based on a quadrangular mesh to a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, the values on quadrangles are weighted by their intersection area and summed."
-
-    A typical use of InterpKernelDEC encompasses two distinct phases :
-    - A setup phase during which the intersection volumes are computed and the communication structures are setup. This corresponds to calling the InterpKernelDEC::synchronize() method.
-    - A use phase during which the remappings are actually performed. This corresponds to the calls to sendData() and recvData() which actually trigger the data exchange. The data exchange are synchronous in the current version of the library so that recvData() and sendData() calls must be synchronized on code A and code B processor groups. 
-
-    The following code excerpt illutrates a typical use of the InterpKernelDEC class.
-
-    \code
-    ...
-    InterpKernelDEC dec(groupA, groupB);
-    dec.attachLocalField(field);
-    dec.synchronize();
-    if (groupA.containsMyRank())
-    dec.recvData();
-    else if (groupB.containsMyRank())
-    dec.sendData();
-    ...
-    \endcode
-    A \ref conservativeremapping of the field from the source mesh to the target mesh is performed by the function synchronise(), which computes the \ref remappingmatrix.
-
-    Computing the field on the receiving side can be expressed in terms of a matrix-vector product : \f$ \phi_t=W.\phi_s\f$, with \f$ \phi_t \f$ the field on the target side and \f$ \phi_s \f$ the field on the source side.
-    When remapping a 3D surface to another 3D surface, a projection phase is necessary to match elements from both sides. Care must be taken when defining this projection to obtain a \ref conservative remapping.
-
-    In the P0-P0 case, this matrix is a plain rectangular matrix with coefficients equal to the intersection areas between triangle and quadrangles. For instance, in the above figure, the matrix is :
-
-    \f[
-    \begin{tabular}{|cccc|}
-    0.72 & 0 & 0.2 & 0 \\
-    0.46 & 0 & 0.51 & 0.03\\
-    0.42 & 0.53 & 0 & 0.05\\
-    0 & 0 & 0.92 & 0.05 \\
-    \end{tabular}
-    \f]
-
-
-
-    \section interpkerneldec_options Options
-    On top of \ref dec_options, options supported by %InterpKernelDEC objects are
-    related to the underlying Intersector class. 
-    All the options available in the intersector objects are
-    available for the %InterpKernelDEC object. The various options available for  * intersectors can be reviewed in \ref InterpKerIntersectors.
-    For instance :
-    \verbatim
-    InterpKernelDEC dec(source_group, target_group);
-    dec.attachLocalField(field);
-    dec.setOptions("DoRotate",false);
-    dec.setOptions("Precision",1e-12);
-    dec.synchronize();
-    \endverbatim
-
-    \warning{  Options must be set before calling the synchronize method. }
-  */
-
-  /*!
-    \addtogroup interpkerneldec
-    @{
-  */
-  
-  InterpKernelDEC::InterpKernelDEC():_interpolation_matrix(0)
+namespace MEDCoupling
+{
+  InterpKernelDEC::InterpKernelDEC():
+    DisjointDEC(),
+    _interpolation_matrix(0)
   {  
   }
 
@@ -112,35 +42,91 @@ namespace ParaMEDMEM
     This constructor creates an InterpKernelDEC which has \a source_group as a working side 
     and  \a target_group as an idle side. All the processors will actually participate, but intersection computations will be performed on the working side during the \a synchronize() phase.
     The constructor must be called synchronously on all processors of both processor groups.
+    The source group and target group MUST form a partition of all the procs within the communicator passed as 'world_comm'
+    when building the group.
 
     \param source_group working side ProcessorGroup
     \param target_group lazy side ProcessorGroup
 
   */
   InterpKernelDEC::InterpKernelDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
-    DisjointDEC(source_group, target_group),_interpolation_matrix(0)
+    DisjointDEC(source_group, target_group),
+    _interpolation_matrix(0)
   {
 
   }
 
+
+  /*!
+   * Creates an InterpKernelDEC from a set of source procs IDs and target group IDs.
+   * The difference with the ctor using groups is that the set of procs might not cover entirely MPI_COMM_WORLD
+   * (a sub-communicator holding the union of source and target procs is recreated internally).
+   */
   InterpKernelDEC::InterpKernelDEC(const std::set<int>& src_ids, const std::set<int>& trg_ids,
-                                   const MPI_Comm& world_comm):DisjointDEC(src_ids,trg_ids,world_comm),
-                                                               _interpolation_matrix(0)
+                                   const MPI_Comm& world_comm):
+    DisjointDEC(src_ids,trg_ids,world_comm),
+    _interpolation_matrix(0)
+  {
+  }
+
+  /*!
+   * Creates an InterpKernelDEC from an string identifier for the source and target groups.
+   * The set of procs might not cover entirely MPI_COMM_WORLD
+   * (a sub-communicator holding the union of source and target procs is recreated internally).
+   */
+  InterpKernelDEC::InterpKernelDEC(ProcessorGroup& generic_group, const std::string& source_group, const std::string& target_group):
+    DisjointDEC(generic_group.getProcIDsByName(source_group),generic_group.getProcIDsByName(target_group)),
+    _interpolation_matrix(0)
+  {
+  }
+  
+  /*!
+   * Split the interaction group based on the predefined token string "<->"
+   *  The string at left of the token will be the source group and the string at right the target group
+   */
+  static std::pair<std::string,std::string> GetGroupsName( const std::string& interaction_group )
+  {
+    const std::string delimiter = "<->";
+    size_t delimiter_position = interaction_group.find(delimiter);
+    if ( delimiter_position == std::string::npos )
+      throw ( "No delimiter <-> found in the interaction group.");
+
+    std::string src = interaction_group.substr(0,delimiter_position);
+    std::string tgt = interaction_group.substr(delimiter_position+delimiter.size(),interaction_group.size());
+    return std::make_pair(src,tgt);
+  }
+
+  /*!
+   * Creates an InterpKernelDEC from an string defining an interaction. 
+   *  The source and target group are obtained by spliting the string based in the "<->" token.
+   *  The constructor accepting a ProcessorGroup and two strings is reused.
+   */
+  InterpKernelDEC::InterpKernelDEC(ProcessorGroup& generic_group, const std::string& interaction_group ):
+    InterpKernelDEC(generic_group,GetGroupsName(interaction_group).first,GetGroupsName(interaction_group).second)
   {
   }
 
   InterpKernelDEC::~InterpKernelDEC()
   {
-    if (_interpolation_matrix !=0)
+    release();
+  }
+
+  void InterpKernelDEC::release()
+  {
+    if (_interpolation_matrix != nullptr)
       delete _interpolation_matrix;
-  } 
+    _interpolation_matrix = nullptr;
+    DisjointDEC::cleanInstance();
+  }
+
 
   /*! 
     \brief Synchronization process for exchanging topologies.
 
-    This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh underlying the fields that have been set with attachLocalField method.
+    This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh
+    underlying the fields that have been set with attachLocalField method.
     It works in four steps :
-    -# Bounding boxes are computed for each subdomain,
+    -# Bounding boxes are computed for each sub-domain,
     -# The lazy side mesh parts that are likely to intersect the working side local processor are sent to the working side,
     -# The working side calls the interpolation kernel to compute the intersection between local and imported mesh.
     -# The lazy side is updated so that it knows the structure of the data that will be sent by
@@ -159,10 +145,10 @@ namespace ParaMEDMEM
       {
         //locate the distant meshes
         ElementLocator locator(*_local_field, *_target_group, *_source_group);
-        //transfering option from InterpKernelDEC to ElementLocator   
+        //transferring option from InterpKernelDEC to ElementLocator   
         locator.copyOptions(*this);
         MEDCouplingPointSet* distant_mesh=0; 
-        int* distant_ids=0;
+        mcIdType* distant_ids=0;
         std::string distantMeth;
         for (int i=0; i<_target_group->size(); i++)
           {
@@ -190,10 +176,10 @@ namespace ParaMEDMEM
     if (_target_group->containsMyRank())
       {
         ElementLocator locator(*_local_field, *_source_group, *_target_group);
-        //transfering option from InterpKernelDEC to ElementLocator
+        //transferring option from InterpKernelDEC to ElementLocator
         locator.copyOptions(*this);
         MEDCouplingPointSet* distant_mesh=0;
-        int* distant_ids=0;
+        mcIdType* distant_ids=0;
         for (int i=0; i<_source_group->size(); i++)
           {
             //        int idistant_proc = (i+_target_group->myRank())%_source_group->size();
@@ -216,6 +202,15 @@ namespace ParaMEDMEM
     _interpolation_matrix->prepare();
   }
 
+  /*!
+   * Set a default value for non fetched entities
+   */
+  void InterpKernelDEC::synchronizeWithDefaultValue(double val)
+  {
+    this->synchronize();
+    if(_interpolation_matrix )
+      _interpolation_matrix->setDefaultValue(val);
+  }
 
   /*!
     Receives the data whether the processor is on the working side or on the lazy side. It must match a \a sendData() call on the other side.
@@ -232,6 +227,29 @@ namespace ParaMEDMEM
       }
   }
 
+  MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIds() const
+  {
+    if( _source_group->containsMyRank() )
+    {
+      return this->retrieveNonFetchedIdsSource();
+    }
+    if( _target_group->containsMyRank() )
+    {
+      return this->retrieveNonFetchedIdsTarget();
+    }
+    THROW_IK_EXCEPTION("Not detected side of rank !");
+  }
+
+  MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsSource() const
+  {
+    return _interpolation_matrix->retrieveNonFetchedIdsSource();
+  }
+
+  MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsTarget() const
+  {
+    mcIdType nbTuples = _local_field->getField()->getNumberOfTuplesExpected();
+    return _interpolation_matrix->retrieveNonFetchedIdsTarget(nbTuples);
+  }
 
   /*!
     Receives the data at time \a time in asynchronous mode. The value of the field
@@ -272,9 +290,5 @@ namespace ParaMEDMEM
     _interpolation_matrix->getAccessDEC()->setTime(time,deltatime);
     sendData() ;
   }
-
-  /*!
-    @}
-  */
   
 }