Salome HOME
[bos #38048] [EDF] (2023-T3) PARAMEDMEM Ergonomy.
[tools/medcoupling.git] / src / ParaMEDMEM / InterpKernelDEC.cxx
index d8a8751f7804fc7c8b2029398546c09a73b18c92..f4494f489a64877a22e5e44bb242c497bf17d12b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2020  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 "ElementLocator.hxx"
 
 namespace MEDCoupling
-{  
-
-  /*!
-    \anchor InterpKernelDEC-det
-    \class InterpKernelDEC
-
-    \section InterpKernelDEC-over Overview
-
-    The InterpKernelDEC enables the \ref InterpKerRemapGlobal "remapping" (or interpolation) of fields between
-    two parallel codes.
-
-    The projection
-    methodology is based on the algorithms of %INTERP_KERNEL, that is to say, they work in a similar fashion than
-    what the \ref remapper "sequential remapper" does. The following \ref discretization "projection methods"
-    are supported: P0->P0 (the most common case), P1->P0, P0->P1.
-
-    The computation is possible for 3D meshes, 2D meshes, and 3D-surface
-    meshes. Dimensions must be identical 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).
-
-    The name "InterpKernelDEC" comes from the fact that this class uses exactly the same algorithms
-    as the sequential remapper. Both this class and the sequential
-    \ref MEDCoupling::MEDCouplingRemapper "MEDCouplingRemapper" are built on top of the %INTERP_KERNEL
-    algorithms (notably the computation of the intersection volumes).
-
-    Among the important properties inherited from the parent abstract class \ref DisjointDEC-det "DisjointDEC",
-    the two \ref MPIProcessorGroup-det "processor groups" (source and target) must have a void intersection.
-
-    \image html NonCoincident_small.png "Transfer of a field supported by a quadrangular mesh to a triangular mesh".
-
-    \image latex NonCoincident_small.eps "Transfer of a field supported by a quadrangular mesh to a triangular mesh"
-
-    In the figure above we see the transfer of a field based on a quadrangular mesh to a new field supported by
-    a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, the values on the
-    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 running phase during which the projections 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 illustrates 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 InterpKerRemapGlobal "remapping" of the field from the source mesh to the target mesh is performed by
-    the function synchronise(), which computes the interpolation matrix.
-
-    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 InterpKerRemapGlobal "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 the usual \ref MEDCoupling::DECOptions "DEC options", the options supported by %InterpKernelDEC objects are
-    related to the underlying \ref InterpKerIntersectors "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.setDoRotate(false);
-    dec.setPrecision(1e-12);
-    dec.synchronize();
-    \endverbatim
-
-    \warning{  Options must be set before calling the synchronize method. }
-  */
-  
+{
   InterpKernelDEC::InterpKernelDEC():
     DisjointDEC(),
-    _nb_distant_points(0), _distant_coords(0),
-    _distant_locations(0), _interpolation_matrix(0)
+    _interpolation_matrix(0)
   {  
   }
 
@@ -150,8 +51,7 @@ namespace MEDCoupling
   */
   InterpKernelDEC::InterpKernelDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
     DisjointDEC(source_group, target_group),
-    _nb_distant_points(0), _distant_coords(0),
-    _distant_locations(0), _interpolation_matrix(0)
+    _interpolation_matrix(0)
   {
 
   }
@@ -165,16 +65,60 @@ namespace MEDCoupling
   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),
-    _nb_distant_points(0), _distant_coords(0),
-    _distant_locations(0), _interpolation_matrix(0)
+    _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.
@@ -258,6 +202,15 @@ namespace MEDCoupling
     _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.
@@ -274,6 +227,29 @@ namespace MEDCoupling
       }
   }
 
+  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