1 // Copyright (C) 2007-2023 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
20 #include "Topology.hxx"
21 #include "BlockTopology.hxx"
22 #include "ComponentTopology.hxx"
23 #include "ExplicitCoincidentDEC.hxx"
24 #include "StructuredCoincidentDEC.hxx"
25 #include "CommInterface.hxx"
26 #include "ProcessorGroup.hxx"
27 #include "MPIProcessorGroup.hxx"
28 #include "ParaFIELD.hxx"
29 #include "ParaMESH.hxx"
30 #include "InterpKernelUtilities.hxx"
31 #include "InterpolationMatrix.hxx"
41 This class encapsulates parallel fields.
43 It gathers a \ref fields "MEDCouplingField" with some extra information related to the parallel
46 It is most conveniently created by giving a pointer to a MEDCouplingFieldDouble
47 object and a ProcessorGroup.
48 By default, a ParaFIELD object will be constructed with all field components
49 located on the same processors. In some specific cases, it might be necessary to scatter components over
50 several processors. In this case, the constructor using a ComponentTopology is required.
56 \brief Constructing a \c ParaFIELD from a \c ParaMESH and a \c ComponentTopology.
58 This constructor creates an empty field based on the ParaMESH description
59 and the partitioning of components described in \a component_topology.
60 It takes ownership over the \c _field object that it creates.
62 Here come the three ComponentTopology constructors :
64 ComponentTopology c; // one component in the field
65 ComponentTopology c(6); //six components, all of them on the same processor
66 ComponentTopology c(6, proc_group); // six components, evenly distributed over the processors of procgroup
70 ParaFIELD::ParaFIELD(TypeOfField type, TypeOfTimeDiscretization td, ParaMESH* para_support, const ComponentTopology& component_topology)
72 _component_topology(component_topology),_topology(0),_own_support(false),
73 _support(para_support)
75 if (para_support->isStructured() || (para_support->getTopology()->getProcGroup()->size()==1 && component_topology.nbBlocks()!=1))
77 const BlockTopology* source_topo = dynamic_cast<const BlockTopology*>(para_support->getTopology());
78 _topology=new BlockTopology(*source_topo,component_topology);
82 if (component_topology.nbBlocks()!=1 && para_support->getTopology()->getProcGroup()->size()!=1)
83 throw INTERP_KERNEL::Exception(LOCALIZED("ParaFIELD constructor : Unstructured Support not taken into account with component topology yet"));
86 const BlockTopology* source_topo=dynamic_cast<const BlockTopology*> (para_support->getTopology());
87 int nb_local_comp=component_topology.nbLocalComponents();
88 _topology=new BlockTopology(*source_topo,nb_local_comp);
91 int nb_components = component_topology.nbLocalComponents();
94 _field=MEDCouplingFieldDouble::New(type,td);
95 _field->setMesh(_support->getCellMesh());
96 DataArrayDouble *array=DataArrayDouble::New();
97 array->alloc(_field->getNumberOfTuples(),nb_components);
98 _field->setArray(array);
103 _field->setName("Default ParaFIELD name");
104 _field->setDescription("Default ParaFIELD description");
107 /*! \brief Constructor creating the ParaFIELD
108 from a given FIELD and a processor group.
110 This constructor supposes that support underlying \a subdomain_field has no ParaMESH
111 attached and it therefore recreates one. It therefore takes ownership over _support. The component topology associated with the field is a basic one (all components on the same processor).
113 ParaFIELD::ParaFIELD(MEDCouplingFieldDouble* subdomain_field, ParaMESH *sup, const ProcessorGroup& proc_group):
114 _field(subdomain_field),
115 _component_topology(ComponentTopology((int)_field->getNumberOfComponents())),_topology(0),_own_support(false),
120 const BlockTopology* source_topo=dynamic_cast<const BlockTopology*> (_support->getTopology());
121 _topology=new BlockTopology(*source_topo,_component_topology.nbLocalComponents());
124 ParaFIELD::~ParaFIELD()
129 /** Destructor involves MPI operations: make sure this is accessible from a proper
130 * method for Python wrapping.
132 void ParaFIELD::release()
149 void ParaFIELD::synchronizeTarget(ParaFIELD* source_field)
151 DisjointDEC* data_channel;
152 if (dynamic_cast<BlockTopology*>(_topology)!=0)
154 data_channel=new StructuredCoincidentDEC;
158 data_channel=new ExplicitCoincidentDEC;
160 data_channel->attachLocalField(this);
161 data_channel->synchronize();
162 data_channel->prepareTargetDE();
163 data_channel->recvData();
168 void ParaFIELD::synchronizeSource(ParaFIELD* target_field)
170 DisjointDEC* data_channel;
171 if (dynamic_cast<BlockTopology*>(_topology)!=0)
173 data_channel=new StructuredCoincidentDEC;
177 data_channel=new ExplicitCoincidentDEC;
179 data_channel->attachLocalField(this);
180 data_channel->synchronize();
181 data_channel->prepareSourceDE();
182 data_channel->sendData();
188 * This method returns, if it exists, an array with only one component and as many as tuples as _field has.
189 * This array gives for every element on which this->_field lies, its global number, if this->_field is nodal.
190 * For example if _field is a nodal field : returned array will be the nodal global numbers.
191 * The content of this method is used to inform Working side to accumulate data received by lazy side.
193 DataArrayIdType* ParaFIELD::returnCumulativeGlobalNumbering() const
197 TypeOfField type=_field->getTypeOfField();
203 return _support->getGlobalNumberingNodeDA();
209 DataArrayIdType* ParaFIELD::returnGlobalNumbering() const
213 TypeOfField type=_field->getTypeOfField();
217 return _support->getGlobalNumberingCellDA();
219 return _support->getGlobalNumberingNodeDA();
225 int ParaFIELD::nbComponents() const
227 return _component_topology.nbComponents();
231 /*! This method retrieves the integral of component \a icomp
232 over the all domain. */
233 double ParaFIELD::getVolumeIntegral(int icomp, bool isWAbs) const
235 CommInterface comm_interface = _topology->getProcGroup()->getCommInterface();
236 double integral=_field->integral(icomp,isWAbs);
238 const MPI_Comm* comm = (dynamic_cast<const MPIProcessorGroup*>(_topology->getProcGroup()))->getComm();
239 comm_interface.allReduce(&integral, &total, 1, MPI_DOUBLE, MPI_SUM, *comm);