-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D
+// Copyright (C) 2007-2024 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include "ParaFIELD.hxx"
#include "ParaMESH.hxx"
#include "ICoCoField.hxx"
-#include "ICoCoMEDField.hxx"
+#include "ICoCoMEDDoubleField.hxx"
#include "MPIProcessorGroup.hxx"
#include <cmath>
#include <iostream>
-namespace ParaMEDMEM
+namespace MEDCoupling
{
-
- /*!
- * \anchor DisjointDEC-det
- * \class DisjointDEC
- *
- * \section DisjointDEC-over Overview
- *
- * Abstract interface class representing a link between two
- * processor groups for exchanging mesh or field data. The two processor groups must
- * have a void intersection (\ref ParaMEDMEM::OverlapDEC "OverlapDEC" is to be considered otherwise).
- * The %DEC is initialized by attaching a field on the receiving or on the
- * sending side.
- *
- * The data is sent or received through calls to the (abstract) methods recvData() and sendData().
- *
- * One can attach either a \c ParaMEDMEM::ParaFIELD, or a
- * \c ICoCo::Field, or directly a \c ParaMEDMEM::MEDCouplingFieldDouble instance.
- * See the various signatures of the method DisjointDEC::attachLocalField()
- *
- * The derivations of this class should be considered for practical instanciation:
- * - \ref InterpKernelDEC-det "InterpKernelDEC"
- * - \ref ExplicitCoincidentDEC-det "ExplicitCoincidentDEC"
- * - \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC"
- *
- * \section DisjointDEC-options DisjointDEC options
- * The options supported by %DisjointDEC objects are the same that the ones supported for all
- * DECs in general and are all inherited from the class \ref ParaMEDMEM::DECOptions "DECOptions"
- *
- */
-
DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):
_local_field(0),
_source_group(&source_group),
_owns_groups(false),
_union_comm(MPI_COMM_NULL)
{
+ checkPartitionGroup();
_union_group = source_group.fuse(target_group);
}
void DisjointDEC::copyInstance(const DisjointDEC& other)
{
DEC::copyFrom(other);
- if(other._target_group)
+ if (other._union_comm != MPI_COMM_NULL)
{
- _target_group=other._target_group->deepCpy();
- _owns_groups=true;
- }
- if(other._source_group)
- {
- _source_group=other._source_group->deepCpy();
- _owns_groups=true;
+ // Tricky: the DEC is responsible for the management of _union_comm. And this comm is referenced by
+ // the MPIProcGroups (source/targets). In the case where _union_comm is not NULL we must take care of rebuilding the
+ // MPIProcGroups with a communicator that will survive the destruction of 'other'.
+ _owns_groups = true;
+ MPI_Comm_dup(other._union_comm, &_union_comm);
+// std::cout << "DUP union comm - new is "<< _union_comm << "\n";
+ _target_group = new MPIProcessorGroup(*_comm_interface, other._target_group->getProcIDs(), _union_comm);
+ _source_group = new MPIProcessorGroup(*_comm_interface, other._source_group->getProcIDs(), _union_comm);
}
+ else{
+ if(other._target_group)
+ {
+ _target_group=other._target_group->deepCopy();
+ _owns_groups=true;
+ }
+ if(other._source_group)
+ {
+ _source_group=other._source_group->deepCopy();
+ _owns_groups=true;
+ }
+ }
if (_source_group && _target_group)
_union_group = _source_group->fuse(*_target_group);
}
const std::set<int>& target_ids,
const MPI_Comm& world_comm):
_local_field(0),
+ _comm_interface(0),
_owns_field(false),
_owns_groups(true),
- _comm_interface(0),
_union_comm(MPI_COMM_NULL)
{
- ParaMEDMEM::CommInterface comm;
+ MEDCoupling::CommInterface comm;
// Create the list of procs including source and target
std::set<int> union_ids; // source and target ids in world_comm
union_ids.insert(source_ids.begin(),source_ids.end());
// Create a communicator on these procs
MPI_Group union_group,world_group;
comm.commGroup(world_comm,&world_group);
- comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group);
+ comm.groupIncl(world_group,(int)union_ids.size(),union_ranks_world,&union_group);
comm.commCreate(world_comm,union_group,&_union_comm);
delete[] union_ranks_world;
if (_union_comm==MPI_COMM_NULL)
int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm
std::copy(target_ids.begin(), target_ids.end(),target_ranks_world);
int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm
- MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union);
- MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union);
+ MPI_Group_translate_ranks(world_group,(int)source_ids.size(),source_ranks_world,union_group,source_ranks_union);
+ MPI_Group_translate_ranks(world_group,(int)target_ids.size(),target_ranks_world,union_group,target_ranks_union);
std::set<int> source_ids_union;
for (int i=0;i<(int)source_ids.size();i++)
source_ids_union.insert(source_ranks_union[i]);
{
delete _local_field;
}
- _local_field=0;
+ _local_field=nullptr;
_owns_field=false;
if(_owns_groups)
{
delete _target_group;
}
_owns_groups=false;
- _source_group=0;
- _target_group=0;
+ _source_group=nullptr;
+ _target_group=nullptr;
delete _union_group;
- _union_group=0;
+ _union_group=nullptr;
if (_union_comm != MPI_COMM_NULL)
_comm_interface->commFree(&_union_comm);
+ _union_comm = MPI_COMM_NULL;
+ }
+
+ /**
+ * Check that the sources and targets procs form a partition of the world communicator referenced in the groups.
+ * This world communicator is not necessarily MPI_WORLD_COMM, but it has to be covered completely for the DECs to work.
+ */
+ void DisjointDEC::checkPartitionGroup() const
+ {
+ int size = -1;
+ MPIProcessorGroup * tgt = static_cast<MPIProcessorGroup *>(_target_group);
+ MPIProcessorGroup * src = static_cast<MPIProcessorGroup *>(_source_group);
+ MPI_Comm comm_t = tgt->getWorldComm();
+ MPI_Comm comm_s = src->getWorldComm();
+ if (comm_t != comm_s)
+ throw INTERP_KERNEL::Exception("DisjointDEC constructor: Inconsistent world communicator when building DisjointDEC");
+ MPI_Comm_size(comm_t, &size);
+
+ std::set<int> union_ids; // source and target ids in world_comm
+ union_ids.insert(src->getProcIDs().begin(),src->getProcIDs().end());
+ union_ids.insert(tgt->getProcIDs().begin(),tgt->getProcIDs().end());
+ if((int)union_ids.size()!=size)
+ throw INTERP_KERNEL::Exception("DisjointDEC constructor: source_ids and target_ids do not form a partition of the communicator! Restrain the world communicator passed to MPIProcessorGroup ctor.");
}
void DisjointDEC::setNature(NatureOfField nature)
will be updated by a recvData() call.
Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side.
The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields :
- - a ICoCo::MEDField, that is created from a MEDCoupling structure
+ - a ICoCo::MEDDoubleField, that is created from a MEDCoupling structure
*/
- void DisjointDEC::attachLocalField(const ICoCo::MEDField *field)
+ void DisjointDEC::attachLocalField(const ICoCo::MEDDoubleField *field)
{
if(!isInUnion())
return ;
if(!field)
- throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !");
- attachLocalField(field->getField());
+ throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDDoubleField pointer is NULL !");
+ attachLocalField(field->getMCField());
}
/*!
void DisjointDEC::renormalizeTargetField(bool isWAbs)
{
if (_source_group->containsMyRank())
- for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
+ for (int icomp=0; icomp<(int)_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
{
double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
double source_norm = total_norm;
}
if (_target_group->containsMyRank())
{
- for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
+ for (int icomp=0; icomp<(int)_local_field->getField()->getArray()->getNumberOfComponents(); icomp++)
{
double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs);
double source_norm=total_norm;
return _union_group->containsMyRank();
}
- void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception)
+ void DisjointDEC::compareFieldAndMethod() const
{
if (_local_field)
{