Salome HOME
Move medtool folder to MED base repository
[modules/med.git] / medtool / src / ParaMEDMEM / MPIProcessorGroup.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "ProcessorGroup.hxx"
21 #include "MPIProcessorGroup.hxx"
22 #include "CommInterface.hxx"
23 #include "InterpolationUtils.hxx"
24
25 #include <iostream>
26 #include <set>
27 #include <algorithm>
28 #include "mpi.h"
29
30 using namespace std;
31
32
33 namespace ParaMEDMEM
34 {
35   /*!
36    * \anchor MPIProcessorGroup-det
37    * \class MPIProcessorGroup
38    *
39    * \section processor_group_overview Overview
40    * The MPIProcessorGroup class is used to set up processor groups that help to define
41    * the MPI topology of the couplings. They can be set up in various ways, the most common being
42    * the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast)
43    * constructor.
44    *
45    * The following code excerpt creates two processor groups on respectively 3 and 2 processors.
46    \verbatim
47    int main()
48    {
49    MPI_Init(&argc,&argv);
50    CommInterface comm_interface;
51    MPIProcessorGroup codeA_group(comm_interface, 0, 2);  // groups processors 0, 1 and 2
52    MPIProcessorGroup codeB_group(comm_interface, 3, 4);  // groups processors 3 and 4
53
54    ...
55    }
56    \endverbatim
57   */
58
59
60   /*! 
61    * Creates a processor group that is based on all the
62    MPI_COMM_WORLD processor.This routine must be called by all processors in MPI_COMM_WORLD.
63    \param interface CommInterface object giving access to the MPI
64    communication layer
65   */
66   MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface):
67     ProcessorGroup(interface),_world_comm(MPI_COMM_WORLD)
68   {
69     _comm=_world_comm;
70     _comm_interface.commGroup(_world_comm, &_group);
71     int size;
72     _comm_interface.commSize(_world_comm,&size);
73     for (int i=0; i<size; i++)
74       _proc_ids.insert(i);
75
76   }
77
78   /*! Creates a processor group that is based on the processors included in \a proc_ids.
79     This routine must be called by all processors in MPI_COMM_WORLD.
80
81     \param interface CommInterface object giving access to the MPI
82     communication layer
83     \param proc_ids set of ids that are to be integrated in the group. The ids number are 
84     to be understood in terms of MPI_COMM_WORLD ranks.
85   */
86
87   MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface, set<int> proc_ids, const MPI_Comm& world_comm):
88     ProcessorGroup(interface, proc_ids), _world_comm(world_comm)
89   {
90     updateMPISpecificAttributes();
91   }
92
93
94   void MPIProcessorGroup::updateMPISpecificAttributes()
95   {
96     //Creation of a communicator 
97     MPI_Group group_world;
98   
99     int size_world;
100     _comm_interface.commSize(_world_comm,&size_world);
101     int rank_world;
102     _comm_interface.commRank(_world_comm,&rank_world);
103     _comm_interface.commGroup(_world_comm, &group_world);
104
105     int* ranks=new int[_proc_ids.size()];
106    
107     // copying proc_ids in ranks
108     copy<set<int>::const_iterator,int*> (_proc_ids.begin(), _proc_ids.end(), ranks);
109     for (int i=0; i< (int)_proc_ids.size();i++)
110       if (ranks[i]>size_world-1)
111         {
112           delete[] ranks;
113           _comm_interface.groupFree(&group_world);  // MPI_Group is a C structure and won't get de-allocated automatically?
114           throw INTERP_KERNEL::Exception("invalid rank in set<int> argument of MPIProcessorGroup constructor");
115         }
116       
117     _comm_interface.groupIncl(group_world, _proc_ids.size(), ranks, &_group);
118   
119     _comm_interface.commCreate(_world_comm, _group, &_comm);
120
121     // clean-up
122     delete[] ranks;
123     _comm_interface.groupFree(&group_world);  // MPI_Group is a C structure and won't get de-allocated automatically?
124   }
125
126   /*! Creates a processor group that is based on the processors between \a pstart and \a pend.
127     This routine must be called by all processors in MPI_COMM_WORLD.
128
129     \param comm_interface CommInterface object giving access to the MPI
130     communication layer
131     \param pstart id in MPI_COMM_WORLD of the first processor in the group
132     \param pend id in MPI_COMM_WORLD of the last processor in the group
133   */
134   MPIProcessorGroup::MPIProcessorGroup (const CommInterface& comm_interface, int pstart, int pend, const MPI_Comm& world_comm): ProcessorGroup(comm_interface,pstart,pend),_world_comm(world_comm)
135   {
136     //Creation of a communicator 
137     MPI_Group group_world;
138   
139     int size_world;
140     _comm_interface.commSize(_world_comm,&size_world);
141     int rank_world;
142     _comm_interface.commRank(_world_comm,&rank_world);
143     _comm_interface.commGroup(_world_comm, &group_world);
144
145     if (pend>size_world-1 || pend <pstart || pstart<0)
146       {
147         _comm_interface.groupFree(&group_world);
148         throw INTERP_KERNEL::Exception("invalid argument in MPIProcessorGroup constructor (comm,pfirst,plast)");
149       }
150     int nprocs=pend-pstart+1;
151     int* ranks=new int[nprocs];
152     for (int i=pstart; i<=pend;i++)
153       {
154         ranks[i-pstart]=i;
155       }
156
157     _comm_interface.groupIncl(group_world, nprocs, ranks, &_group);
158   
159     _comm_interface.commCreate(_world_comm, _group, &_comm);
160
161     // clean-up
162     delete[] ranks;
163     _comm_interface.groupFree(&group_world);  // MPI_Group is a C structured and won't get de-allocated automatically?
164   }
165
166   MPIProcessorGroup::MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids) :
167     ProcessorGroup(proc_group.getCommInterface()),_world_comm(MPI_COMM_WORLD)
168   {
169     cout << "MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids)" <<endl;
170     cout << "Not implemented yet !"<<endl;
171     exit(1);
172   }
173
174   MPIProcessorGroup::MPIProcessorGroup(const MPIProcessorGroup& other):ProcessorGroup(other),_world_comm(other._world_comm)
175   {
176     updateMPISpecificAttributes();
177   }
178
179   MPIProcessorGroup::~MPIProcessorGroup()
180   {
181     _comm_interface.groupFree(&_group);
182     if (_comm!=_world_comm && _comm !=MPI_COMM_NULL)
183       _comm_interface.commFree(&_comm);
184   
185   }
186
187   /*! Translation of the rank id between two processor groups. This method translates rank \a rank
188     on the current processor group to the rank on group pointed by \a group.
189     \param group group from which the rank is expected
190     \param rank rank on group \a group of the processor which is to be translated
191     \return rank on local group
192   */
193   int MPIProcessorGroup::translateRank(const ProcessorGroup* group, int rank) const
194   {
195     const MPIProcessorGroup* targetgroup=dynamic_cast<const MPIProcessorGroup*>(group);
196     int local_rank;
197     MPI_Group_translate_ranks(targetgroup->_group, 1, &rank, _group, &local_rank);
198     return local_rank;
199   }
200   
201   /*!Creates a processor group that is the complement of the current group 
202     inside MPI_COMM_WORLD
203     \return pointer to the new ProcessorGroup structure.
204   */
205   ProcessorGroup* MPIProcessorGroup::createComplementProcGroup() const
206   {
207     set <int> procs;
208     int world_size=_comm_interface.worldSize();
209     for (int i=0; i<world_size; i++)
210       procs.insert(i);
211     for (set<int>::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++)
212       procs.erase(*iter);
213     
214     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
215     
216   }
217
218   ProcessorGroup *MPIProcessorGroup::deepCpy() const
219   {
220     return new MPIProcessorGroup(*this);
221   }
222
223   /*!Adding processors of group \a group to local group.
224     \param group group that is to be fused with current group
225     \return new group formed by the fusion of local group and \a group.
226   */
227   ProcessorGroup*  MPIProcessorGroup::fuse (const ProcessorGroup& group) const
228   {
229     set <int> procs = _proc_ids;
230     const set<int>& distant_proc_ids = group.getProcIDs();
231     for (set<int>::const_iterator iter=distant_proc_ids.begin(); iter!=distant_proc_ids.end(); iter++)
232       {
233         procs.insert(*iter);
234       }
235     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
236   }
237
238   int MPIProcessorGroup::myRank() const
239   { 
240     int rank;
241     MPI_Comm_rank(_comm,&rank);
242     return rank;
243   }
244   
245   ProcessorGroup* MPIProcessorGroup::createProcGroup() const
246   {
247     set <int> procs;
248     for (set<int>::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++)
249       procs.insert(*iter);
250   
251     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
252
253   }
254 }