1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D
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
20 #include "DisjointDEC.hxx"
21 #include "CommInterface.hxx"
22 #include "Topology.hxx"
23 #include "BlockTopology.hxx"
24 #include "ComponentTopology.hxx"
25 #include "ParaFIELD.hxx"
26 #include "ParaMESH.hxx"
27 #include "ICoCoField.hxx"
28 #include "ICoCoMEDField.hxx"
29 #include "MPIProcessorGroup.hxx"
36 * \section decintroduction Introduction
38 * Interface class for creation of a link between two
39 * processor groups for exhanging mesh or field data.
40 * The \c DEC is defined by attaching a field on the receiving or on the
42 * On top of attaching a \c ParaMEDMEM::FIELD, it is possible to
43 * attach a ICoCo::Field. This class is an abstract class that enables
44 * coupling of codes that respect the ICoCo interface \ref icoco. It has two implementations:
45 * one for codes that express their fields as \ref medoupling fields (ICoCo::MEDField).
47 * \section dec_options DEC Options
48 * Options supported by \c DEC objects are
51 * <TR><TD>Option</TD><TD>Description</TD><TD>Default value</TD></TR>
52 * <TR><TD>ForcedRenormalization</TD><TD>After receiving data, the target field is renormalized so that L2-norms of the source and target fields match.</TD><TD> false </TD></TR>
56 The following code excerpt shows how to set options for an object that inherits from \c DEC :
59 InterpKernelDEC dec(source_group,target_group);
60 dec.setOptions("ForcedRenormalization",true);
61 dec.attachLocalField(field);
63 if (source_group.containsMyRank())
77 DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):_local_field(0),
78 _source_group(&source_group),
79 _target_group(&target_group),
83 _union_group = source_group.fuse(target_group);
86 DisjointDEC::DisjointDEC(const DisjointDEC& s):DEC(s),_local_field(0),_union_group(0),_source_group(0),_target_group(0),_owns_field(false),_owns_groups(false)
91 DisjointDEC & DisjointDEC::operator=(const DisjointDEC& s)
99 void DisjointDEC::copyInstance(const DisjointDEC& other)
101 DEC::copyFrom(other);
102 if(other._target_group)
104 _target_group=other._target_group->deepCpy();
107 if(other._source_group)
109 _source_group=other._source_group->deepCpy();
112 if (_source_group && _target_group)
113 _union_group = _source_group->fuse(*_target_group);
116 DisjointDEC::DisjointDEC(const std::set<int>& source_ids, const std::set<int>& target_ids, const MPI_Comm& world_comm):_local_field(0),
120 ParaMEDMEM::CommInterface comm;
121 // Create the list of procs including source and target
122 std::set<int> union_ids; // source and target ids in world_comm
123 union_ids.insert(source_ids.begin(),source_ids.end());
124 union_ids.insert(target_ids.begin(),target_ids.end());
125 if(union_ids.size()!=(source_ids.size()+target_ids.size()))
126 throw INTERP_KERNEL::Exception("DisjointDEC constructor : source_ids and target_ids overlap partially or fully. This type of DEC does not support it ! OverlapDEC class could be the solution !");
127 int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm
128 std::copy(union_ids.begin(), union_ids.end(), union_ranks_world);
130 // Create a communicator on these procs
131 MPI_Group union_group,world_group;
132 comm.commGroup(world_comm,&world_group);
133 comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
135 comm.commCreate(world_comm,union_group,&union_comm);
136 delete[] union_ranks_world;
138 if (union_comm==MPI_COMM_NULL)
139 { // This process is not in union
146 // Translate source_ids and target_ids from world_comm to union_comm
147 int* source_ranks_world=new int[source_ids.size()]; // ranks of sources in world_comm
148 std::copy(source_ids.begin(), source_ids.end(),source_ranks_world);
149 int* source_ranks_union=new int[source_ids.size()]; // ranks of sources in union_comm
150 int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm
151 std::copy(target_ids.begin(), target_ids.end(),target_ranks_world);
152 int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm
153 MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union);
154 MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union);
155 std::set<int> source_ids_union;
156 for (int i=0;i<(int)source_ids.size();i++)
157 source_ids_union.insert(source_ranks_union[i]);
158 std::set<int> target_ids_union;
159 for (int i=0;i<(int)target_ids.size();i++)
160 target_ids_union.insert(target_ranks_union[i]);
161 delete [] source_ranks_world;
162 delete [] source_ranks_union;
163 delete [] target_ranks_world;
164 delete [] target_ranks_union;
166 // Create the MPIProcessorGroups
167 _source_group = new MPIProcessorGroup(comm,source_ids_union,union_comm);
168 _target_group = new MPIProcessorGroup(comm,target_ids_union,union_comm);
169 _union_group = _source_group->fuse(*_target_group);
173 DisjointDEC::~DisjointDEC()
178 void DisjointDEC::cleanInstance()
188 delete _source_group;
189 delete _target_group;
198 void DisjointDEC::setNature(NatureOfField nature)
201 _local_field->getField()->setNature(nature);
204 /*! Attaches a local field to a DEC.
205 If the processor is on the receiving end of the DEC, the field
206 will be updated by a recvData() call.
207 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
209 void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt)
217 _comm_interface=&(field->getTopology()->getProcGroup()->getCommInterface());
218 compareFieldAndMethod();
221 /*! Attaches a local field to a DEC. The method will test whether the processor
222 is on the source or the target side and will associate the mesh underlying the
223 field to the local side.
225 If the processor is on the receiving end of the DEC, the field
226 will be updated by a recvData() call.
227 Reversely, if the processor is on the sending end, the field will be read, possibly transformed,
228 and sent appropriately to the other side.
231 void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field)
235 ProcessorGroup* local_group;
236 if (_source_group->containsMyRank())
237 local_group=_source_group;
238 else if (_target_group->containsMyRank())
239 local_group=_target_group;
241 throw INTERP_KERNEL::Exception("Invalid procgroup for field attachment to DEC");
242 ParaMESH *paramesh=new ParaMESH(static_cast<MEDCouplingPointSet *>(const_cast<MEDCouplingMesh *>(field->getMesh())),*local_group,field->getMesh()->getName());
243 ParaFIELD *tmp=new ParaFIELD(field, paramesh, *local_group);
244 tmp->setOwnSupport(true);
245 attachLocalField(tmp,true);
246 //_comm_interface=&(local_group->getCommInterface());
250 Attaches a local field to a DEC.
251 If the processor is on the receiving end of the DEC, the field
252 will be updated by a recvData() call.
253 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
254 The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields :
255 - a ICoCo::MEDField, that is created from a MEDCoupling structure
258 void DisjointDEC::attachLocalField(const ICoCo::MEDField *field)
263 throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !");
264 attachLocalField(field->getField());
268 Computes the field norm over its support
269 on the source side and renormalizes the field on the target side
270 so that the norms match.
273 I_{source}=\sum_{i=1}^{n_{source}}V_{i}.|\Phi^{source}_{i}|^2,
277 I_{target}=\sum_{i=1}^{n_{target}}V_{i}.|\Phi^{target}_{i}|^2,
281 \Phi^{target}:=\Phi^{target}.\sqrt{I_{source}/I_{target}}.
285 void DisjointDEC::renormalizeTargetField(bool isWAbs)
287 if (_source_group->containsMyRank())
288 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
290 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
291 double source_norm = total_norm;
292 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
295 if (_target_group->containsMyRank())
297 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
299 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
300 double source_norm=total_norm;
301 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
303 if (fabs(total_norm)>1e-100)
304 _local_field->getField()->applyLin(source_norm/total_norm,0.0,icomp+1);
310 bool DisjointDEC::isInSourceSide() const
314 return _source_group->containsMyRank();
317 bool DisjointDEC::isInTargetSide() const
321 return _target_group->containsMyRank();
324 bool DisjointDEC::isInUnion() const
328 return _union_group->containsMyRank();
331 void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception)
335 TypeOfField entity = _local_field->getField()->getTypeOfField();
336 if ( getMethod() == "P0" )
338 if ( entity != ON_CELLS )
339 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
340 " For P0 interpolation, field must be on MED_CELL's");
342 else if ( getMethod() == "P1" )
344 if ( entity != ON_NODES )
345 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
346 " For P1 interpolation, field must be on MED_NODE's");
348 else if ( getMethod() == "P1d" )
350 if ( entity != ON_CELLS )
351 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
352 " For P1d interpolation, field must be on MED_CELL's");
353 if ( _target_group->containsMyRank() )
354 throw INTERP_KERNEL::Exception("Projection to P1d field not supported");
358 throw INTERP_KERNEL::Exception("Unknown interpolation method. Possible methods: P0, P1, P1d");
364 If way==true, source procs call sendData() and target procs call recvData().
365 if way==false, it's the other way round.
367 void DisjointDEC::sendRecvData(bool way)
378 else if(isInTargetSide())