Salome HOME
Make WriteField and WriteFieldUsingAlreadyWrittenMesh accessible for INT32, FLOAT32...
[tools/medcoupling.git] / src / ParaMEDMEM / DisjointDEC.cxx
index 3170acb82381185e8174c9061c4a499c30b6f1e7..4db440a6b72c22015e3a616000bbf5dd9f182afe 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2014  CEA/DEN, EDF R&D
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 #include "ParaMESH.hxx"
 #include "ICoCoField.hxx"
 #include "ICoCoMEDField.hxx"
-#include "ICoCoTrioField.hxx"
 #include "MPIProcessorGroup.hxx"
 
 #include <cmath>
 #include <iostream>
 
-/*! \defgroup dec DEC
- *
- * \section decintroduction Introduction
- *
- * Interface class for creation of a link between two 
- * processor groups for exhanging mesh or field data.
- * The \c DEC is defined by attaching a field on the receiving or on the 
- * sending side. 
- * On top of attaching a \c ParaMEDMEM::FIELD, it is possible to
- * attach a ICoCo::Field. This class is an abstract class that enables 
- * coupling of codes that respect the ICoCo interface \ref icoco. It has two implementations:
- * one for codes that express their fields as \ref medoupling fields (ICoCo::MEDField) and one
- * for codes that express their fields as Trio/U fields.
- * 
- * \section dec_options DEC Options
- * Options supported by \c DEC objects are
- *
- * <TABLE BORDER=1 >
- * <TR><TD>Option</TD><TD>Description</TD><TD>Default value</TD></TR>
- * <TR><TD>ForcedRenormalization</TD><TD>After receiving data, the target field is renormalized so that L2-norms of the source and target fields match.</TD><TD> false </TD></TR>
- *</TABLE>
-
-
- The following code excerpt shows how to set options for an object that inherits from \c DEC :
-
- \code
- InterpKernelDEC dec(source_group,target_group);
- dec.setOptions("ForcedRenormalization",true);
- dec.attachLocalField(field);
- dec.synchronize();
- if (source_group.containsMyRank())
- dec.sendData();
- else
- dec.recvData();
- \endcode
-*/
-
-namespace ParaMEDMEM
-{
 
+namespace MEDCoupling
+{
 
-  /*! \addtogroup dec
-    @{ 
+  /*!
+   * \anchor DisjointDEC-det
+   * \class DisjointDEC
+   *
+   * \section DisjointDEC-over Overview
+   *
+   * Abstract interface class representing a link between two
+   * processor groups for exchanging mesh or field data. The two processor groups must
+   * have a void intersection (\ref MEDCoupling::OverlapDEC "OverlapDEC" is to be considered otherwise).
+   * The %DEC is initialized by attaching a field on the receiving or on the
+   * sending side.
+   *
+   * The data is sent or received through calls to the (abstract) methods recvData() and sendData().
+   *
+   * One can attach either a \c MEDCoupling::ParaFIELD, or a
+   * \c ICoCo::Field, or directly a \c MEDCoupling::MEDCouplingFieldDouble instance.
+   * See the various signatures of the method DisjointDEC::attachLocalField()
+   *
+   * The derivations of this class should be considered for practical instanciation:
+   * - \ref InterpKernelDEC-det "InterpKernelDEC"
+   * - \ref ExplicitCoincidentDEC-det "ExplicitCoincidentDEC"
+   * - \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC"
+   *
+   * \section DisjointDEC-options DisjointDEC options
+   * The options supported by %DisjointDEC objects are the same that the ones supported for all
+   * DECs in general and are all inherited from the class \ref MEDCoupling::DECOptions "DECOptions"
+   *
   */
-  DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):_local_field(0), 
-                                                                                       _source_group(&source_group),
-                                                                                       _target_group(&target_group),
-                                                                                       _owns_field(false),
-                                                                                       _owns_groups(false),
-                                                                                       _icoco_field(0)
+
+  DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
+      _local_field(0),
+      _source_group(&source_group),
+      _target_group(&target_group),
+      _comm_interface(0),
+      _owns_field(false),
+      _owns_groups(false),
+      _union_comm(MPI_COMM_NULL)
   {
+    checkPartitionGroup();
     _union_group = source_group.fuse(target_group);  
   }
   
-  DisjointDEC::DisjointDEC(const DisjointDEC& s):DEC(s),_local_field(0),_union_group(0),_source_group(0),_target_group(0),_owns_field(false),_owns_groups(false),_icoco_field(0)
+  DisjointDEC::DisjointDEC(const DisjointDEC& s):
+      DEC(s),
+      _local_field(0),
+      _union_group(0),
+      _source_group(0),
+      _target_group(0),
+      _comm_interface(0),
+      _owns_field(false),
+      _owns_groups(false),
+      _union_comm(MPI_COMM_NULL)
   {
     copyInstance(s);
   }
@@ -102,32 +102,49 @@ namespace ParaMEDMEM
   void DisjointDEC::copyInstance(const DisjointDEC& other)
   {
     DEC::copyFrom(other);
-    if(other._target_group)
-      {
-        _target_group=other._target_group->deepCpy();
-        _owns_groups=true;
-      }
-    if(other._source_group)
+    if (other._union_comm != MPI_COMM_NULL)
       {
-        _source_group=other._source_group->deepCpy();
-        _owns_groups=true;
+        // Tricky: the DEC is responsible for the management of _union_comm. And this comm is referenced by
+        // the MPIProcGroups (source/targets). In the case where _union_comm is not NULL we must take care of rebuilding the
+        // MPIProcGroups with a communicator that will survive the destruction of 'other'.
+        _owns_groups = true;
+        MPI_Comm_dup(other._union_comm, &_union_comm);
+//        std::cout << "DUP union comm - new is "<< _union_comm << "\n";
+        _target_group = new MPIProcessorGroup(*_comm_interface, other._target_group->getProcIDs(), _union_comm);
+        _source_group = new MPIProcessorGroup(*_comm_interface, other._source_group->getProcIDs(), _union_comm);
       }
+    else{
+      if(other._target_group)
+        {
+          _target_group=other._target_group->deepCopy();
+          _owns_groups=true;
+        }
+      if(other._source_group)
+        {
+          _source_group=other._source_group->deepCopy();
+          _owns_groups=true;
+        }
+    }
     if (_source_group && _target_group)
       _union_group = _source_group->fuse(*_target_group);
   }
 
-  DisjointDEC::DisjointDEC(const std::set<int>& source_ids, const std::set<int>& target_ids, const MPI_Comm& world_comm):_local_field(0), 
-                                                                                                                         _owns_field(false),
-                                                                                                                         _owns_groups(true),
-                                                                                                                         _icoco_field(0)
+  DisjointDEC::DisjointDEC(const std::set<int>& source_ids,
+                           const std::set<int>& target_ids,
+                           const MPI_Comm& world_comm):
+     _local_field(0),
+     _owns_field(false),
+     _owns_groups(true),
+     _comm_interface(0),
+     _union_comm(MPI_COMM_NULL)
   {
-    ParaMEDMEM::CommInterface comm;
+    MEDCoupling::CommInterface comm;
     // Create the list of procs including source and target
     std::set<int> union_ids; // source and target ids in world_comm
     union_ids.insert(source_ids.begin(),source_ids.end());
     union_ids.insert(target_ids.begin(),target_ids.end());
     if(union_ids.size()!=(source_ids.size()+target_ids.size()))
-      throw INTERP_KERNEL::Exception("DisjointDEC constructor : source_ids and target_ids overlap partially or fully. This type of DEC does not support it ! OverlapDEC class could be the solution !");
+      throw INTERP_KERNEL::Exception("DisjointDEC constructor : source_ids and target_ids overlap partially or fully. This type of DEC does not support it! OverlapDEC class could be the solution!");
     int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm
     std::copy(union_ids.begin(), union_ids.end(), union_ranks_world);
 
@@ -135,15 +152,15 @@ namespace ParaMEDMEM
     MPI_Group union_group,world_group;
     comm.commGroup(world_comm,&world_group);
     comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
-    MPI_Comm union_comm;
-    comm.commCreate(world_comm,union_group,&union_comm);
+    comm.commCreate(world_comm,union_group,&_union_comm);
     delete[] union_ranks_world;
-
-    if (union_comm==MPI_COMM_NULL)
+    if (_union_comm==MPI_COMM_NULL)
       { // This process is not in union
         _source_group=0;
         _target_group=0;
         _union_group=0;
+        comm.groupFree(&union_group);
+        comm.groupFree(&world_group);
         return;
       }
 
@@ -168,10 +185,11 @@ namespace ParaMEDMEM
     delete [] target_ranks_union;
 
     // Create the MPIProcessorGroups
-    _source_group = new MPIProcessorGroup(comm,source_ids_union,union_comm);
-    _target_group = new MPIProcessorGroup(comm,target_ids_union,union_comm);
+    _source_group = new MPIProcessorGroup(comm,source_ids_union,_union_comm);
+    _target_group = new MPIProcessorGroup(comm,target_ids_union,_union_comm);
     _union_group = _source_group->fuse(*_target_group);
-
+    comm.groupFree(&union_group);
+    comm.groupFree(&world_group);
   }
 
   DisjointDEC::~DisjointDEC()
@@ -195,10 +213,32 @@ namespace ParaMEDMEM
     _owns_groups=false;
     _source_group=0;
     _target_group=0;
-    delete _icoco_field;
-    _icoco_field=0;
     delete _union_group;
     _union_group=0;
+    if (_union_comm != MPI_COMM_NULL)
+      _comm_interface->commFree(&_union_comm);
+  }
+
+  /**
+   * Check that the sources and targets procs form a partition of the world communicator referenced in the groups.
+   * This world communicator is not necessarily MPI_WORLD_COMM, but it has to be covered completly for the DECs to work.
+   */
+  void DisjointDEC::checkPartitionGroup() const
+  {
+    int size = -1;
+    MPIProcessorGroup * tgt = static_cast<MPIProcessorGroup *>(_target_group);
+    MPIProcessorGroup * src = static_cast<MPIProcessorGroup *>(_source_group);
+    MPI_Comm comm_t = tgt->getWorldComm();
+    MPI_Comm comm_s = src->getWorldComm();
+    if (comm_t != comm_s)
+      throw INTERP_KERNEL::Exception("DisjointDEC constructor: Inconsistent world communicator when building DisjointDEC");
+    MPI_Comm_size(comm_t, &size);
+
+    std::set<int> union_ids; // source and target ids in world_comm
+    union_ids.insert(src->getProcIDs().begin(),src->getProcIDs().end());
+    union_ids.insert(tgt->getProcIDs().begin(),tgt->getProcIDs().end());
+    if(union_ids.size()!=size)
+      throw INTERP_KERNEL::Exception("DisjointDEC constructor: source_ids and target_ids do not form a partition of the communicator! Restrain the world communicator passed to MPIProcessorGroup ctor.");
   }
 
   void DisjointDEC::setNature(NatureOfField nature)
@@ -212,7 +252,7 @@ namespace ParaMEDMEM
     will be updated by a recvData() call.
     Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
   */
-  void DisjointDEC::attachLocalField(const ParaFIELD* field, bool ownPt) 
+  void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt)
   {
     if(!isInUnion())
       return ;
@@ -234,7 +274,7 @@ namespace ParaMEDMEM
     and sent appropriately to the other side.
   */
 
-  void DisjointDEC::attachLocalField(MEDCouplingFieldDouble* field) 
+  void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field)
   {
     if(!isInUnion())
       return ;
@@ -259,35 +299,15 @@ namespace ParaMEDMEM
     Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
     The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields :
     - a ICoCo::MEDField, that is created from a MEDCoupling structure
-    - a ICOCo::TrioField, that is created from tables extracted from a TRIO-U structure.
     
   */
-  void DisjointDEC::attachLocalField(const ICoCo::Field* field)
+  void DisjointDEC::attachLocalField(const ICoCo::MEDField *field)
   {
     if(!isInUnion())
       return ;
-    const ICoCo::MEDField* medfield=dynamic_cast<const ICoCo::MEDField*> (field);
-    if(medfield !=0)
-      {
-        attachLocalField(medfield->getField());
-        return;
-      }
-    const ICoCo::TrioField* triofield=dynamic_cast<const ICoCo::TrioField*> (field);
-    if (triofield !=0)
-      {
-        /* Strange part of code localgroup not used !
-        ProcessorGroup* localgroup;
-        if (_source_group->containsMyRank())
-          localgroup=_source_group;
-        else
-        localgroup=_target_group;*/
-        delete _icoco_field;
-        
-        _icoco_field=new ICoCo::MEDField(*const_cast<ICoCo::TrioField* >(triofield));
-        attachLocalField(_icoco_field);
-        return;
-      }
-    throw INTERP_KERNEL::Exception("incompatible field type");
+    if(!field)
+      throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !");
+    attachLocalField(field->getField());
   }
   
   /*!
@@ -331,7 +351,6 @@ namespace ParaMEDMEM
           }
       }
   }
-  /*! @} */
 
   bool DisjointDEC::isInSourceSide() const
   {