-// Copyright (C) 2007-2016 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)
{
}
*/
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)
{
}
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.
{
//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++)
{
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();
_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.
}
}
+ 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