Salome HOME
[bos #38048] [EDF] (2023-T3) PARAMEDMEM Ergonomy.
[tools/medcoupling.git] / src / ParaMEDMEM / MPIProcessorGroup.cxx
old mode 100755 (executable)
new mode 100644 (file)
index cb96a69..1e40fd6
@@ -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
 
 using namespace std;
 
-/*! \defgroup processor_group Processor Groups
- * 
- * \section processor_group_overview Overview
- * The MPIProcessorGroup class is used to set up processor groups that help to define
- * the MPI topology of the couplings. They can be set up in various ways, the most common being
- * the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast) 
- * constructor.
- * 
- * The following code excerpt creates two processor groups on respectively 3 and 2 processors.
- \verbatim
- int main()
- {
- MPI_Init(&argc,&argv);
- CommInterface comm_interface;
- MPIProcessorGroup codeA_group(comm_interface, 0, 2);
- MPIProcessorGroup codeB_group(comm_interface, 3, 4);
-   
- ...
- }
- \endverbatim
-*/
-
 
-namespace ParaMEDMEM
+namespace MEDCoupling
 {
-  /*! 
-    \addtogroup processor_group
-    @{ 
+  /*!
+   \anchor MPIProcessorGroup-det
+   \class MPIProcessorGroup
+
+   The MPIProcessorGroup class represents a set of distinct "processors" (computation nodes)
+   in a MPI code. It is used to define the MPI topology of code couplings.
+
+   Groups can be set up in various ways, the most common being
+   the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast)
+   constructor.
+
+   The following code excerpt creates two processor groups on respectively 3 and 2 processors.
+   \verbatim
+   int main()
+   {
+   MPI_Init(&argc,&argv);
+   CommInterface comm_interface;
+   MPIProcessorGroup codeA_group(comm_interface, 0, 2);  // groups processors 0, 1 and 2
+   MPIProcessorGroup codeB_group(comm_interface, 3, 4);  // groups processors 3 and 4
+
+   ...
+   }
+   \endverbatim
   */
 
+
   /*! 
    * Creates a processor group that is based on all the
-   MPI_COMM_WORLD processor.This routine must be called by all processors in MPI_COMM_WORLD.
+   processors of MPI_COMM_WORLD .This routine must be called by all processors in MPI_COMM_WORLD.
    \param interface CommInterface object giving access to the MPI
    communication layer
   */
@@ -87,7 +86,24 @@ namespace ParaMEDMEM
   */
 
   MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface, set<int> proc_ids, const MPI_Comm& world_comm):
-    ProcessorGroup(interface, proc_ids),_world_comm(world_comm)
+    ProcessorGroup(interface, proc_ids), _world_comm(world_comm)
+  {
+    updateMPISpecificAttributes();
+  }
+
+
+  /*! Creates a processor group that is based on the processors included in \a proc_ids_by_name[name].
+    This routine must be called by all processors in MPI_COMM_WORLD.
+
+    \param interface CommInterface object giving access to the MPI
+    communication layer
+    \param proc_ids_by_name a map defining a relation between a name and a set of ids that are to be integrated in the group. 
+    The ids number are to be understood in terms of MPI_COMM_WORLD ranks.
+    \param simCodeTag identifier of the group
+  */
+
+  MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface, std::map<std::string,std::set<int>> proc_ids_by_name, const std::string& simCodeTag, const MPI_Comm& world_comm):
+    ProcessorGroup(interface, proc_ids_by_name, simCodeTag), _world_comm(world_comm)
   {
     updateMPISpecificAttributes();
   }
@@ -110,12 +126,19 @@ namespace ParaMEDMEM
     copy<set<int>::const_iterator,int*> (_proc_ids.begin(), _proc_ids.end(), ranks);
     for (int i=0; i< (int)_proc_ids.size();i++)
       if (ranks[i]>size_world-1)
-        throw INTERP_KERNEL::Exception("invalid rank in set<int> argument of MPIProcessorGroup constructor");
+        {
+          delete[] ranks;
+          _comm_interface.groupFree(&group_world);  // MPI_Group is a C structure and won't get de-allocated automatically?
+          throw INTERP_KERNEL::Exception("invalid rank in set<int> argument of MPIProcessorGroup constructor");
+        }
       
-    _comm_interface.groupIncl(group_world, _proc_ids.size(), ranks, &_group);
+    _comm_interface.groupIncl(group_world, (int)_proc_ids.size(), ranks, &_group);
   
     _comm_interface.commCreate(_world_comm, _group, &_comm);
+
+    // clean-up
     delete[] ranks;
+    _comm_interface.groupFree(&group_world);  // MPI_Group is a C structure and won't get de-allocated automatically?
   }
 
   /*! Creates a processor group that is based on the processors between \a pstart and \a pend.
@@ -138,7 +161,10 @@ namespace ParaMEDMEM
     _comm_interface.commGroup(_world_comm, &group_world);
 
     if (pend>size_world-1 || pend <pstart || pstart<0)
-      throw INTERP_KERNEL::Exception("invalid argument in MPIProcessorGroup constructor (comm,pfirst,plast)");
+      {
+        _comm_interface.groupFree(&group_world);
+        throw INTERP_KERNEL::Exception("invalid argument in MPIProcessorGroup constructor (comm,pfirst,plast)");
+      }
     int nprocs=pend-pstart+1;
     int* ranks=new int[nprocs];
     for (int i=pstart; i<=pend;i++)
@@ -149,36 +175,44 @@ namespace ParaMEDMEM
     _comm_interface.groupIncl(group_world, nprocs, ranks, &_group);
   
     _comm_interface.commCreate(_world_comm, _group, &_comm);
+
+    // clean-up
     delete[] ranks;
+    _comm_interface.groupFree(&group_world);  // MPI_Group is a C structured and won't get de-allocated automatically?
   }
-  /*!
-    @}
-  */
 
   MPIProcessorGroup::MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids) :
-    ProcessorGroup(proc_group.getCommInterface()),_world_comm(MPI_COMM_WORLD)
+    ProcessorGroup(proc_group.getCommInterface()),
+    _world_comm(MPI_COMM_WORLD), _group(MPI_GROUP_NULL), _comm(MPI_COMM_NULL)
   {
     cout << "MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids)" <<endl;
     cout << "Not implemented yet !"<<endl;
     exit(1);
   }
 
-  MPIProcessorGroup::MPIProcessorGroup(const MPIProcessorGroup& other):ProcessorGroup(other),_world_comm(other._world_comm)
+  MPIProcessorGroup::MPIProcessorGroup(const MPIProcessorGroup& other):
+      ProcessorGroup(other),_world_comm(other._world_comm)
   {
     updateMPISpecificAttributes();
   }
 
   MPIProcessorGroup::~MPIProcessorGroup()
   {
-    _comm_interface.groupFree(&_group);
+    release();
+  }
+
+  /** Destructor involves MPI operations: make sure this is accessible from a proper
+   * method for Python wrapping.
+   */
+  void MPIProcessorGroup::release()
+  {
+    if (_group != MPI_GROUP_EMPTY)
+      _comm_interface.groupFree(&_group);
+    _group = MPI_GROUP_EMPTY;
     if (_comm!=_world_comm && _comm !=MPI_COMM_NULL)
       _comm_interface.commFree(&_comm);
-  
+    _comm = MPI_COMM_NULL;
   }
-  /*!
-    \addtogroup processor_group
-    @{
-  */
 
   /*! Translation of the rank id between two processor groups. This method translates rank \a rank
     on the current processor group to the rank on group pointed by \a group.
@@ -211,7 +245,7 @@ namespace ParaMEDMEM
     
   }
 
-  ProcessorGroup *MPIProcessorGroup::deepCpy() const
+  MPIProcessorGroup *MPIProcessorGroup::deepCopy() const
   {
     return new MPIProcessorGroup(*this);
   }
@@ -238,9 +272,6 @@ namespace ParaMEDMEM
     return rank;
   }
   
-  /*!
-    @}
-  */
   ProcessorGroup* MPIProcessorGroup::createProcGroup() const
   {
     set <int> procs;