Salome HOME
ParaMEDMemTest: bug fix: dangling pointer on stack.
[tools/medcoupling.git] / src / ParaMEDMEM / DisjointDEC.cxx
index 365e8d6aaa0989a9936146c7f1187c5a116db847..178f296f65cb37019683590b913a922bb7822b1a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D
+// Copyright (C) 2007-2020  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
 
 namespace MEDCoupling
 {
-
-  /*!
-   * \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),
@@ -73,6 +43,7 @@ namespace MEDCoupling
       _owns_groups(false),
       _union_comm(MPI_COMM_NULL)
   {
+    checkPartitionGroup();
     _union_group = source_group.fuse(target_group);  
   }
   
@@ -101,16 +72,29 @@ namespace MEDCoupling
   void DisjointDEC::copyInstance(const DisjointDEC& other)
   {
     DEC::copyFrom(other);
-    if(other._target_group)
+    if (other._union_comm != MPI_COMM_NULL)
       {
-        _target_group=other._target_group->deepCpy();
-        _owns_groups=true;
-      }
-    if(other._source_group)
-      {
-        _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);
   }
@@ -119,9 +103,9 @@ namespace MEDCoupling
                            const std::set<int>& target_ids,
                            const MPI_Comm& world_comm):
      _local_field(0),
+     _comm_interface(0),
      _owns_field(false),
      _owns_groups(true),
-     _comm_interface(0),
      _union_comm(MPI_COMM_NULL)
   {
     MEDCoupling::CommInterface comm;
@@ -137,7 +121,7 @@ namespace MEDCoupling
     // Create a communicator on these procs
     MPI_Group union_group,world_group;
     comm.commGroup(world_comm,&world_group);
-    comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
+    comm.groupIncl(world_group,(int)union_ids.size(),union_ranks_world,&union_group);
     comm.commCreate(world_comm,union_group,&_union_comm);
     delete[] union_ranks_world;
     if (_union_comm==MPI_COMM_NULL)
@@ -157,8 +141,8 @@ namespace MEDCoupling
     int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm
     std::copy(target_ids.begin(), target_ids.end(),target_ranks_world);
     int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm
-    MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union);
-    MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union);
+    MPI_Group_translate_ranks(world_group,(int)source_ids.size(),source_ranks_world,union_group,source_ranks_union);
+    MPI_Group_translate_ranks(world_group,(int)target_ids.size(),target_ranks_world,union_group,target_ranks_union);
     std::set<int> source_ids_union;
     for (int i=0;i<(int)source_ids.size();i++)
       source_ids_union.insert(source_ranks_union[i]);
@@ -205,6 +189,28 @@ namespace MEDCoupling
       _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 completely 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((int)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)
   {
     if(_local_field)
@@ -295,7 +301,7 @@ namespace MEDCoupling
   void DisjointDEC::renormalizeTargetField(bool isWAbs)
   {
     if (_source_group->containsMyRank())
-      for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
+      for (int icomp=0; icomp<(int)_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
         {
           double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
           double source_norm = total_norm;
@@ -304,7 +310,7 @@ namespace MEDCoupling
         }
     if (_target_group->containsMyRank())
       {
-        for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
+        for (int icomp=0; icomp<(int)_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
           {
             double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
             double source_norm=total_norm;
@@ -337,7 +343,7 @@ namespace MEDCoupling
     return _union_group->containsMyRank();
   }
 
-  void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception)
+  void DisjointDEC::compareFieldAndMethod() const
   {
     if (_local_field)
       {