X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FParaMEDMEM%2FDisjointDEC.cxx;h=4db440a6b72c22015e3a616000bbf5dd9f182afe;hb=7e632de173a3f7701ed288471c5de2bc0f55dbc3;hp=3170acb82381185e8174c9061c4a499c30b6f1e7;hpb=fb512e2b77325290aaa2b4c9fd8f22d5949b6369;p=tools%2Fmedcoupling.git diff --git a/src/ParaMEDMEM/DisjointDEC.cxx b/src/ParaMEDMEM/DisjointDEC.cxx index 3170acb82..4db440a6b 100644 --- a/src/ParaMEDMEM/DisjointDEC.cxx +++ b/src/ParaMEDMEM/DisjointDEC.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,67 +26,67 @@ #include "ParaMESH.hxx" #include "ICoCoField.hxx" #include "ICoCoMEDField.hxx" -#include "ICoCoTrioField.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 - @{ + /*! + * \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 MEDCoupling::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 MEDCoupling::ParaFIELD, or a + * \c ICoCo::Field, or directly a \c MEDCoupling::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 MEDCoupling::DECOptions "DECOptions" + * */ - 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,32 +102,49 @@ namespace ParaMEDMEM void DisjointDEC::copyInstance(const DisjointDEC& other) { DEC::copyFrom(other); - if(other._target_group) - { - _target_group=other._target_group->deepCpy(); - _owns_groups=true; - } - if(other._source_group) + if (other._union_comm != MPI_COMM_NULL) { - _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), + _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 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); @@ -135,15 +152,15 @@ namespace ParaMEDMEM 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.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; } @@ -168,10 +185,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() @@ -195,10 +213,32 @@ namespace ParaMEDMEM _owns_groups=false; _source_group=0; _target_group=0; - delete _icoco_field; - _icoco_field=0; delete _union_group; _union_group=0; + if (_union_comm != MPI_COMM_NULL) + _comm_interface->commFree(&_union_comm); + } + + /** + * 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 completly 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(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 +252,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 +274,7 @@ namespace ParaMEDMEM and sent appropriately to the other side. */ - void DisjointDEC::attachLocalField(MEDCouplingFieldDouble* field) + void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field) { if(!isInUnion()) return ; @@ -259,35 +299,15 @@ namespace ParaMEDMEM 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. */ - void DisjointDEC::attachLocalField(const ICoCo::Field* field) + void DisjointDEC::attachLocalField(const ICoCo::MEDField *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::MEDField pointer is NULL !"); + attachLocalField(field->getField()); } /*! @@ -331,7 +351,6 @@ namespace ParaMEDMEM } } } - /*! @} */ bool DisjointDEC::isInSourceSide() const {