Salome HOME
Various fixes for test runs - introducing MEDCOUPLING_RESOURCE_DIR env variable
[tools/medcoupling.git] / src / ParaMEDMEM / InterpKernelDEC.cxx
1 // Copyright (C) 2007-2020  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 "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   InterpKernelDEC::~InterpKernelDEC()
73   {
74     if (_interpolation_matrix !=0)
75       delete _interpolation_matrix;
76   } 
77
78   /*! 
79     \brief Synchronization process for exchanging topologies.
80
81     This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh
82     underlying the fields that have been set with attachLocalField method.
83     It works in four steps :
84     -# Bounding boxes are computed for each sub-domain,
85     -# The lazy side mesh parts that are likely to intersect the working side local processor are sent to the working side,
86     -# The working side calls the interpolation kernel to compute the intersection between local and imported mesh.
87     -# The lazy side is updated so that it knows the structure of the data that will be sent by
88     the working side during a \a sendData() call.
89
90   */
91   void InterpKernelDEC::synchronize()
92   {
93     if(!isInUnion())
94       return ;
95     delete _interpolation_matrix;
96     _interpolation_matrix = new InterpolationMatrix (_local_field, *_source_group,*_target_group,*this,*this); 
97
98     //setting up the communication DEC on both sides  
99     if (_source_group->containsMyRank())
100       {
101         //locate the distant meshes
102         ElementLocator locator(*_local_field, *_target_group, *_source_group);
103         //transferring option from InterpKernelDEC to ElementLocator   
104         locator.copyOptions(*this);
105         MEDCouplingPointSet* distant_mesh=0; 
106         mcIdType* distant_ids=0;
107         std::string distantMeth;
108         for (int i=0; i<_target_group->size(); i++)
109           {
110             //        int idistant_proc = (i+_source_group->myRank())%_target_group->size();
111             int idistant_proc=i;
112
113             //gathers pieces of the target meshes that can intersect the local mesh
114             locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids);
115             if (distant_mesh !=0)
116               {
117                 locator.exchangeMethod(_method,idistant_proc,distantMeth);
118                 //adds the contribution of the distant mesh on the local one
119                 int idistant_proc_in_union=_union_group->translateRank(_target_group,idistant_proc);
120                 //std::cout <<"add contribution from proc "<<idistant_proc_in_union<<" to proc "<<_union_group->myRank()<<std::endl;
121                 _interpolation_matrix->addContribution(*distant_mesh,idistant_proc_in_union,distant_ids,_method,distantMeth);
122                 distant_mesh->decrRef();
123                 delete [] distant_ids;
124                 distant_mesh=0;
125                 distant_ids=0;
126               }
127           }
128        _interpolation_matrix->finishContributionW(locator);
129       }
130
131     if (_target_group->containsMyRank())
132       {
133         ElementLocator locator(*_local_field, *_source_group, *_target_group);
134         //transferring option from InterpKernelDEC to ElementLocator
135         locator.copyOptions(*this);
136         MEDCouplingPointSet* distant_mesh=0;
137         mcIdType* distant_ids=0;
138         for (int i=0; i<_source_group->size(); i++)
139           {
140             //        int idistant_proc = (i+_target_group->myRank())%_source_group->size();
141             int  idistant_proc=i;
142             //gathers pieces of the target meshes that can intersect the local mesh
143             locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids);
144             //std::cout << " Data sent from "<<_union_group->myRank()<<" to source proc "<< idistant_proc<<std::endl;
145             if (distant_mesh!=0)
146               {
147                 std::string distantMeth;
148                 locator.exchangeMethod(_method,idistant_proc,distantMeth);
149                 distant_mesh->decrRef();
150                 delete [] distant_ids;
151                 distant_mesh=0;
152                 distant_ids=0;
153               }
154           }
155         _interpolation_matrix->finishContributionL(locator);
156       }
157     _interpolation_matrix->prepare();
158   }
159
160
161   /*!
162     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.
163   */
164   void InterpKernelDEC::recvData()
165   {
166     if (_source_group->containsMyRank())
167       _interpolation_matrix->transposeMultiply(*_local_field->getField());
168     else if (_target_group->containsMyRank())
169       {
170         _interpolation_matrix->multiply(*_local_field->getField());
171         if (getForcedRenormalization())
172           renormalizeTargetField(getMeasureAbsStatus());
173       }
174   }
175
176
177   /*!
178     Receives the data at time \a time in asynchronous mode. The value of the field
179     will be time-interpolated from the field values received.
180     \param time time at which the value is desired
181   */
182   void InterpKernelDEC::recvData( double time )
183   {
184     _interpolation_matrix->getAccessDEC()->setTime(time);
185     recvData() ;
186   }
187
188   /*!
189     Sends the data whether the processor is on the working side or on the lazy side.
190     It must match a recvData() call on the other side.
191   */
192   void InterpKernelDEC::sendData()
193   {
194     if (_source_group->containsMyRank())
195       {
196     
197         _interpolation_matrix->multiply(*_local_field->getField());
198         if (getForcedRenormalization())
199           renormalizeTargetField(getMeasureAbsStatus());
200     
201       }
202     else if (_target_group->containsMyRank())
203       _interpolation_matrix->transposeMultiply(*_local_field->getField());
204   }
205
206   /*!
207     Sends the data available at time \a time in asynchronous mode. 
208     \param time time at which the value is available
209     \param deltatime time interval between the value presently sent and the next one. 
210   */
211   void InterpKernelDEC::sendData( double time , double deltatime )
212   {
213     _interpolation_matrix->getAccessDEC()->setTime(time,deltatime);
214     sendData() ;
215   }
216   
217 }