Salome HOME
Synchronize adm files
[modules/med.git] / src / ParaMEDMEM / MxN_Mapping.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 "CommInterface.hxx" 
21 #include "ProcessorGroup.hxx"
22 #include "MPIProcessorGroup.hxx"
23 #include "MPIAccessDEC.hxx"
24 #include "MxN_Mapping.hxx"
25
26 using namespace std;
27
28 namespace ParaMEDMEM
29 {
30   MxN_Mapping::MxN_Mapping()
31   {
32   }
33
34
35   MxN_Mapping::MxN_Mapping(const ProcessorGroup& source_group, const ProcessorGroup& target_group,const DECOptions& dec_options)
36     : DECOptions(dec_options),_union_group(source_group.fuse(target_group))
37   {
38     _access_DEC = new MPIAccessDEC(source_group,target_group,getAsynchronous());
39     _access_DEC->setTimeInterpolator(getTimeInterpolationMethod());
40     _send_proc_offsets.resize(_union_group->size()+1,0);
41     _recv_proc_offsets.resize(_union_group->size()+1,0);
42   
43   }
44
45   MxN_Mapping::~MxN_Mapping()
46   {
47     delete _union_group;
48     delete _access_DEC;
49   }
50
51
52   /*!
53     Method registering a new element for correspondence with a distant element
54     \param distant_proc proc rank of the distant processor (in terms of the union group)
55     \param distant_element id of the element on the distant processor
56   */
57   void MxN_Mapping::addElementFromSource(int distant_proc, int distant_element)
58   {
59     _sending_ids.push_back(make_pair(distant_proc,distant_element));
60     for (int i=distant_proc; i<_union_group->size(); i++)
61       _send_proc_offsets[i+1]++;
62   }
63
64   void MxN_Mapping::initialize()
65   {
66     _sending_ids.clear();
67     std::fill(_send_proc_offsets.begin(),_send_proc_offsets.end(),0);
68   }
69
70   void MxN_Mapping::prepareSendRecv()
71   {
72     CommInterface comm_interface=_union_group->getCommInterface();
73     // sending count pattern
74     int* nbsend=new int[_union_group->size()];
75     int* nbrecv=new int[_union_group->size()];
76     for (int i=0; i<_union_group->size(); i++)
77       {
78         nbsend[i]=_send_proc_offsets[i+1]-_send_proc_offsets[i];
79       }
80   
81     MPIProcessorGroup* group = static_cast<MPIProcessorGroup*>(_union_group);
82     const MPI_Comm* comm=group->getComm();
83     comm_interface.allToAll(nbsend, 1, MPI_INT,
84                             nbrecv, 1, MPI_INT,
85                             *comm);
86          
87     for (int i=0; i<_union_group->size(); i++)
88       {
89         for (int j=i+1;j<_union_group->size()+1; j++)
90           _recv_proc_offsets[j]+=nbrecv[i];
91     
92       } 
93
94     delete[] nbsend;
95     delete[] nbrecv;
96
97     _recv_ids.resize(_recv_proc_offsets[_union_group->size()]);
98     int* isendbuf=0;
99     int* irecvbuf=0;
100     if (_sending_ids.size()>0)
101       isendbuf = new int[_sending_ids.size()];
102     if (_recv_ids.size()>0)  
103       irecvbuf = new int[_recv_ids.size()];
104     int* sendcounts = new int[_union_group->size()];
105     int* senddispls=new int[_union_group->size()];
106     int* recvcounts=new int[_union_group->size()];
107     int* recvdispls=new int[_union_group->size()];
108     for (int i=0; i< _union_group->size(); i++)
109       {
110         sendcounts[i]=_send_proc_offsets[i+1]-_send_proc_offsets[i];
111         senddispls[i]=_send_proc_offsets[i];
112         recvcounts[i]=_recv_proc_offsets[i+1]-_recv_proc_offsets[i];
113         recvdispls[i]=_recv_proc_offsets[i];
114       }
115     vector<int> offsets = _send_proc_offsets;
116     for (int i=0; i<(int)_sending_ids.size();i++)
117       {
118         int iproc = _sending_ids[i].first;
119         isendbuf[offsets[iproc]]=_sending_ids[i].second;
120         offsets[iproc]++;
121       }
122     comm_interface.allToAllV(isendbuf, sendcounts, senddispls, MPI_INT,
123                              irecvbuf, recvcounts, recvdispls, MPI_INT,
124                              *comm);
125                            
126     for (int i=0; i< _recv_proc_offsets[_union_group->size()]; i++)
127       _recv_ids[i]=irecvbuf[i];                           
128  
129     if (_sending_ids.size()>0)
130       delete[] isendbuf;
131     if (_recv_ids.size()>0)  
132       delete[] irecvbuf;
133     delete[] sendcounts;
134     delete[]recvcounts;
135     delete[]senddispls;
136     delete[] recvdispls;
137   }
138
139   /*! Exchanging field data between two groups of processes
140    * 
141    * \param field MEDCoupling field containing the values to be sent
142    * 
143    * The ids that were defined by addElementFromSource method
144    * are sent.
145    */ 
146   void MxN_Mapping::sendRecv(double* sendfield, MEDCouplingFieldDouble& field) const 
147   {
148     CommInterface comm_interface=_union_group->getCommInterface();
149     const MPIProcessorGroup* group = static_cast<const MPIProcessorGroup*>(_union_group);
150  
151     int nbcomp=field.getArray()->getNumberOfComponents();
152     double* sendbuf=0;
153     double* recvbuf=0;
154     if (_sending_ids.size() >0)
155       sendbuf = new double[_sending_ids.size()*nbcomp];
156     if (_recv_ids.size()>0)
157       recvbuf = new double[_recv_ids.size()*nbcomp];
158     
159     int* sendcounts = new int[_union_group->size()];
160     int* senddispls=new int[_union_group->size()];
161     int* recvcounts=new int[_union_group->size()];
162     int* recvdispls=new int[_union_group->size()];
163   
164     for (int i=0; i< _union_group->size(); i++)
165       {
166         sendcounts[i]=nbcomp*(_send_proc_offsets[i+1]-_send_proc_offsets[i]);
167         senddispls[i]=nbcomp*(_send_proc_offsets[i]);
168         recvcounts[i]=nbcomp*(_recv_proc_offsets[i+1]-_recv_proc_offsets[i]);
169         recvdispls[i]=nbcomp*(_recv_proc_offsets[i]);
170       }
171     //building the buffer of the elements to be sent
172     vector<int> offsets = _send_proc_offsets;
173
174     for (int i=0; i<(int)_sending_ids.size();i++)
175       { 
176         int iproc = _sending_ids[i].first;
177         for (int icomp=0; icomp<nbcomp; icomp++)
178           sendbuf[offsets[iproc]*nbcomp+icomp]=sendfield[i*nbcomp+icomp];
179         offsets[iproc]++;
180       }
181   
182     //communication phase
183     switch (getAllToAllMethod())
184       {
185       case Native:
186         {
187           const MPI_Comm* comm = group->getComm();
188           comm_interface.allToAllV(sendbuf, sendcounts, senddispls, MPI_DOUBLE,
189                                    recvbuf, recvcounts, recvdispls, MPI_DOUBLE,
190                                    *comm);
191         }
192         break;
193       case PointToPoint:
194         _access_DEC->allToAllv(sendbuf, sendcounts, senddispls, MPI_DOUBLE,
195                               recvbuf, recvcounts, recvdispls, MPI_DOUBLE);
196         break;
197       }
198   
199     //setting the received values in the field
200     DataArrayDouble *fieldArr=field.getArray();
201     double* recvptr=recvbuf;                         
202     for (int i=0; i< _recv_proc_offsets[_union_group->size()]; i++)
203       {
204         for (int icomp=0; icomp<nbcomp; icomp++)
205           {
206             double temp = fieldArr->getIJ(_recv_ids[i],icomp);
207             fieldArr->setIJ(_recv_ids[i],icomp,temp+*recvptr);
208             recvptr++;
209           }
210       }   
211     if (sendbuf!=0 && getAllToAllMethod()== Native)
212       delete[] sendbuf;
213     if (recvbuf !=0)
214       delete[] recvbuf;
215     delete[] sendcounts;
216     delete[] recvcounts;
217     delete[] senddispls; 
218     delete[] recvdispls;
219   
220   }
221
222   /*! Exchanging field data between two groups of processes
223    * 
224    * \param field MEDCoupling field containing the values to be sent
225    * 
226    * The ids that were defined by addElementFromSource method
227    * are sent.
228    */ 
229   void MxN_Mapping::reverseSendRecv(double* recvfield, MEDCouplingFieldDouble& field) const 
230   {
231     CommInterface comm_interface=_union_group->getCommInterface();
232     const MPIProcessorGroup* group = static_cast<const MPIProcessorGroup*>(_union_group);
233
234     int nbcomp=field.getArray()->getNumberOfComponents();
235     double* sendbuf=0;
236     double* recvbuf=0;
237     if (_recv_ids.size() >0)
238       sendbuf = new double[_recv_ids.size()*nbcomp];
239     if (_sending_ids.size()>0)
240       recvbuf = new double[_sending_ids.size()*nbcomp];
241
242     int* sendcounts = new int[_union_group->size()];
243     int* senddispls=new int[_union_group->size()];
244     int* recvcounts=new int[_union_group->size()];
245     int* recvdispls=new int[_union_group->size()];
246
247     for (int i=0; i< _union_group->size(); i++)
248       {
249         sendcounts[i]=nbcomp*(_recv_proc_offsets[i+1]-_recv_proc_offsets[i]);
250         senddispls[i]=nbcomp*(_recv_proc_offsets[i]);
251         recvcounts[i]=nbcomp*(_send_proc_offsets[i+1]-_send_proc_offsets[i]);
252         recvdispls[i]=nbcomp*(_send_proc_offsets[i]);
253       }
254     //building the buffer of the elements to be sent
255     vector<int> offsets = _recv_proc_offsets;
256     DataArrayDouble *fieldArr=field.getArray();
257     for (int iproc=0; iproc<_union_group->size();iproc++)
258       for (int i=_recv_proc_offsets[iproc]; i<_recv_proc_offsets[iproc+1]; i++)
259         {
260           for (int icomp=0; icomp<nbcomp; icomp++)
261             sendbuf[i*nbcomp+icomp]=fieldArr->getIJ(_recv_ids[i],icomp);
262         }
263
264     //communication phase
265     switch (getAllToAllMethod())
266       {
267       case Native:
268         {
269           const MPI_Comm* comm = group->getComm();
270           comm_interface.allToAllV(sendbuf, sendcounts, senddispls, MPI_DOUBLE,
271                                    recvbuf, recvcounts, recvdispls, MPI_DOUBLE,
272                                    *comm);
273         }
274         break;
275       case PointToPoint:
276         _access_DEC->allToAllv(sendbuf, sendcounts, senddispls, MPI_DOUBLE,
277                                recvbuf, recvcounts, recvdispls, MPI_DOUBLE);
278         break;
279       }
280
281     //setting the received values in the field
282     double* recvptr=recvbuf;                         
283     for (int i=0; i< _send_proc_offsets[_union_group->size()]; i++)
284       {
285         for (int icomp=0; icomp<nbcomp; icomp++)
286           {
287             recvfield[i*nbcomp+icomp]=*recvptr;
288             recvptr++;
289           }
290       }
291     if (sendbuf!=0 && getAllToAllMethod() == Native)
292       delete[] sendbuf;
293     if (recvbuf!=0)
294       delete[] recvbuf;
295     delete[] sendcounts;
296     delete[] recvcounts;
297     delete[] senddispls; 
298     delete[] recvdispls;
299   }
300
301   ostream & operator<< (ostream & f ,const AllToAllMethod & alltoallmethod )
302   {
303     switch (alltoallmethod)
304       {
305       case Native :
306         f << " Native ";
307         break;
308       case PointToPoint :
309         f << " PointToPoint ";
310         break;
311       default :
312         f << " UnknownAllToAllMethod ";
313         break;
314       }
315     return f;
316   }
317 }