Salome HOME
OverlapDEC: bug fix. Bounding box adjustment was negative.
[tools/medcoupling.git] / src / ParaMEDMEM / OverlapElementLocator.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 // Author : Anthony Geay (CEA/DEN)
20
21 #include "OverlapElementLocator.hxx"
22
23 #include "CommInterface.hxx"
24 #include "Topology.hxx"
25 #include "BlockTopology.hxx"
26 #include "ParaFIELD.hxx"
27 #include "ParaMESH.hxx"
28 #include "ProcessorGroup.hxx"
29 #include "MPIProcessorGroup.hxx"
30 #include "OverlapInterpolationMatrix.hxx"
31 #include "MEDCouplingFieldDouble.hxx"
32 #include "MEDCouplingFieldDiscretization.hxx"
33 #include "DirectedBoundingBox.hxx"
34 #include "InterpKernelAutoPtr.hxx"
35
36 #include <limits>
37
38 using namespace std;
39
40 namespace ParaMEDMEM 
41
42   const int OverlapElementLocator::START_TAG_MESH_XCH = 1140;
43
44   OverlapElementLocator::OverlapElementLocator(const ParaFIELD *sourceField, const ParaFIELD *targetField,
45                                                const ProcessorGroup& group, double epsAbs)
46     : _local_source_field(sourceField),
47       _local_target_field(targetField),
48       _local_source_mesh(0),
49       _local_target_mesh(0),
50       _domain_bounding_boxes(0),
51       _group(group),
52       _epsAbs(epsAbs)
53   { 
54     if(_local_source_field)
55       _local_source_mesh=_local_source_field->getSupport()->getCellMesh();
56     if(_local_target_field)
57       _local_target_mesh=_local_target_field->getSupport()->getCellMesh();
58     _comm=getCommunicator();
59     computeBoundingBoxesAndTodoList();
60   }
61
62   OverlapElementLocator::~OverlapElementLocator()
63   {
64     delete [] _domain_bounding_boxes;
65   }
66
67   const MPI_Comm *OverlapElementLocator::getCommunicator() const
68   {
69     const MPIProcessorGroup* group=static_cast<const MPIProcessorGroup*>(&_group);
70     return group->getComm();
71   }
72
73   void OverlapElementLocator::computeBoundingBoxesAndTodoList()
74   {
75     CommInterface comm_interface=_group.getCommInterface();
76     const MPIProcessorGroup* group=static_cast<const MPIProcessorGroup*> (&_group);
77     _local_space_dim=0;
78     if(_local_source_mesh)
79       _local_space_dim=_local_source_mesh->getSpaceDimension();
80     else
81       _local_space_dim=_local_target_mesh->getSpaceDimension();
82     //
83     const MPI_Comm* comm = group->getComm();
84     int bbSize=2*2*_local_space_dim;//2 (for source/target) 2 (min/max)
85     _domain_bounding_boxes=new double[bbSize*_group.size()];
86     INTERP_KERNEL::AutoPtr<double> minmax=new double[bbSize];
87     //Format minmax : Xmin_src,Xmax_src,Ymin_src,Ymax_src,Zmin_src,Zmax_src,Xmin_trg,Xmax_trg,Ymin_trg,Ymax_trg,Zmin_trg,Zmax_trg
88     if(_local_source_mesh)
89       _local_source_mesh->getBoundingBox(minmax);
90     else
91       {
92         for(int i=0;i<_local_space_dim;i++)
93           {
94             minmax[i*2]=std::numeric_limits<double>::max();
95             minmax[i*2+1]=-std::numeric_limits<double>::max();
96           }
97       }
98     if(_local_target_mesh)
99       _local_target_mesh->getBoundingBox(minmax+2*_local_space_dim);
100     else
101       {
102         for(int i=0;i<_local_space_dim;i++)
103           {
104             minmax[i*2+2*_local_space_dim]=std::numeric_limits<double>::max();
105             minmax[i*2+1+2*_local_space_dim]=-std::numeric_limits<double>::max();
106           }
107       }
108     comm_interface.allGather(minmax, bbSize, MPI_DOUBLE,
109                              _domain_bounding_boxes,bbSize, MPI_DOUBLE, 
110                              *comm);
111   
112     // Computation of all pairs needing an interpolation pairs are duplicated now !
113     
114     _proc_pairs.clear();//first is source second is target
115     _proc_pairs.resize(_group.size());
116     for(int i=0;i<_group.size();i++)
117       for(int j=0;j<_group.size();j++)
118         {
119           if(intersectsBoundingBox(i,j))
120             {
121             _proc_pairs[i].push_back(j);
122 //            std::cout << "("  << _group.myRank() << ") PROC pair: " << i << "," << j << std::endl;
123             }
124         }
125     // OK now let's assigning as balanced as possible, job to each proc of group
126     std::vector< std::vector< ProcCouple > > pairsToBeDonePerProc(_group.size());
127     int i=0;
128     for(std::vector< std::vector< int > >::const_iterator it1=_proc_pairs.begin();it1!=_proc_pairs.end();it1++,i++)
129       for(std::vector< int >::const_iterator it2=(*it1).begin();it2!=(*it1).end();it2++)
130         {
131           if(pairsToBeDonePerProc[i].size()<=pairsToBeDonePerProc[*it2].size())//it includes the fact that i==*it2
132             pairsToBeDonePerProc[i].push_back(ProcCouple(i,*it2));
133           else
134             pairsToBeDonePerProc[*it2].push_back(ProcCouple(i,*it2));
135         }
136     //Keeping todo list of current proc. _to_do_list contains a set of pair where at least _group.myRank() appears once.
137     //This proc will be in charge to perform interpolation of any of element of '_to_do_list'
138     //If _group.myRank()==myPair.first, current proc should fetch target mesh of myPair.second (if different from _group.myRank()).
139     //If _group.myRank()==myPair.second, current proc should fetch source mesh of myPair.second.
140     
141     int myProcId=_group.myRank();
142     _to_do_list=pairsToBeDonePerProc[myProcId];
143
144 //    std::stringstream scout;
145 //    scout << "(" << myProcId << ") my TODO list is: ";
146 //    for (std::vector< ProcCouple >::const_iterator itdbg=_to_do_list.begin(); itdbg!=_to_do_list.end(); itdbg++)
147 //      scout << "(" << (*itdbg).first << "," << (*itdbg).second << ")";
148 //    std::cout << scout.str() << "\n";
149
150     // Feeding now '_procs_to_send*'. A same id can appears twice. The second parameter in pair means what
151     // to send true=source, false=target
152     _procs_to_send_mesh.clear();
153     _procs_to_send_field.clear();
154     for(int i=_group.size()-1;i>=0;i--)
155       {
156         const std::vector< ProcCouple >& anRemoteProcToDoList=pairsToBeDonePerProc[i];
157         for(std::vector< ProcCouple >::const_iterator it=anRemoteProcToDoList.begin();it!=anRemoteProcToDoList.end();it++)
158           {
159             if((*it).first==myProcId)
160               {
161                 if(i!=myProcId)
162                   _procs_to_send_mesh.push_back(Proc_SrcOrTgt(i,true));
163                 _procs_to_send_field.push_back((*it).second);
164               }
165             if((*it).second==myProcId)
166               if(i!=myProcId)
167                 _procs_to_send_mesh.push_back(Proc_SrcOrTgt(i,false));
168           }
169       }
170   }
171
172   /*!
173    * The aim of this method is to perform the communication to get data corresponding to '_to_do_list' attribute.
174    * The principle is the following : if proc n1 and n2 need to perform a cross sending with n1<n2, then n1 will send first and receive then.
175    */
176   void OverlapElementLocator::exchangeMeshes(OverlapInterpolationMatrix& matrix)
177   {
178     int myProcId=_group.myRank();
179     //starting to receive every procs whose id is lower than myProcId.
180     std::vector< ProcCouple > toDoListForFetchRemaining;
181     for(std::vector< ProcCouple >::const_iterator it=_to_do_list.begin();it!=_to_do_list.end();it++)
182       {
183         int first = (*it).first, second = (*it).second;
184         if(first!=second)
185           {
186             if(first==myProcId)
187               {
188                 if(second<myProcId)
189                   receiveRemoteMeshFrom(second,false);
190                 else
191                   toDoListForFetchRemaining.push_back(ProcCouple(first,second));
192               }
193             else
194               {//(*it).second==myProcId
195                 if(first<myProcId)
196                   receiveRemoteMeshFrom(first,true);
197                 else
198                   toDoListForFetchRemaining.push_back(ProcCouple(first,second));
199               }
200           }
201       }
202     //sending source or target mesh to remote procs
203     for(std::vector< Proc_SrcOrTgt >::const_iterator it2=_procs_to_send_mesh.begin();it2!=_procs_to_send_mesh.end();it2++)
204       sendLocalMeshTo((*it2).first,(*it2).second,matrix);
205     //fetching remaining meshes
206     for(std::vector< ProcCouple >::const_iterator it=toDoListForFetchRemaining.begin();it!=toDoListForFetchRemaining.end();it++)
207       {
208         if((*it).first!=(*it).second)
209           {
210             if((*it).first==myProcId)
211               receiveRemoteMeshFrom((*it).second,false);
212             else//(*it).second==myProcId
213               receiveRemoteMeshFrom((*it).first,true);
214           }
215       }
216   }
217   
218   std::string OverlapElementLocator::getSourceMethod() const
219   {
220     return _local_source_field->getField()->getDiscretization()->getStringRepr();
221   }
222
223   std::string OverlapElementLocator::getTargetMethod() const
224   {
225     return _local_target_field->getField()->getDiscretization()->getStringRepr();
226   }
227
228   const MEDCouplingPointSet *OverlapElementLocator::getSourceMesh(int procId) const
229   {
230     int myProcId=_group.myRank();
231     if(myProcId==procId)
232       return _local_source_mesh;
233     Proc_SrcOrTgt p(procId,true);
234     std::map<Proc_SrcOrTgt, AutoMCPointSet >::const_iterator it=_remote_meshes.find(p);
235     return (*it).second;
236   }
237
238   const DataArrayInt *OverlapElementLocator::getSourceIds(int procId) const
239   {
240     int myProcId=_group.myRank();
241     if(myProcId==procId)
242       return 0;
243     Proc_SrcOrTgt p(procId,true);
244     std::map<Proc_SrcOrTgt, AutoDAInt >::const_iterator it=_remote_elems.find(p);
245     return (*it).second;
246   }
247
248   const MEDCouplingPointSet *OverlapElementLocator::getTargetMesh(int procId) const
249   {
250     int myProcId=_group.myRank();
251     if(myProcId==procId)
252       return _local_target_mesh;
253     Proc_SrcOrTgt p(procId,false);
254     std::map<Proc_SrcOrTgt, AutoMCPointSet >::const_iterator it=_remote_meshes.find(p);
255     return (*it).second;
256   }
257
258   const DataArrayInt *OverlapElementLocator::getTargetIds(int procId) const
259   {
260     int myProcId=_group.myRank();
261     if(myProcId==procId)
262       return 0;
263     Proc_SrcOrTgt p(procId,false);
264     std::map<Proc_SrcOrTgt, AutoDAInt >::const_iterator it=_remote_elems.find(p);
265     return (*it).second;
266   }
267
268
269   bool OverlapElementLocator::intersectsBoundingBox(int isource, int itarget) const
270   {
271     const double *source_bb=_domain_bounding_boxes+isource*2*2*_local_space_dim;
272     const double *target_bb=_domain_bounding_boxes+itarget*2*2*_local_space_dim+2*_local_space_dim;
273
274     for (int idim=0; idim < _local_space_dim; idim++)
275       {
276         bool intersects = (target_bb[idim*2]<source_bb[idim*2+1]+_epsAbs)
277           && (source_bb[idim*2]<target_bb[idim*2+1]+_epsAbs);
278         if (!intersects)
279           return false; 
280       }
281     return true;
282   }
283
284   /*!
285    * This methods sends (part of) local source if 'sourceOrTarget'==True to proc 'procId'.
286    * This methods sends (part of) local target if 'sourceOrTarget'==False to proc 'procId'.
287    *
288    * This method prepares the matrix too, for matrix assembling and future matrix-vector computation.
289    */
290   void OverlapElementLocator::sendLocalMeshTo(int procId, bool sourceOrTarget, OverlapInterpolationMatrix& matrix) const
291   {
292    //int myProcId=_group.myRank();
293    const double *distant_bb=0;
294    MEDCouplingPointSet *local_mesh=0;
295    const ParaFIELD *field=0;
296    if(sourceOrTarget)//source for local mesh but target for distant mesh
297      {
298        distant_bb=_domain_bounding_boxes+procId*2*2*_local_space_dim+2*_local_space_dim;
299        local_mesh=_local_source_mesh;
300        field=_local_source_field;
301      }
302    else//target for local but source for distant
303      {
304        distant_bb=_domain_bounding_boxes+procId*2*2*_local_space_dim;
305        local_mesh=_local_target_mesh;
306        field=_local_target_field;
307      }
308    AutoDAInt elems=local_mesh->getCellsInBoundingBox(distant_bb,getBoundingBoxAdjustment());
309    DataArrayInt *old2new_map;
310    MEDCouplingPointSet *send_mesh=static_cast<MEDCouplingPointSet *>(field->getField()->buildSubMeshData(elems->begin(),elems->end(),old2new_map));
311    if(sourceOrTarget)
312      matrix.keepTracksOfSourceIds(procId,old2new_map);
313    else
314      matrix.keepTracksOfTargetIds(procId,old2new_map);
315    sendMesh(procId,send_mesh,old2new_map);
316    send_mesh->decrRef();
317    old2new_map->decrRef();
318   }
319
320   /*!
321    * This method recieves source remote mesh on proc 'procId' if sourceOrTarget==True
322    * This method recieves target remote mesh on proc 'procId' if sourceOrTarget==False
323    */
324   void OverlapElementLocator::receiveRemoteMeshFrom(int procId, bool sourceOrTarget)
325   {
326     DataArrayInt *old2new_map=0;
327     MEDCouplingPointSet *m=0;
328     receiveMesh(procId,m,old2new_map);
329     Proc_SrcOrTgt p(procId,sourceOrTarget);
330     _remote_meshes[p]=m;
331     _remote_elems[p]=old2new_map;
332   }
333
334   void OverlapElementLocator::sendMesh(int procId, const MEDCouplingPointSet *mesh, const DataArrayInt *idsToSend) const
335   {
336     CommInterface comInterface=_group.getCommInterface();
337
338     // First stage : exchanging sizes
339     vector<double> tinyInfoLocalD;//tinyInfoLocalD not used for the moment
340     vector<int> tinyInfoLocal;
341     vector<string> tinyInfoLocalS;
342     mesh->getTinySerializationInformation(tinyInfoLocalD,tinyInfoLocal,tinyInfoLocalS);
343     const MPI_Comm *comm=getCommunicator();
344     //
345     int lgth[2];
346     lgth[0]=tinyInfoLocal.size();
347     lgth[1]=idsToSend->getNbOfElems();
348     comInterface.send(&lgth,2,MPI_INT,procId,START_TAG_MESH_XCH,*_comm);
349     comInterface.send(&tinyInfoLocal[0],tinyInfoLocal.size(),MPI_INT,procId,START_TAG_MESH_XCH+1,*comm);
350     //
351     DataArrayInt *v1Local=0;
352     DataArrayDouble *v2Local=0;
353     mesh->serialize(v1Local,v2Local);
354     comInterface.send(v1Local->getPointer(),v1Local->getNbOfElems(),MPI_INT,procId,START_TAG_MESH_XCH+2,*comm);
355     comInterface.send(v2Local->getPointer(),v2Local->getNbOfElems(),MPI_DOUBLE,procId,START_TAG_MESH_XCH+3,*comm);
356     //finished for mesh, ids now
357     comInterface.send(const_cast<int *>(idsToSend->getConstPointer()),lgth[1],MPI_INT,procId,START_TAG_MESH_XCH+4,*comm);
358     //
359     v1Local->decrRef();
360     v2Local->decrRef();
361   }
362
363   void OverlapElementLocator::receiveMesh(int procId, MEDCouplingPointSet* &mesh, DataArrayInt *&ids) const
364   {
365     int lgth[2];
366     MPI_Status status;
367     const MPI_Comm *comm=getCommunicator();
368     CommInterface comInterface=_group.getCommInterface();
369     comInterface.recv(lgth,2,MPI_INT,procId,START_TAG_MESH_XCH,*_comm,&status);
370     std::vector<int> tinyInfoDistant(lgth[0]);
371     ids=DataArrayInt::New();
372     ids->alloc(lgth[1],1);
373     comInterface.recv(&tinyInfoDistant[0],lgth[0],MPI_INT,procId,START_TAG_MESH_XCH+1,*comm,&status);
374     mesh=MEDCouplingPointSet::BuildInstanceFromMeshType((MEDCouplingMeshType)tinyInfoDistant[0]);
375     std::vector<std::string> unusedTinyDistantSts;
376     vector<double> tinyInfoDistantD(1);//tinyInfoDistantD not used for the moment
377     DataArrayInt *v1Distant=DataArrayInt::New();
378     DataArrayDouble *v2Distant=DataArrayDouble::New();
379     mesh->resizeForUnserialization(tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts);
380     comInterface.recv(v1Distant->getPointer(),v1Distant->getNbOfElems(),MPI_INT,procId,START_TAG_MESH_XCH+2,*comm,&status);
381     comInterface.recv(v2Distant->getPointer(),v2Distant->getNbOfElems(),MPI_DOUBLE,procId,START_TAG_MESH_XCH+3,*comm,&status);
382     mesh->unserialization(tinyInfoDistantD,tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts);
383     //finished for mesh, ids now
384     comInterface.recv(ids->getPointer(),lgth[1],MPI_INT,procId,1144,*comm,&status);
385     //
386     v1Distant->decrRef();
387     v2Distant->decrRef();
388   }
389 }