X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FParaMEDMEM%2FDisjointDEC.cxx;h=b213300bbf59038edfdf02445934d169957ef13b;hb=0bf52b9b294008eeb79b593572b035bff39bc7b7;hp=a50c0d414e0500f27587f70d3d7a3b0828707393;hpb=169c6a89a70a5866050d9f87a58714d27d407c8a;p=tools%2Fmedcoupling.git diff --git a/src/ParaMEDMEM/DisjointDEC.cxx b/src/ParaMEDMEM/DisjointDEC.cxx index a50c0d414..b213300bb 100644 --- a/src/ParaMEDMEM/DisjointDEC.cxx +++ b/src/ParaMEDMEM/DisjointDEC.cxx @@ -1,9 +1,9 @@ -// Copyright (C) 2007-2013 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 // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,68 +25,38 @@ #include "ParaFIELD.hxx" #include "ParaMESH.hxx" #include "ICoCoField.hxx" -#include "ICoCoMEDField.hxx" -#include "ICoCoTrioField.hxx" +#include "ICoCoMEDDoubleField.hxx" #include "MPIProcessorGroup.hxx" #include #include -/*! \defgroup dec DEC - * - * \section decintroduction Introduction - * - * Interface class for creation of a link between two - * processor groups for exhanging mesh or field data. - * The \c DEC is defined by attaching a field on the receiving or on the - * sending side. - * On top of attaching a \c ParaMEDMEM::FIELD, it is possible to - * attach a ICoCo::Field. This class is an abstract class that enables - * coupling of codes that respect the ICoCo interface \ref icoco. It has two implementations: - * one for codes that express their fields as \ref medoupling fields (ICoCo::MEDField) and one - * for codes that express their fields as Trio/U fields. - * - * \section dec_options DEC Options - * Options supported by \c DEC objects are - * - * - * - * - *
OptionDescriptionDefault value
ForcedRenormalizationAfter receiving data, the target field is renormalized so that L2-norms of the source and target fields match. false
- - The following code excerpt shows how to set options for an object that inherits from \c DEC : - - \code - InterpKernelDEC dec(source_group,target_group); - dec.setOptions("ForcedRenormalization",true); - dec.attachLocalField(field); - dec.synchronize(); - if (source_group.containsMyRank()) - dec.sendData(); - else - dec.recvData(); - \endcode -*/ - -namespace ParaMEDMEM +namespace MEDCoupling { - - - /*! \addtogroup dec - @{ - */ - DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group):_local_field(0), - _source_group(&source_group), - _target_group(&target_group), - _owns_field(false), - _owns_groups(false), - _icoco_field(0) + DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group): + _local_field(0), + _source_group(&source_group), + _target_group(&target_group), + _comm_interface(0), + _owns_field(false), + _owns_groups(false), + _union_comm(MPI_COMM_NULL) { + checkPartitionGroup(); _union_group = source_group.fuse(target_group); } - 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),_icoco_field(0) + DisjointDEC::DisjointDEC(const DisjointDEC& s): + DEC(s), + _local_field(0), + _union_group(0), + _source_group(0), + _target_group(0), + _comm_interface(0), + _owns_field(false), + _owns_groups(false), + _union_comm(MPI_COMM_NULL) { copyInstance(s); } @@ -102,48 +72,65 @@ namespace ParaMEDMEM 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); } - DisjointDEC::DisjointDEC(const std::set& source_ids, const std::set& target_ids, const MPI_Comm& world_comm):_local_field(0), - _owns_field(false), - _owns_groups(true), - _icoco_field(0) + DisjointDEC::DisjointDEC(const std::set& source_ids, + const std::set& target_ids, + const MPI_Comm& world_comm): + _local_field(0), + _comm_interface(0), + _owns_field(false), + _owns_groups(true), + _union_comm(MPI_COMM_NULL) { - ParaMEDMEM::CommInterface comm; + MEDCoupling::CommInterface comm; // Create the list of procs including source and target std::set union_ids; // source and target ids in world_comm union_ids.insert(source_ids.begin(),source_ids.end()); union_ids.insert(target_ids.begin(),target_ids.end()); if(union_ids.size()!=(source_ids.size()+target_ids.size())) - 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 !"); + 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!"); int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm std::copy(union_ids.begin(), union_ids.end(), union_ranks_world); // 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); - MPI_Comm union_comm; - comm.commCreate(world_comm,union_group,&union_comm); + 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) + if (_union_comm==MPI_COMM_NULL) { // This process is not in union _source_group=0; _target_group=0; _union_group=0; + comm.groupFree(&union_group); + comm.groupFree(&world_group); return; } @@ -154,8 +141,8 @@ namespace ParaMEDMEM 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 source_ids_union; for (int i=0;i<(int)source_ids.size();i++) source_ids_union.insert(source_ranks_union[i]); @@ -168,10 +155,11 @@ namespace ParaMEDMEM delete [] target_ranks_union; // Create the MPIProcessorGroups - _source_group = new MPIProcessorGroup(comm,source_ids_union,union_comm); - _target_group = new MPIProcessorGroup(comm,target_ids_union,union_comm); + _source_group = new MPIProcessorGroup(comm,source_ids_union,_union_comm); + _target_group = new MPIProcessorGroup(comm,target_ids_union,_union_comm); _union_group = _source_group->fuse(*_target_group); - + comm.groupFree(&union_group); + comm.groupFree(&world_group); } DisjointDEC::~DisjointDEC() @@ -185,7 +173,7 @@ namespace ParaMEDMEM { delete _local_field; } - _local_field=0; + _local_field=nullptr; _owns_field=false; if(_owns_groups) { @@ -193,12 +181,35 @@ namespace ParaMEDMEM delete _target_group; } _owns_groups=false; - _source_group=0; - _target_group=0; - delete _icoco_field; - _icoco_field=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(_target_group); + MPIProcessorGroup * src = static_cast(_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 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) @@ -212,7 +223,7 @@ namespace ParaMEDMEM 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. */ - void DisjointDEC::attachLocalField(const ParaFIELD* field, bool ownPt) + void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt) { if(!isInUnion()) return ; @@ -234,7 +245,7 @@ namespace ParaMEDMEM and sent appropriately to the other side. */ - void DisjointDEC::attachLocalField(MEDCouplingFieldDouble* field) + void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field) { if(!isInUnion()) return ; @@ -258,36 +269,16 @@ namespace ParaMEDMEM 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::TrioField, that is created from tables extracted from a TRIO-U structure. + - a ICoCo::MEDDoubleField, that is created from a MEDCoupling structure */ - void DisjointDEC::attachLocalField(const ICoCo::Field* field) + void DisjointDEC::attachLocalField(const ICoCo::MEDDoubleField *field) { if(!isInUnion()) return ; - const ICoCo::MEDField* medfield=dynamic_cast (field); - if(medfield !=0) - { - attachLocalField(medfield->getField()); - return; - } - const ICoCo::TrioField* triofield=dynamic_cast (field); - if (triofield !=0) - { - /* Strange part of code localgroup not used ! - ProcessorGroup* localgroup; - if (_source_group->containsMyRank()) - localgroup=_source_group; - else - localgroup=_target_group;*/ - delete _icoco_field; - - _icoco_field=new ICoCo::MEDField(*const_cast(triofield)); - attachLocalField(_icoco_field); - return; - } - throw INTERP_KERNEL::Exception("incompatible field type"); + if(!field) + throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDDoubleField pointer is NULL !"); + attachLocalField(field->getMCField()); } /*! @@ -311,7 +302,7 @@ namespace ParaMEDMEM 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; @@ -320,7 +311,7 @@ namespace ParaMEDMEM } 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; @@ -331,7 +322,6 @@ namespace ParaMEDMEM } } } - /*! @} */ bool DisjointDEC::isInSourceSide() const { @@ -354,7 +344,7 @@ namespace ParaMEDMEM return _union_group->containsMyRank(); } - void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception) + void DisjointDEC::compareFieldAndMethod() const { if (_local_field) {