Salome HOME
Synchronize adm files
[modules/med.git] / src / ParaMEDMEM / MPIProcessorGroup.cxx
1 // Copyright (C) 2007-2014  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 /*! \defgroup processor_group Processor Groups
33  * 
34  * \section processor_group_overview Overview
35  * The MPIProcessorGroup class is used to set up processor groups that help to define
36  * the MPI topology of the couplings. They can be set up in various ways, the most common being
37  * the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast) 
38  * constructor.
39  * 
40  * The following code excerpt creates two processor groups on respectively 3 and 2 processors.
41  \verbatim
42  int main()
43  {
44  MPI_Init(&argc,&argv);
45  CommInterface comm_interface;
46  MPIProcessorGroup codeA_group(comm_interface, 0, 2);
47  MPIProcessorGroup codeB_group(comm_interface, 3, 4);
48    
49  ...
50  }
51  \endverbatim
52 */
53
54
55 namespace ParaMEDMEM
56 {
57   /*! 
58     \addtogroup processor_group
59     @{ 
60   */
61
62   /*! 
63    * Creates a processor group that is based on all the
64    MPI_COMM_WORLD processor.This routine must be called by all processors in MPI_COMM_WORLD.
65    \param interface CommInterface object giving access to the MPI
66    communication layer
67   */
68   MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface):
69     ProcessorGroup(interface),_world_comm(MPI_COMM_WORLD)
70   {
71     _comm=_world_comm;
72     _comm_interface.commGroup(_world_comm, &_group);
73     int size;
74     _comm_interface.commSize(_world_comm,&size);
75     for (int i=0; i<size; i++)
76       _proc_ids.insert(i);
77
78   }
79
80   /*! Creates a processor group that is based on the processors included in \a proc_ids.
81     This routine must be called by all processors in MPI_COMM_WORLD.
82
83     \param interface CommInterface object giving access to the MPI
84     communication layer
85     \param proc_ids set of ids that are to be integrated in the group. The ids number are 
86     to be understood in terms of MPI_COMM_WORLD ranks.
87   */
88
89   MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface, set<int> proc_ids, const MPI_Comm& world_comm):
90     ProcessorGroup(interface, proc_ids),_world_comm(world_comm)
91   {
92     updateMPISpecificAttributes();
93   }
94
95
96   void MPIProcessorGroup::updateMPISpecificAttributes()
97   {
98     //Creation of a communicator 
99     MPI_Group group_world;
100   
101     int size_world;
102     _comm_interface.commSize(_world_comm,&size_world);
103     int rank_world;
104     _comm_interface.commRank(_world_comm,&rank_world);
105     _comm_interface.commGroup(_world_comm, &group_world);
106
107     int* ranks=new int[_proc_ids.size()];
108    
109     // copying proc_ids in ranks
110     copy<set<int>::const_iterator,int*> (_proc_ids.begin(), _proc_ids.end(), ranks);
111     for (int i=0; i< (int)_proc_ids.size();i++)
112       if (ranks[i]>size_world-1)
113         throw INTERP_KERNEL::Exception("invalid rank in set<int> argument of MPIProcessorGroup constructor");
114       
115     _comm_interface.groupIncl(group_world, _proc_ids.size(), ranks, &_group);
116   
117     _comm_interface.commCreate(_world_comm, _group, &_comm);
118     delete[] ranks;
119   }
120
121   /*! Creates a processor group that is based on the processors between \a pstart and \a pend.
122     This routine must be called by all processors in MPI_COMM_WORLD.
123
124     \param comm_interface CommInterface object giving access to the MPI
125     communication layer
126     \param pstart id in MPI_COMM_WORLD of the first processor in the group
127     \param pend id in MPI_COMM_WORLD of the last processor in the group
128   */
129   MPIProcessorGroup::MPIProcessorGroup (const CommInterface& comm_interface, int pstart, int pend, const MPI_Comm& world_comm): ProcessorGroup(comm_interface,pstart,pend),_world_comm(world_comm)
130   {
131     //Creation of a communicator 
132     MPI_Group group_world;
133   
134     int size_world;
135     _comm_interface.commSize(_world_comm,&size_world);
136     int rank_world;
137     _comm_interface.commRank(_world_comm,&rank_world);
138     _comm_interface.commGroup(_world_comm, &group_world);
139
140     if (pend>size_world-1 || pend <pstart || pstart<0)
141       throw INTERP_KERNEL::Exception("invalid argument in MPIProcessorGroup constructor (comm,pfirst,plast)");
142     int nprocs=pend-pstart+1;
143     int* ranks=new int[nprocs];
144     for (int i=pstart; i<=pend;i++)
145       {
146         ranks[i-pstart]=i;
147       }
148
149     _comm_interface.groupIncl(group_world, nprocs, ranks, &_group);
150   
151     _comm_interface.commCreate(_world_comm, _group, &_comm);
152     delete[] ranks;
153   }
154   /*!
155     @}
156   */
157
158   MPIProcessorGroup::MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids) :
159     ProcessorGroup(proc_group.getCommInterface()),_world_comm(MPI_COMM_WORLD)
160   {
161     cout << "MPIProcessorGroup (const ProcessorGroup& proc_group, set<int> proc_ids)" <<endl;
162     cout << "Not implemented yet !"<<endl;
163     exit(1);
164   }
165
166   MPIProcessorGroup::MPIProcessorGroup(const MPIProcessorGroup& other):ProcessorGroup(other),_world_comm(other._world_comm)
167   {
168     updateMPISpecificAttributes();
169   }
170
171   MPIProcessorGroup::~MPIProcessorGroup()
172   {
173     _comm_interface.groupFree(&_group);
174     if (_comm!=_world_comm && _comm !=MPI_COMM_NULL)
175       _comm_interface.commFree(&_comm);
176   
177   }
178   /*!
179     \addtogroup processor_group
180     @{
181   */
182
183   /*! Translation of the rank id between two processor groups. This method translates rank \a rank
184     on the current processor group to the rank on group pointed by \a group.
185     \param group group from which the rank is expected
186     \param rank rank on group \a group of the processor which is to be translated
187     \return rank on local group
188   */
189   int MPIProcessorGroup::translateRank(const ProcessorGroup* group, int rank) const
190   {
191     const MPIProcessorGroup* targetgroup=dynamic_cast<const MPIProcessorGroup*>(group);
192     int local_rank;
193     MPI_Group_translate_ranks(targetgroup->_group, 1, &rank, _group, &local_rank);
194     return local_rank;
195   }
196   
197   /*!Creates a processor group that is the complement of the current group 
198     inside MPI_COMM_WORLD
199     \return pointer to the new ProcessorGroup structure.
200   */
201   ProcessorGroup* MPIProcessorGroup::createComplementProcGroup() const
202   {
203     set <int> procs;
204     int world_size=_comm_interface.worldSize();
205     for (int i=0; i<world_size; i++)
206       procs.insert(i);
207     for (set<int>::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++)
208       procs.erase(*iter);
209     
210     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
211     
212   }
213
214   ProcessorGroup *MPIProcessorGroup::deepCpy() const
215   {
216     return new MPIProcessorGroup(*this);
217   }
218
219   /*!Adding processors of group \a group to local group.
220     \param group group that is to be fused with current group
221     \return new group formed by the fusion of local group and \a group.
222   */
223   ProcessorGroup*  MPIProcessorGroup::fuse (const ProcessorGroup& group) const
224   {
225     set <int> procs = _proc_ids;
226     const set<int>& distant_proc_ids = group.getProcIDs();
227     for (set<int>::const_iterator iter=distant_proc_ids.begin(); iter!=distant_proc_ids.end(); iter++)
228       {
229         procs.insert(*iter);
230       }
231     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
232   }
233
234   int MPIProcessorGroup::myRank() const
235   { 
236     int rank;
237     MPI_Comm_rank(_comm,&rank);
238     return rank;
239   }
240   
241   /*!
242     @}
243   */
244   ProcessorGroup* MPIProcessorGroup::createProcGroup() const
245   {
246     set <int> procs;
247     for (set<int>::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++)
248       procs.insert(*iter);
249   
250     return new MPIProcessorGroup(_comm_interface, procs, _world_comm);
251
252   }
253 }