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) and one
46 * for codes that express their fields as Trio/U fields.
48 * \section dec_options DEC Options
49 * Options supported by \c DEC objects are
52 * <TR><TD>Option</TD><TD>Description</TD><TD>Default value</TD></TR>
53 * <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>
57 The following code excerpt shows how to set options for an object that inherits from \c DEC :
60 InterpKernelDEC dec(source_group,target_group);
61 dec.setOptions("ForcedRenormalization",true);
62 dec.attachLocalField(field);
64 if (source_group.containsMyRank())
78 DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):_local_field(0),
79 _source_group(&source_group),
80 _target_group(&target_group),
84 _union_group = source_group.fuse(target_group);
87 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)
92 DisjointDEC & DisjointDEC::operator=(const DisjointDEC& s)
100 void DisjointDEC::copyInstance(const DisjointDEC& other)
102 DEC::copyFrom(other);
103 if(other._target_group)
105 _target_group=other._target_group->deepCpy();
108 if(other._source_group)
110 _source_group=other._source_group->deepCpy();
113 if (_source_group && _target_group)
114 _union_group = _source_group->fuse(*_target_group);
117 DisjointDEC::DisjointDEC(const std::set<int>& source_ids, const std::set<int>& target_ids, const MPI_Comm& world_comm):_local_field(0),
121 ParaMEDMEM::CommInterface comm;
122 // Create the list of procs including source and target
123 std::set<int> union_ids; // source and target ids in world_comm
124 union_ids.insert(source_ids.begin(),source_ids.end());
125 union_ids.insert(target_ids.begin(),target_ids.end());
126 if(union_ids.size()!=(source_ids.size()+target_ids.size()))
127 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 !");
128 int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm
129 std::copy(union_ids.begin(), union_ids.end(), union_ranks_world);
131 // Create a communicator on these procs
132 MPI_Group union_group,world_group;
133 comm.commGroup(world_comm,&world_group);
134 comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
136 comm.commCreate(world_comm,union_group,&union_comm);
137 delete[] union_ranks_world;
139 if (union_comm==MPI_COMM_NULL)
140 { // This process is not in union
147 // Translate source_ids and target_ids from world_comm to union_comm
148 int* source_ranks_world=new int[source_ids.size()]; // ranks of sources in world_comm
149 std::copy(source_ids.begin(), source_ids.end(),source_ranks_world);
150 int* source_ranks_union=new int[source_ids.size()]; // ranks of sources in union_comm
151 int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm
152 std::copy(target_ids.begin(), target_ids.end(),target_ranks_world);
153 int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm
154 MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union);
155 MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union);
156 std::set<int> source_ids_union;
157 for (int i=0;i<(int)source_ids.size();i++)
158 source_ids_union.insert(source_ranks_union[i]);
159 std::set<int> target_ids_union;
160 for (int i=0;i<(int)target_ids.size();i++)
161 target_ids_union.insert(target_ranks_union[i]);
162 delete [] source_ranks_world;
163 delete [] source_ranks_union;
164 delete [] target_ranks_world;
165 delete [] target_ranks_union;
167 // Create the MPIProcessorGroups
168 _source_group = new MPIProcessorGroup(comm,source_ids_union,union_comm);
169 _target_group = new MPIProcessorGroup(comm,target_ids_union,union_comm);
170 _union_group = _source_group->fuse(*_target_group);
174 DisjointDEC::~DisjointDEC()
179 void DisjointDEC::cleanInstance()
189 delete _source_group;
190 delete _target_group;
199 void DisjointDEC::setNature(NatureOfField nature)
202 _local_field->getField()->setNature(nature);
205 /*! Attaches a local field to a DEC.
206 If the processor is on the receiving end of the DEC, the field
207 will be updated by a recvData() call.
208 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
210 void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt)
218 _comm_interface=&(field->getTopology()->getProcGroup()->getCommInterface());
219 compareFieldAndMethod();
222 /*! Attaches a local field to a DEC. The method will test whether the processor
223 is on the source or the target side and will associate the mesh underlying the
224 field to the local side.
226 If the processor is on the receiving end of the DEC, the field
227 will be updated by a recvData() call.
228 Reversely, if the processor is on the sending end, the field will be read, possibly transformed,
229 and sent appropriately to the other side.
232 void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field)
236 ProcessorGroup* local_group;
237 if (_source_group->containsMyRank())
238 local_group=_source_group;
239 else if (_target_group->containsMyRank())
240 local_group=_target_group;
242 throw INTERP_KERNEL::Exception("Invalid procgroup for field attachment to DEC");
243 ParaMESH *paramesh=new ParaMESH(static_cast<MEDCouplingPointSet *>(const_cast<MEDCouplingMesh *>(field->getMesh())),*local_group,field->getMesh()->getName());
244 ParaFIELD *tmp=new ParaFIELD(field, paramesh, *local_group);
245 tmp->setOwnSupport(true);
246 attachLocalField(tmp,true);
247 //_comm_interface=&(local_group->getCommInterface());
251 Attaches a local field to a DEC.
252 If the processor is on the receiving end of the DEC, the field
253 will be updated by a recvData() call.
254 Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
255 The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields :
256 - a ICoCo::MEDField, that is created from a MEDCoupling structure
257 - a ICOCo::TrioField, that is created from tables extracted from a TRIO-U structure.
260 void DisjointDEC::attachLocalField(const ICoCo::MEDField *field)
265 throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !");
266 attachLocalField(field->getField());
270 Computes the field norm over its support
271 on the source side and renormalizes the field on the target side
272 so that the norms match.
275 I_{source}=\sum_{i=1}^{n_{source}}V_{i}.|\Phi^{source}_{i}|^2,
279 I_{target}=\sum_{i=1}^{n_{target}}V_{i}.|\Phi^{target}_{i}|^2,
283 \Phi^{target}:=\Phi^{target}.\sqrt{I_{source}/I_{target}}.
287 void DisjointDEC::renormalizeTargetField(bool isWAbs)
289 if (_source_group->containsMyRank())
290 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
292 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
293 double source_norm = total_norm;
294 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
297 if (_target_group->containsMyRank())
299 for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
301 double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
302 double source_norm=total_norm;
303 _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast<MPIProcessorGroup*>(_union_group)->getComm());
305 if (fabs(total_norm)>1e-100)
306 _local_field->getField()->applyLin(source_norm/total_norm,0.0,icomp+1);
312 bool DisjointDEC::isInSourceSide() const
316 return _source_group->containsMyRank();
319 bool DisjointDEC::isInTargetSide() const
323 return _target_group->containsMyRank();
326 bool DisjointDEC::isInUnion() const
330 return _union_group->containsMyRank();
333 void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception)
337 TypeOfField entity = _local_field->getField()->getTypeOfField();
338 if ( getMethod() == "P0" )
340 if ( entity != ON_CELLS )
341 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
342 " For P0 interpolation, field must be on MED_CELL's");
344 else if ( getMethod() == "P1" )
346 if ( entity != ON_NODES )
347 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
348 " For P1 interpolation, field must be on MED_NODE's");
350 else if ( getMethod() == "P1d" )
352 if ( entity != ON_CELLS )
353 throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch."
354 " For P1d interpolation, field must be on MED_CELL's");
355 if ( _target_group->containsMyRank() )
356 throw INTERP_KERNEL::Exception("Projection to P1d field not supported");
360 throw INTERP_KERNEL::Exception("Unknown interpolation method. Possible methods: P0, P1, P1d");
366 If way==true, source procs call sendData() and target procs call recvData().
367 if way==false, it's the other way round.
369 void DisjointDEC::sendRecvData(bool way)
380 else if(isInTargetSide())