1 // Copyright (C) 2007-2024 CEA, EDF
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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"
29 #include "InterpolationMatrix.hxx"
30 #include "InterpKernelDEC.hxx"
31 #include "ElementLocator.hxx"
35 InterpKernelDEC::InterpKernelDEC():
37 _interpolation_matrix(0)
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.
48 \param source_group working side ProcessorGroup
49 \param target_group lazy side ProcessorGroup
52 InterpKernelDEC::InterpKernelDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
53 DisjointDEC(source_group, target_group),
54 _interpolation_matrix(0)
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).
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)
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).
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)
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
87 static std::pair<std::string,std::string> GetGroupsName( const std::string& interaction_group )
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.");
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);
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.
104 InterpKernelDEC::InterpKernelDEC(ProcessorGroup& generic_group, const std::string& interaction_group ):
105 InterpKernelDEC(generic_group,GetGroupsName(interaction_group).first,GetGroupsName(interaction_group).second)
109 InterpKernelDEC::~InterpKernelDEC()
114 void InterpKernelDEC::release()
116 if (_interpolation_matrix != nullptr)
117 delete _interpolation_matrix;
118 _interpolation_matrix = nullptr;
119 DisjointDEC::cleanInstance();
124 \brief Synchronization process for exchanging topologies.
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.
136 void InterpKernelDEC::synchronize()
140 delete _interpolation_matrix;
141 _interpolation_matrix = new InterpolationMatrix (_local_field, *_source_group,*_target_group,*this,*this);
143 //setting up the communication DEC on both sides
144 if (_source_group->containsMyRank())
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++)
155 // int idistant_proc = (i+_source_group->myRank())%_target_group->size();
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)
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;
173 _interpolation_matrix->finishContributionW(locator);
176 if (_target_group->containsMyRank())
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++)
185 // int idistant_proc = (i+_target_group->myRank())%_source_group->size();
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;
192 std::string distantMeth;
193 locator.exchangeMethod(_method,idistant_proc,distantMeth);
194 distant_mesh->decrRef();
195 delete [] distant_ids;
200 _interpolation_matrix->finishContributionL(locator);
202 _interpolation_matrix->prepare();
206 * Set a default value for non fetched entities
208 void InterpKernelDEC::synchronizeWithDefaultValue(double val)
211 if(_interpolation_matrix )
212 _interpolation_matrix->setDefaultValue(val);
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.
218 void InterpKernelDEC::recvData()
220 if (_source_group->containsMyRank())
221 _interpolation_matrix->transposeMultiply(*_local_field->getField());
222 else if (_target_group->containsMyRank())
224 _interpolation_matrix->multiply(*_local_field->getField());
225 if (getForcedRenormalization())
226 renormalizeTargetField(getMeasureAbsStatus());
230 MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIds() const
232 if( _source_group->containsMyRank() )
234 return this->retrieveNonFetchedIdsSource();
236 if( _target_group->containsMyRank() )
238 return this->retrieveNonFetchedIdsTarget();
240 THROW_IK_EXCEPTION("Not detected side of rank !");
243 MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsSource() const
245 return _interpolation_matrix->retrieveNonFetchedIdsSource();
248 MCAuto<DataArrayIdType> InterpKernelDEC::retrieveNonFetchedIdsTarget() const
250 mcIdType nbTuples = _local_field->getField()->getNumberOfTuplesExpected();
251 return _interpolation_matrix->retrieveNonFetchedIdsTarget(nbTuples);
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
259 void InterpKernelDEC::recvData( double time )
261 _interpolation_matrix->getAccessDEC()->setTime(time);
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.
269 void InterpKernelDEC::sendData()
271 if (_source_group->containsMyRank())
274 _interpolation_matrix->multiply(*_local_field->getField());
275 if (getForcedRenormalization())
276 renormalizeTargetField(getMeasureAbsStatus());
279 else if (_target_group->containsMyRank())
280 _interpolation_matrix->transposeMultiply(*_local_field->getField());
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.
288 void InterpKernelDEC::sendData( double time , double deltatime )
290 _interpolation_matrix->getAccessDEC()->setTime(time,deltatime);