1 // Copyright (C) 2007-2015 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"
39 * \anchor DisjointDEC-det
42 * Interface class for creation of a link between two
43 * processor groups for exhanging mesh or field data.
44 * The \c DEC is defined by attaching a field on the receiving or on the
46 * On top of attaching a \c ParaMEDMEM::ParaFIELD, it is possible to
47 * attach a ICoCo::Field. This class is an abstract class that enables
48 * coupling of codes that respect the ICoCo interface \ref icoco. It has two implementations:
49 * one for codes that express their fields as \ref fields "MEDCoupling fields" (ICoCo::MEDField).
51 * \section dec_options DEC Options
52 * Options supported by \c DEC objects are
55 * <TR><TD>Option</TD><TD>Description</TD><TD>Default value</TD></TR>
56 * <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>
60 The following code excerpt shows how to set options for an object that inherits from \c DEC :
63 InterpKernelDEC dec(source_group,target_group);
64 dec.setOptions("ForcedRenormalization",true);
65 dec.attachLocalField(field);
67 if (source_group.containsMyRank())
75 DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):_local_field(0),
76 _source_group(&source_group),
77 _target_group(&target_group),
81 _union_group = source_group.fuse(target_group);
84 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)
89 DisjointDEC & DisjointDEC::operator=(const DisjointDEC& s)
97 void DisjointDEC::copyInstance(const DisjointDEC& other)
100 if(other._target_group)
102 _target_group=other._target_group->deepCpy();
105 if(other._source_group)
107 _source_group=other._source_group->deepCpy();
110 if (_source_group && _target_group)
111 _union_group = _source_group->fuse(*_target_group);
114 DisjointDEC::DisjointDEC(const std::set<int>& source_ids, const std::set<int>& target_ids, const MPI_Comm& world_comm):_local_field(0),
118 ParaMEDMEM::CommInterface comm;
119 // Create the list of procs including source and target
120 std::set<int> union_ids; // source and target ids in world_comm
121 union_ids.insert(source_ids.begin(),source_ids.end());
122 union_ids.insert(target_ids.begin(),target_ids.end());
123 if(union_ids.size()!=(source_ids.size()+target_ids.size()))
124 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 !");
125 int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm
126 std::copy(union_ids.begin(), union_ids.end(), union_ranks_world);
128 // Create a communicator on these procs
129 MPI_Group union_group,world_group;
130 comm.commGroup(world_comm,&world_group);
131 comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
133 comm.commCreate(world_comm,union_group,&union_comm);
134 delete[] union_ranks_world;
136 if (union_comm==MPI_COMM_NULL)
137 { // This process is not in union
144 // Translate source_ids and target_ids from world_comm to union_comm
145 int* source_ranks_world=new int[source_ids.size()]; // ranks of sources in world_comm
146 std::copy(source_ids.begin(), source_ids.end(),source_ranks_world);
147 int* source_ranks_union=new int[source_ids.size()]; // ranks of sources in union_comm
148 int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm
149 std::copy(target_ids.begin(), target_ids.end(),target_ranks_world);
150 int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm
151 MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union);
152 MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union);
153 std::set<int> source_ids_union;
154 for (int i=0;i<(int)source_ids.size();i++)
155 source_ids_union.insert(source_ranks_union[i]);
156 std::set<int> target_ids_union;
157 for (int i=0;i<(int)target_ids.size();i++)
158 target_ids_union.insert(target_ranks_union[i]);
159 delete [] source_ranks_world;
160 delete [] source_ranks_union;
161 delete [] target_ranks_world;
162 delete [] target_ranks_union;
164 // Create the MPIProcessorGroups
165 _source_group = new MPIProcessorGroup(comm,source_ids_union,union_comm);
166 _target_group = new MPIProcessorGroup(comm,target_ids_union,union_comm);
167 _union_group = _source_group->fuse(*_target_group);
171 DisjointDEC::~DisjointDEC()
176 void DisjointDEC::cleanInstance()
186 delete _source_group;
187 delete _target_group;
196 void DisjointDEC::setNature(NatureOfField nature)
199 _local_field->getField()->setNature(nature);
202 /*! Attaches a local field to a DEC.
203 If the processor is on the receiving end of the DEC, the field
204 will be updated by a recvData() call.
205 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
207 void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt)
215 _comm_interface=&(field->getTopology()->getProcGroup()->getCommInterface());
216 compareFieldAndMethod();
219 /*! Attaches a local field to a DEC. The method will test whether the processor
220 is on the source or the target side and will associate the mesh underlying the
221 field to the local side.
223 If the processor is on the receiving end of the DEC, the field
224 will be updated by a recvData() call.
225 Reversely, if the processor is on the sending end, the field will be read, possibly transformed,
226 and sent appropriately to the other side.
229 void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field)
233 ProcessorGroup* local_group;
234 if (_source_group->containsMyRank())
235 local_group=_source_group;
236 else if (_target_group->containsMyRank())
237 local_group=_target_group;
239 throw INTERP_KERNEL::Exception("Invalid procgroup for field attachment to DEC");
240 ParaMESH *paramesh=new ParaMESH(static_cast<MEDCouplingPointSet *>(const_cast<MEDCouplingMesh *>(field->getMesh())),*local_group,field->getMesh()->getName());
241 ParaFIELD *tmp=new ParaFIELD(field, paramesh, *local_group);
242 tmp->setOwnSupport(true);
243 attachLocalField(tmp,true);
244 //_comm_interface=&(local_group->getCommInterface());
248 Attaches a local field to a DEC.
249 If the processor is on the receiving end of the DEC, the field
250 will be updated by a recvData() call.
251 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
252 The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields :
253 - a ICoCo::MEDField, that is created from a MEDCoupling structure
256 void DisjointDEC::attachLocalField(const ICoCo::MEDField *field)
261 throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !");
262 attachLocalField(field->getField());
266 Computes the field norm over its support
267 on the source side and renormalizes the field on the target side
268 so that the norms match.
271 I_{source}=\sum_{i=1}^{n_{source}}V_{i}.|\Phi^{source}_{i}|^2,
275 I_{target}=\sum_{i=1}^{n_{target}}V_{i}.|\Phi^{target}_{i}|^2,
279 \Phi^{target}:=\Phi^{target}.\sqrt{I_{source}/I_{target}}.
283 void DisjointDEC::renormalizeTargetField(bool isWAbs)
285 if (_source_group->containsMyRank())
286 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
288 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
289 double source_norm = total_norm;
290 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
293 if (_target_group->containsMyRank())
295 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
297 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
298 double source_norm=total_norm;
299 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
301 if (fabs(total_norm)>1e-100)
302 _local_field->getField()->applyLin(source_norm/total_norm,0.0,icomp+1);
307 bool DisjointDEC::isInSourceSide() const
311 return _source_group->containsMyRank();
314 bool DisjointDEC::isInTargetSide() const
318 return _target_group->containsMyRank();
321 bool DisjointDEC::isInUnion() const
325 return _union_group->containsMyRank();
328 void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception)
332 TypeOfField entity = _local_field->getField()->getTypeOfField();
333 if ( getMethod() == "P0" )
335 if ( entity != ON_CELLS )
336 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
337 " For P0 interpolation, field must be on MED_CELL's");
339 else if ( getMethod() == "P1" )
341 if ( entity != ON_NODES )
342 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
343 " For P1 interpolation, field must be on MED_NODE's");
345 else if ( getMethod() == "P1d" )
347 if ( entity != ON_CELLS )
348 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
349 " For P1d interpolation, field must be on MED_CELL's");
350 if ( _target_group->containsMyRank() )
351 throw INTERP_KERNEL::Exception("Projection to P1d field not supported");
355 throw INTERP_KERNEL::Exception("Unknown interpolation method. Possible methods: P0, P1, P1d");
361 If way==true, source procs call sendData() and target procs call recvData().
362 if way==false, it's the other way round.
364 void DisjointDEC::sendRecvData(bool way)
375 else if(isInTargetSide())