Salome HOME
[ICoCo] ICoCo interface version 2
[tools/medcoupling.git] / src / ParaMEDMEM / OverlapDEC.cxx
1 // Copyright (C) 2007-2021  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 "OverlapDEC.hxx"
22 #include "CommInterface.hxx"
23 #include "ParaMESH.hxx"
24 #include "ParaFIELD.hxx"
25 #include "MPIProcessorGroup.hxx"
26 #include "OverlapElementLocator.hxx"
27 #include "OverlapInterpolationMatrix.hxx"
28 #include "ICoCoMEDDoubleField.hxx"
29
30 namespace MEDCoupling
31 {
32   OverlapDEC::OverlapDEC(const std::set<int>& procIds, const MPI_Comm& world_comm):
33       _load_balancing_algo(1),
34       _own_group(true),_interpolation_matrix(0), _locator(0),
35       _default_field_value(0.0),
36       _source_field(0),_own_source_field(false),
37       _target_field(0),_own_target_field(false),
38       _comm(MPI_COMM_NULL)
39   {
40     MEDCoupling::CommInterface comm;
41     int *ranks_world=new int[procIds.size()]; // ranks of sources and targets in world_comm
42     std::copy(procIds.begin(),procIds.end(),ranks_world);
43     MPI_Group group,world_group;
44     comm.commGroup(world_comm,&world_group);
45     comm.groupIncl(world_group,(int)procIds.size(),ranks_world,&group);
46     delete [] ranks_world;
47     comm.commCreate(world_comm,group,&_comm);
48     comm.groupFree(&group);
49     comm.groupFree(&world_group);
50     if(_comm==MPI_COMM_NULL)
51       {
52         _group=0;
53         return ;
54       }
55     std::set<int> idsUnion;
56     for(unsigned int i=0;i<procIds.size();i++)
57       idsUnion.insert(i);
58     _group=new MPIProcessorGroup(comm,idsUnion,_comm);
59   }
60
61   OverlapDEC::~OverlapDEC()
62   {
63     release();
64   }
65
66   /** Destructor involves MPI operations: make sure this is accessible from a proper
67    * method for Python wrapping.
68    */
69   void OverlapDEC::release()
70   {
71     if(_own_group)
72       {
73         delete _group;
74         _group = nullptr;
75       }
76     if(_own_source_field)
77       {
78         delete _source_field;
79         _source_field = nullptr;
80       }
81     if(_own_target_field)
82       {
83         delete _target_field;
84         _target_field = nullptr;
85       }
86     delete _interpolation_matrix;
87     _interpolation_matrix = nullptr;
88     delete _locator;
89     _locator = nullptr;
90     if (_comm != MPI_COMM_NULL)
91       {
92         MEDCoupling::CommInterface comm;
93         comm.commFree(&_comm);
94       }
95     _comm = MPI_COMM_NULL;
96   }
97
98   void OverlapDEC::sendRecvData(bool way)
99   {
100     if(way)
101       sendData();
102     else
103       recvData();
104   }
105
106   void OverlapDEC::sendData()
107   {
108     _interpolation_matrix->multiply(_default_field_value);
109   }
110
111   void OverlapDEC::recvData()
112   {
113     throw INTERP_KERNEL::Exception("Not implemented yet !!!!");
114     //_interpolation_matrix->transposeMultiply();
115   }
116   
117   void OverlapDEC::synchronize()
118   {
119     if(!isInGroup())
120       return ;
121     // Check number of components of field on both side (for now allowing void field/mesh on one proc is not allowed)
122     if (!_source_field || !_source_field->getField())
123       throw INTERP_KERNEL::Exception("OverlapDEC::synchronize(): currently, having a void source field on a proc is not allowed!");
124     if (!_target_field || !_target_field->getField())
125       throw INTERP_KERNEL::Exception("OverlapDEC::synchronize(): currently, having a void target field on a proc is not allowed!");
126     if (_target_field->getField()->getNumberOfComponents() != _source_field->getField()->getNumberOfComponents())
127       throw INTERP_KERNEL::Exception("OverlapDEC::synchronize(): source and target field have different number of components!");
128     delete _interpolation_matrix;
129     _locator = new OverlapElementLocator(_source_field,_target_field,*_group, getBoundingBoxAdjustmentAbs(), _load_balancing_algo);
130     _interpolation_matrix=new OverlapInterpolationMatrix(_source_field,_target_field,*_group,*this,*this, *_locator);
131     _locator->copyOptions(*this);
132     _locator->exchangeMeshes(*_interpolation_matrix);
133     std::vector< std::pair<int,int> > jobs=_locator->getToDoList();
134     std::string srcMeth=_locator->getSourceMethod();
135     std::string trgMeth=_locator->getTargetMethod();
136     for(std::vector< std::pair<int,int> >::const_iterator it=jobs.begin();it!=jobs.end();it++)
137       {
138         const MEDCouplingPointSet *src=_locator->getSourceMesh((*it).first);
139         const DataArrayIdType *srcIds=_locator->getSourceIds((*it).first);
140         const MEDCouplingPointSet *trg=_locator->getTargetMesh((*it).second);
141         const DataArrayIdType *trgIds=_locator->getTargetIds((*it).second);
142         _interpolation_matrix->computeLocalIntersection(src,srcIds,srcMeth,(*it).first,trg,trgIds,trgMeth,(*it).second);
143       }
144     _interpolation_matrix->prepare(_locator->getProcsToSendFieldData());
145     _interpolation_matrix->computeSurfacesAndDeno();
146   }
147
148   void OverlapDEC::attachSourceLocalField(ParaFIELD *field, bool ownPt)
149   {
150     if(!isInGroup())
151       return ;
152     if(_own_source_field)
153       delete _source_field;
154     _source_field=field;
155     _own_source_field=ownPt;
156   }
157
158   void OverlapDEC::attachTargetLocalField(ParaFIELD *field, bool ownPt)
159   {
160     if(!isInGroup())
161       return ;
162     if(_own_target_field)
163       delete _target_field;
164     _target_field=field;
165     _own_target_field=ownPt;
166   }
167
168   void OverlapDEC::attachSourceLocalField(MEDCouplingFieldDouble *field)
169   {
170     if(!isInGroup())
171       return ;
172
173     ParaMESH *paramesh = new ParaMESH(static_cast<MEDCouplingPointSet *>(const_cast<MEDCouplingMesh *>(field->getMesh())),
174                                       *_group,field->getMesh()->getName());
175     ParaFIELD *tmpField=new ParaFIELD(field, paramesh, *_group);
176     tmpField->setOwnSupport(true);
177     attachSourceLocalField(tmpField,true);
178   }
179
180   void OverlapDEC::attachTargetLocalField(MEDCouplingFieldDouble *field)
181   {
182     if(!isInGroup())
183       return ;
184
185     ParaMESH *paramesh = new ParaMESH(static_cast<MEDCouplingPointSet *>(const_cast<MEDCouplingMesh *>(field->getMesh())),
186                                       *_group,field->getMesh()->getName());
187     ParaFIELD *tmpField=new ParaFIELD(field, paramesh, *_group);
188     tmpField->setOwnSupport(true);
189     attachTargetLocalField(tmpField,true);
190   }
191
192   void OverlapDEC::attachSourceLocalField(ICoCo::MEDDoubleField *field)
193   {
194     attachSourceLocalField(field->getMCField());
195   }
196
197   void OverlapDEC::attachTargetLocalField(ICoCo::MEDDoubleField *field)
198   {
199     attachTargetLocalField(field->getMCField());
200   }
201
202   bool OverlapDEC::isInGroup() const
203   {
204     if(!_group)
205       return false;
206     return _group->containsMyRank();
207   }
208
209   void OverlapDEC::debugPrintWorkSharing(std::ostream & ostr) const
210   {
211     _locator->debugPrintWorkSharing(ostr);
212   }
213 }