Salome HOME
Copyrights update 2015.
[modules/med.git] / src / ParaMEDMEM / ExplicitCoincidentDEC.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 <mpi.h>
21 #include "CommInterface.hxx"
22 #include "Topology.hxx"
23 #include "BlockTopology.hxx"
24 #include "ComponentTopology.hxx"
25 #include "ParaFIELD.hxx"
26 #include "MPIProcessorGroup.hxx"
27 #include "ExplicitCoincidentDEC.hxx"
28 #include "ExplicitMapping.hxx"
29 #include "InterpKernelUtilities.hxx"
30
31 using namespace std;
32
33 namespace ParaMEDMEM
34 {
35   /*! \defgroup explicitcoincidentdec ExplicitCoincidentDEC
36    */
37   ExplicitCoincidentDEC::ExplicitCoincidentDEC():_toposource(0),_topotarget(0)
38   {  
39   }
40
41   ExplicitCoincidentDEC::~ExplicitCoincidentDEC()
42   {
43   }
44
45
46   /*!
47     \addtogroup explicitcoincidentdec
48     @{
49   */
50
51   /*! Synchronization process for exchanging topologies
52    */
53   void ExplicitCoincidentDEC::synchronize()
54   {
55     if (_source_group->containsMyRank())
56       {
57         _toposource = dynamic_cast<ExplicitTopology*>(_local_field->getTopology());
58         _sourcegroup= _toposource->getProcGroup()->createProcGroup();
59         _targetgroup=_toposource->getProcGroup()->createComplementProcGroup();
60       }
61     if (_target_group->containsMyRank())
62       {
63         _topotarget = dynamic_cast<ExplicitTopology*>(_local_field->getTopology());
64         _sourcegroup= _topotarget->getProcGroup()->createComplementProcGroup();
65         _targetgroup=_topotarget->getProcGroup()->createProcGroup();
66       }
67   
68     // Exchanging
69   
70     // Transmitting source topology to target code 
71     broadcastTopology(_toposource,_topotarget,1000);
72     transferMappingToSource();
73   }
74
75   /*! Creates the arrays necessary for the data transfer
76    * and fills the send array with the values of the 
77    * source field
78    *  */
79   void ExplicitCoincidentDEC::prepareSourceDE()
80   {
81     ////////////////////////////////////
82     //Step 1 : buffer array creation 
83   
84     if (!_toposource->getProcGroup()->containsMyRank())
85       return;
86     MPIProcessorGroup* group=new MPIProcessorGroup(_sourcegroup->getCommInterface());
87   
88     // Warning : the size of the target side is implicitly deduced
89     //from the size of MPI_COMM_WORLD
90     int target_size = _toposource->getProcGroup()->getCommInterface().worldSize()- _toposource->getProcGroup()->size()  ;
91   
92     vector<int>* target_arrays=new vector<int>[target_size];
93   
94     int nb_local = _toposource-> getNbLocalElements();
95
96     int union_size=group->size();
97   
98     _sendcounts=new int[union_size];
99     _senddispls=new int[union_size];
100     _recvcounts=new int[union_size];
101     _recvdispls=new int[union_size];
102   
103     for (int i=0; i< union_size; i++)
104       {
105         _sendcounts[i]=0;
106         _recvcounts[i]=0;
107         _recvdispls[i]=0;
108       }
109     _senddispls[0]=0;
110  
111     int* counts=_explicit_mapping.getCounts();
112     for (int i=0; i<group->size(); i++)
113       _sendcounts[i]=counts[i];
114   
115     for (int iproc=1; iproc<group->size();iproc++)
116       _senddispls[iproc]=_senddispls[iproc-1]+_sendcounts[iproc-1];
117   
118     _sendbuffer = new double [nb_local * _toposource->getNbComponents()];
119   
120     /////////////////////////////////////////////////////////////
121     //Step 2 : filling the buffers with the source field values 
122   
123     int* counter=new int [target_size];
124     counter[0]=0;  
125     for (int i=1; i<target_size; i++)
126       counter[i]=counter[i-1]+target_arrays[i-1].size();
127   
128   
129     const double* value = _local_field->getField()->getArray()->getPointer();
130   
131     int* bufferindex= _explicit_mapping.getBufferIndex();
132   
133     for (int ielem=0; ielem<nb_local; ielem++)
134       {
135         int ncomp = _toposource->getNbComponents();
136         for (int icomp=0; icomp<ncomp; icomp++)
137           {
138             _sendbuffer[ielem*ncomp+icomp]=value[bufferindex[ielem]*ncomp+icomp];
139           }  
140       }
141     delete[] target_arrays;
142     delete[] counter;
143   }
144
145   /*!
146    *  Creates the buffers for receiving the fields on the target side
147    */
148   void ExplicitCoincidentDEC::prepareTargetDE()
149   {
150     if (!_topotarget->getProcGroup()->containsMyRank())
151       return;
152     MPIProcessorGroup* group=new MPIProcessorGroup(_topotarget->getProcGroup()->getCommInterface());
153
154     vector < vector <int> > source_arrays(_sourcegroup->size());
155     int nb_local = _topotarget-> getNbLocalElements();
156     for (int ielem=0; ielem< nb_local ; ielem++)
157       {
158         //pair<int,int> source_local =_distant_elems[ielem];
159         pair <int,int> source_local=_explicit_mapping.getDistantNumbering(ielem);
160         source_arrays[source_local.first].push_back(source_local.second); 
161       }  
162     int union_size=group->size();
163     _recvcounts=new int[union_size];
164     _recvdispls=new int[union_size];
165     _sendcounts=new int[union_size];
166     _senddispls=new int[union_size];
167     
168     for (int i=0; i< union_size; i++)
169       {
170         _sendcounts[i]=0;
171         _recvcounts[i]=0;
172         _recvdispls[i]=0;
173       }
174     for (int iproc=0; iproc < _sourcegroup->size(); iproc++)
175       {
176         //converts the rank in target to the rank in union communicator
177         int unionrank=group->translateRank(_sourcegroup,iproc);
178         _recvcounts[unionrank]=source_arrays[iproc].size()*_topotarget->getNbComponents();
179       }
180     for (int i=1; i<union_size; i++)
181       _recvdispls[i]=_recvdispls[i-1]+_recvcounts[i-1];
182     _recvbuffer=new double[nb_local*_topotarget->getNbComponents()];
183     
184   }
185
186  
187   /*!
188    * Synchronizing a topology so that all the 
189    * group possesses it.
190    * 
191    * \param toposend Topology that is transmitted. It is read on processes where it already exists, and it is created and filled on others.
192    * \param toporecv Topology which is received.
193    * \param tag Communication tag associated with this operation.
194    */
195   void ExplicitCoincidentDEC::broadcastTopology(const ExplicitTopology* toposend, ExplicitTopology* toporecv, int tag)
196   {
197     MPI_Status status;
198   
199     int* serializer=0;
200     int size;
201   
202     MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface);
203   
204     // The send processors serialize the send topology
205     // and send the buffers to the recv procs
206     if (toposend !=0 && toposend->getProcGroup()->containsMyRank())
207       {
208         toposend->serialize(serializer, size);
209         for (int iproc=0; iproc< group->size(); iproc++)
210           {
211             int itarget=iproc;
212             if (!toposend->getProcGroup()->contains(itarget))
213               {
214                 _comm_interface->send(&size,1,MPI_INT, itarget,tag+itarget,*(group->getComm()));
215                 _comm_interface->send(serializer, size, MPI_INT, itarget, tag+itarget,*(group->getComm()));          
216               }
217           }
218       }
219     else
220       {
221         vector <int> size2(group->size());
222         int myworldrank=group->myRank();
223         for (int iproc=0; iproc<group->size();iproc++)
224           {
225             int isource = iproc;
226             if (!toporecv->getProcGroup()->contains(isource))
227               {
228                 int nbelem;
229                 _comm_interface->recv(&nbelem, 1, MPI_INT, isource, tag+myworldrank, *(group->getComm()), &status);
230                 int* buffer = new int[nbelem];
231                 _comm_interface->recv(buffer, nbelem, MPI_INT, isource,tag+myworldrank, *(group->getComm()), &status);        
232       
233                 ExplicitTopology* topotemp=new ExplicitTopology();
234                 topotemp->unserialize(buffer, *_comm_interface);
235                 delete[] buffer;
236         
237                 for (int ielem=0; ielem<toporecv->getNbLocalElements(); ielem++)
238                   {
239                     int global = toporecv->localToGlobal(ielem);
240                     int sendlocal=topotemp->globalToLocal(global);
241                     if (sendlocal!=-1)
242                       {
243                         size2[iproc]++;
244                         _explicit_mapping.pushBackElem(make_pair(iproc,sendlocal));
245                       }
246                   }
247                 delete topotemp;
248               }
249           }  
250       }  
251     MESSAGE (" rank "<<group->myRank()<< " broadcastTopology is over");
252   }
253
254   void ExplicitCoincidentDEC::transferMappingToSource()
255   {
256
257     MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface);
258   
259     // sending source->target mapping which is stored by target
260     //in _distant_elems from target to source
261     if (_topotarget!=0 && _topotarget->getProcGroup()->containsMyRank())
262       {
263         int world_size = _topotarget->getProcGroup()->getCommInterface().worldSize()  ;
264         int* nb_transfer_union=new int[world_size];
265         int* dummy_recv=new int[world_size];
266         for (int i=0; i<world_size; i++)
267           nb_transfer_union[i]=0;
268         //converts the rank in target to the rank in union communicator
269     
270         for (int i=0; i<  _explicit_mapping.nbDistantDomains(); i++)
271           {
272             int unionrank=group->translateRank(_sourcegroup,_explicit_mapping.getDistantDomain(i));
273             nb_transfer_union[unionrank]=_explicit_mapping.getNbDistantElems(i);
274           }
275         _comm_interface->allToAll(nb_transfer_union, 1, MPI_INT, dummy_recv, 1, MPI_INT, MPI_COMM_WORLD);
276       
277         int* sendbuffer= _explicit_mapping.serialize(_topotarget->getProcGroup()->myRank());
278       
279         int* sendcounts= new int [world_size];
280         int* senddispls = new int [world_size];
281         for (int i=0; i< world_size; i++)
282           {
283             sendcounts[i]=2*nb_transfer_union[i];
284             if (i==0)
285               senddispls[i]=0;
286             else
287               senddispls[i]=senddispls[i-1]+sendcounts[i-1];
288           }
289         int* recvcounts=new int[world_size];
290         int* recvdispls=new int[world_size];
291         int *dummyrecv=0;
292         for (int i=0; i <world_size; i++)
293           {
294             recvcounts[i]=0;
295             recvdispls[i]=0;
296           }
297         _comm_interface->allToAllV(sendbuffer, sendcounts, senddispls, MPI_INT, dummyrecv, recvcounts, senddispls, MPI_INT, MPI_COMM_WORLD);
298       
299       }
300     //receiving in the source subdomains the mapping sent by targets
301     else
302       {
303         int world_size = _toposource->getProcGroup()->getCommInterface().worldSize()  ;
304         int* nb_transfer_union=new int[world_size];
305         int* dummy_send=new int[world_size];
306         for (int i=0; i<world_size; i++)
307           dummy_send[i]=0;
308         _comm_interface->allToAll(dummy_send, 1, MPI_INT, nb_transfer_union, 1, MPI_INT, MPI_COMM_WORLD);
309       
310         int total_size=0;
311         for (int i=0; i< world_size; i++)
312           total_size+=nb_transfer_union[i];
313         int nbtarget = _targetgroup->size();
314         int* targetranks = new int[ nbtarget];
315         for (int i=0; i<nbtarget; i++)
316           targetranks[i]=group->translateRank(_targetgroup,i);
317         int* mappingbuffer= new int [total_size*2];
318         int* sendcounts= new int [world_size];
319         int* senddispls = new int [world_size];
320         int* recvcounts=new int[world_size];
321         int* recvdispls=new int[world_size];
322         for (int i=0; i< world_size; i++)
323           {
324             recvcounts[i]=2*nb_transfer_union[i];
325             if (i==0)
326               recvdispls[i]=0;
327             else
328               recvdispls[i]=recvdispls[i-1]+recvcounts[i-1];
329           }
330
331         int *dummysend=0;
332         for (int i=0; i <world_size; i++)
333           {
334             sendcounts[i]=0;
335             senddispls[i]=0;
336           }
337         _comm_interface->allToAllV(dummysend, sendcounts, senddispls, MPI_INT, mappingbuffer, recvcounts, recvdispls, MPI_INT, MPI_COMM_WORLD);
338         _explicit_mapping.unserialize(world_size,nb_transfer_union,nbtarget, targetranks, mappingbuffer);
339       }
340   }
341
342   void ExplicitCoincidentDEC::recvData()
343   {
344     //MPI_COMM_WORLD is used instead of group because there is no
345     //mechanism for creating the union group yet
346     MESSAGE("recvData");
347
348     cout<<"start AllToAll"<<endl;
349     _comm_interface->allToAllV(_sendbuffer, _sendcounts, _senddispls, MPI_DOUBLE, 
350                                _recvbuffer, _recvcounts, _recvdispls, MPI_DOUBLE,MPI_COMM_WORLD);
351     cout<<"end AllToAll"<<endl;
352     int nb_local = _topotarget->getNbLocalElements();
353     double* value=new double[nb_local*_topotarget->getNbComponents()];
354
355     vector<int> counters(_sourcegroup->size());
356     counters[0]=0;
357     for (int i=0; i<_sourcegroup->size()-1; i++)
358       {
359         MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface);
360         int worldrank=group->translateRank(_sourcegroup,i);
361         counters[i+1]=counters[i]+_recvcounts[worldrank];
362       }
363   
364     for (int ielem=0; ielem<nb_local ; ielem++)
365       {
366         pair<int,int> distant_numbering=_explicit_mapping.getDistantNumbering(ielem);
367         int iproc=distant_numbering.first; 
368         int ncomp =  _topotarget->getNbComponents();
369         for (int icomp=0; icomp< ncomp; icomp++)
370           value[ielem*ncomp+icomp]=_recvbuffer[counters[iproc]*ncomp+icomp];
371         counters[iproc]++;
372       }  
373     _local_field->getField()->getArray()->useArray(value,true,CPP_DEALLOC,nb_local,_topotarget->getNbComponents());
374   }
375
376   void ExplicitCoincidentDEC::sendData()
377   {
378     MESSAGE ("sendData");
379     for (int i=0; i< 4; i++)
380       cout << _sendcounts[i]<<" ";
381     cout <<endl;
382     for (int i=0; i< 4; i++)
383       cout << _senddispls[i]<<" ";
384     cout <<endl;
385     //MPI_COMM_WORLD is used instead of group because there is no
386     //mechanism for creating the union group yet
387     cout <<"start AllToAll"<<endl;
388     _comm_interface->allToAllV(_sendbuffer, _sendcounts, _senddispls, MPI_DOUBLE, 
389                                _recvbuffer, _recvcounts, _recvdispls, MPI_DOUBLE,MPI_COMM_WORLD);
390   }
391   /*!
392     @}
393   */
394 }
395