Salome HOME
[bos #38048] [EDF] (2023-T3) PARAMEDMEM Ergonomy.
[tools/medcoupling.git] / src / ParaMEDMEM / InterpKernelDEC.cxx
1 // Copyright (C) 2007-2024  CEA, EDF
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 "ParaMESH.hxx"
28 #include "DEC.hxx"
29 #include "InterpolationMatrix.hxx"
30 #include "InterpKernelDEC.hxx"
31 #include "ElementLocator.hxx"
32
33 namespace MEDCoupling
34 {
35   InterpKernelDEC::InterpKernelDEC():
36     DisjointDEC(),
37     _interpolation_matrix(0)
38   {  
39   }
40
41   /*!
42     This constructor creates an InterpKernelDEC which has \a source_group as a working side 
43     and  \a target_group as an idle side. All the processors will actually participate, but intersection computations will be performed on the working side during the \a synchronize() phase.
44     The constructor must be called synchronously on all processors of both processor groups.
45     The source group and target group MUST form a partition of all the procs within the communicator passed as 'world_comm'
46     when building the group.
47
48     \param source_group working side ProcessorGroup
49     \param target_group lazy side ProcessorGroup
50
51   */
52   InterpKernelDEC::InterpKernelDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
53     DisjointDEC(source_group, target_group),
54     _interpolation_matrix(0)
55   {
56
57   }
58
59
60   /*!
61    * Creates an InterpKernelDEC from a set of source procs IDs and target group IDs.
62    * The difference with the ctor using groups is that the set of procs might not cover entirely MPI_COMM_WORLD
63    * (a sub-communicator holding the union of source and target procs is recreated internally).
64    */
65   InterpKernelDEC::InterpKernelDEC(const std::set<int>& src_ids, const std::set<int>& trg_ids,
66                                    const MPI_Comm& world_comm):
67     DisjointDEC(src_ids,trg_ids,world_comm),
68     _interpolation_matrix(0)
69   {
70   }
71
72   /*!
73    * Creates an InterpKernelDEC from an string identifier for the source and target groups.
74    * The set of procs might not cover entirely MPI_COMM_WORLD
75    * (a sub-communicator holding the union of source and target procs is recreated internally).
76    */
77   InterpKernelDEC::InterpKernelDEC(ProcessorGroup& generic_group, const std::string& source_group, const std::string& target_group):
78     DisjointDEC(generic_group.getProcIDsByName(source_group),generic_group.getProcIDsByName(target_group)),
79     _interpolation_matrix(0)
80   {
81   }
82   
83   /*!
84    * Split the interaction group based on the predefined token string "<->"
85    *  The string at left of the token will be the source group and the string at right the target group
86    */
87   static std::pair<std::string,std::string> GetGroupsName( const std::string& interaction_group )
88   {
89     const std::string delimiter = "<->";
90     size_t delimiter_position = interaction_group.find(delimiter);
91     if ( delimiter_position == std::string::npos )
92       throw ( "No delimiter <-> found in the interaction group.");
93
94     std::string src = interaction_group.substr(0,delimiter_position);
95     std::string tgt = interaction_group.substr(delimiter_position+delimiter.size(),interaction_group.size());
96     return std::make_pair(src,tgt);
97   }
98
99   /*!
100    * Creates an InterpKernelDEC from an string defining an interaction. 
101    *  The source and target group are obtained by spliting the string based in the "<->" token.
102    *  The constructor accepting a ProcessorGroup and two strings is reused.
103    */
104   InterpKernelDEC::InterpKernelDEC(ProcessorGroup& generic_group, const std::string& interaction_group ):
105     InterpKernelDEC(generic_group,GetGroupsName(interaction_group).first,GetGroupsName(interaction_group).second)
106   {
107   }
108
109   InterpKernelDEC::~InterpKernelDEC()
110   {
111     release();
112   }
113
114   void InterpKernelDEC::release()
115   {
116     if (_interpolation_matrix != nullptr)
117       delete _interpolation_matrix;
118     _interpolation_matrix = nullptr;
119     DisjointDEC::cleanInstance();
120   }
121
122
123   /*! 
124     \brief Synchronization process for exchanging topologies.
125
126     This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh
127     underlying the fields that have been set with attachLocalField method.
128     It works in four steps :
129     -# Bounding boxes are computed for each sub-domain,
130     -# The lazy side mesh parts that are likely to intersect the working side local processor are sent to the working side,
131     -# The working side calls the interpolation kernel to compute the intersection between local and imported mesh.
132     -# The lazy side is updated so that it knows the structure of the data that will be sent by
133     the working side during a \a sendData() call.
134
135   */
136   void InterpKernelDEC::synchronize()
137   {
138     if(!isInUnion())
139       return ;
140     delete _interpolation_matrix;
141     _interpolation_matrix = new InterpolationMatrix (_local_field, *_source_group,*_target_group,*this,*this); 
142
143     //setting up the communication DEC on both sides  
144     if (_source_group->containsMyRank())
145       {
146         //locate the distant meshes
147         ElementLocator locator(*_local_field, *_target_group, *_source_group);
148         //transferring option from InterpKernelDEC to ElementLocator   
149         locator.copyOptions(*this);
150         MEDCouplingPointSet* distant_mesh=0; 
151         mcIdType* distant_ids=0;
152         std::string distantMeth;
153         for (int i=0; i<_target_group->size(); i++)
154           {
155             //        int idistant_proc = (i+_source_group->myRank())%_target_group->size();
156             int idistant_proc=i;
157
158             //gathers pieces of the target meshes that can intersect the local mesh
159             locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids);
160             if (distant_mesh !=0)
161               {
162                 locator.exchangeMethod(_method,idistant_proc,distantMeth);
163                 //adds the contribution of the distant mesh on the local one
164                 int idistant_proc_in_union=_union_group->translateRank(_target_group,idistant_proc);
165                 //std::cout <<"add contribution from proc "<<idistant_proc_in_union<<" to proc "<<_union_group->myRank()<<std::endl;
166                 _interpolation_matrix->addContribution(*distant_mesh,idistant_proc_in_union,distant_ids,_method,distantMeth);
167                 distant_mesh->decrRef();
168                 delete [] distant_ids;
169                 distant_mesh=0;
170                 distant_ids=0;
171               }
172           }
173        _interpolation_matrix->finishContributionW(locator);
174       }
175
176     if (_target_group->containsMyRank())
177       {
178         ElementLocator locator(*_local_field, *_source_group, *_target_group);
179         //transferring option from InterpKernelDEC to ElementLocator
180         locator.copyOptions(*this);
181         MEDCouplingPointSet* distant_mesh=0;
182         mcIdType* distant_ids=0;
183         for (int i=0; i<_source_group->size(); i++)
184           {
185             //        int idistant_proc = (i+_target_group->myRank())%_source_group->size();
186             int  idistant_proc=i;
187             //gathers pieces of the target meshes that can intersect the local mesh
188             locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids);
189             //std::cout << " Data sent from "<<_union_group->myRank()<<" to source proc "<< idistant_proc<<std::endl;
190             if (distant_mesh!=0)
191               {
192                 std::string distantMeth;
193                 locator.exchangeMethod(_method,idistant_proc,distantMeth);
194                 distant_mesh->decrRef();
195                 delete [] distant_ids;
196                 distant_mesh=0;
197                 distant_ids=0;
198               }
199           }
200         _interpolation_matrix->finishContributionL(locator);
201       }
202     _interpolation_matrix->prepare();
203   }
204
205   /*!
206    * Set a default value for non fetched entities
207    */
208   void InterpKernelDEC::synchronizeWithDefaultValue(double val)
209   {
210     this->synchronize();
211     if(_interpolation_matrix )
212       _interpolation_matrix->setDefaultValue(val);
213   }
214
215   /*!
216     Receives the data whether the processor is on the working side or on the lazy side. It must match a \a sendData() call on the other side.
217   */
218   void InterpKernelDEC::recvData()
219   {
220     if (_source_group->containsMyRank())
221       _interpolation_matrix->transposeMultiply(*_local_field->getField());
222     else if (_target_group->containsMyRank())
223       {
224         _interpolation_matrix->multiply(*_local_field->getField());
225         if (getForcedRenormalization())
226           renormalizeTargetField(getMeasureAbsStatus());
227       }
228   }
229
230   MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIds() const
231   {
232     if( _source_group->containsMyRank() )
233     {
234       return this->retrieveNonFetchedIdsSource();
235     }
236     if( _target_group->containsMyRank() )
237     {
238       return this->retrieveNonFetchedIdsTarget();
239     }
240     THROW_IK_EXCEPTION("Not detected side of rank !");
241   }
242
243   MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsSource() const
244   {
245     return _interpolation_matrix->retrieveNonFetchedIdsSource();
246   }
247
248   MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsTarget() const
249   {
250     mcIdType nbTuples = _local_field->getField()->getNumberOfTuplesExpected();
251     return _interpolation_matrix->retrieveNonFetchedIdsTarget(nbTuples);
252   }
253
254   /*!
255     Receives the data at time \a time in asynchronous mode. The value of the field
256     will be time-interpolated from the field values received.
257     \param time time at which the value is desired
258   */
259   void InterpKernelDEC::recvData( double time )
260   {
261     _interpolation_matrix->getAccessDEC()->setTime(time);
262     recvData() ;
263   }
264
265   /*!
266     Sends the data whether the processor is on the working side or on the lazy side.
267     It must match a recvData() call on the other side.
268   */
269   void InterpKernelDEC::sendData()
270   {
271     if (_source_group->containsMyRank())
272       {
273     
274         _interpolation_matrix->multiply(*_local_field->getField());
275         if (getForcedRenormalization())
276           renormalizeTargetField(getMeasureAbsStatus());
277     
278       }
279     else if (_target_group->containsMyRank())
280       _interpolation_matrix->transposeMultiply(*_local_field->getField());
281   }
282
283   /*!
284     Sends the data available at time \a time in asynchronous mode. 
285     \param time time at which the value is available
286     \param deltatime time interval between the value presently sent and the next one. 
287   */
288   void InterpKernelDEC::sendData( double time , double deltatime )
289   {
290     _interpolation_matrix->getAccessDEC()->setTime(time,deltatime);
291     sendData() ;
292   }
293   
294 }