Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
ParallelComm.hpp
Go to the documentation of this file.
00001 /**
00002  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003  * storing and accessing finite element mesh data.
00004  *
00005  * Copyright 2004 Sandia Corporation.  Under the terms of Contract
00006  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007  * retains certain rights in this software.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  */
00015 
00016 #ifndef MOAB_PARALLEL_COMM_HPP
00017 #define MOAB_PARALLEL_COMM_HPP
00018 
00019 #include "moab/Forward.hpp"
00020 #include "moab/Interface.hpp"
00021 #include "moab/Range.hpp"
00022 #include "moab/ProcConfig.hpp"
00023 #include <map>
00024 #include <set>
00025 #include <vector>
00026 #include <iostream>
00027 #include <fstream>
00028 #include <cassert>
00029 #include <cstdlib>
00030 #include <cmath>
00031 #include "moab/TupleList.hpp"
00032 
00033 namespace moab
00034 {
00035 
00036 class SequenceManager;
00037 class Error;
00038 template < typename KeyType, typename ValType, ValType NullVal >
00039 class RangeMap;
00040 typedef RangeMap< EntityHandle, EntityHandle, 0 > HandleMap;
00041 class ParallelMergeMesh;
00042 class DebugOutput;
00043 class SharedSetData;
00044 
00045 #define MAX_SHARING_PROCS 64
00046 
00047 /**
00048  * \brief Parallel communications in MOAB
00049  * \author Tim Tautges
00050  *
00051  *  This class implements methods to communicate mesh between processors
00052  *
00053  */
00054 class ParallelComm
00055 {
00056   public:
00057     friend class ParallelMergeMesh;
00058 
00059     // ==================================
00060     // \section CONSTRUCTORS/DESTRUCTORS/PCOMM MANAGEMENT
00061     // ==================================
00062 
00063     //! constructor
00064     ParallelComm( Interface* impl, MPI_Comm comm, int* pcomm_id_out = 0 );
00065 
00066     //! constructor taking packed buffer, for testing
00067     ParallelComm( Interface* impl, std::vector< unsigned char >& tmp_buff, MPI_Comm comm, int* pcomm_id_out = 0 );
00068 
00069     //! Get ID used to reference this PCOMM instance
00070     int get_id() const
00071     {
00072         return pcommID;
00073     }
00074 
00075     //! get the indexed pcomm object from the interface
00076     static ParallelComm* get_pcomm( Interface* impl, const int index );
00077 
00078     //! Get ParallelComm instance associated with partition handle
00079     //! Will create ParallelComm instance if a) one does not already
00080     //! exist and b) a valid value for MPI_Comm is passed.
00081     static ParallelComm* get_pcomm( Interface* impl, EntityHandle partitioning, const MPI_Comm* comm = 0 );
00082 
00083     static ErrorCode get_all_pcomm( Interface* impl, std::vector< ParallelComm* >& list );
00084 
00085     //! destructor
00086     ~ParallelComm();
00087 
00088     static unsigned char PROC_SHARED, PROC_OWNER;
00089 
00090     // ==================================
00091     // \section GLOBAL IDS
00092     // ==================================
00093 
00094     //! assign a global id space, for largest-dimension or all entities (and
00095     //! in either case for vertices too)
00096     //!\param owned_only If true, do not get global IDs for non-owned entities
00097     //!                  from remote processors.
00098     ErrorCode assign_global_ids( EntityHandle this_set,
00099                                  const int dimension,
00100                                  const int start_id          = 1,
00101                                  const bool largest_dim_only = true,
00102                                  const bool parallel         = true,
00103                                  const bool owned_only       = false );
00104 
00105     //! assign a global id space, for largest-dimension or all entities (and
00106     //! in either case for vertices too)
00107     ErrorCode assign_global_ids( Range entities[],
00108                                  const int dimension,
00109                                  const int start_id,
00110                                  const bool parallel,
00111                                  const bool owned_only );
00112 
00113     //! check for global ids; based only on tag handle being there or not;
00114     //! if it's not there, create them for the specified dimensions
00115     //!\param owned_only If true, do not get global IDs for non-owned entities
00116     //!                  from remote processors.
00117     ErrorCode check_global_ids( EntityHandle this_set,
00118                                 const int dimension,
00119                                 const int start_id          = 1,
00120                                 const bool largest_dim_only = true,
00121                                 const bool parallel         = true,
00122                                 const bool owned_only       = false );
00123 
00124     // ==================================
00125     // \section HIGH-LEVEL COMMUNICATION (send/recv/bcast/scatter ents, exchange tags)
00126     // ==================================
00127 
00128     /** \brief send entities to another processor, optionally waiting until it's done
00129      *
00130      * Send entities to another processor, with adjs, sets, and tags.
00131      * If store_remote_handles is true, this call receives back handles assigned to
00132      * entities sent to destination processor and stores them in sharedh_tag or
00133      * sharedhs_tag.
00134      * \param to_proc Destination processor
00135      * \param orig_ents Entities requested to send
00136      * \param adjs If true, send adjacencies for equiv entities (currently unsupported)
00137      * \param tags If true, send tag values for all tags assigned to entities
00138      * \param store_remote_handles If true, also recv message with handles on destination processor
00139      * (currently unsupported) \param final_ents Range containing all entities sent \param incoming
00140      * keep track if any messages are coming to this processor (newly added) \param wait_all If
00141      * true, wait until all messages received/sent complete
00142      */
00143     ErrorCode send_entities( const int to_proc,
00144                              Range& orig_ents,
00145                              const bool adjs,
00146                              const bool tags,
00147                              const bool store_remote_handles,
00148                              const bool is_iface,
00149                              Range& final_ents,
00150                              int& incoming1,
00151                              int& incoming2,                                 // newly added
00152                              TupleList& entprocs,                            // newly added
00153                              std::vector< MPI_Request >& recv_remoteh_reqs,  // newly added
00154                              bool wait_all = true );
00155 
00156     ErrorCode send_entities( std::vector< unsigned int >& send_procs,
00157                              std::vector< Range* >& send_ents,
00158                              int& incoming1,
00159                              int& incoming2,
00160                              const bool store_remote_handles );
00161 
00162     /** \brief Receive entities from another processor, optionally waiting until it's done
00163      *
00164      * Receive entities from another processor, with adjs, sets, and tags.
00165      * If store_remote_handles is true, this call sends back handles assigned to
00166      * the entities received.
00167      * \param from_proc Source processor
00168      * \param store_remote_handles If true, send message with new entity handles to source processor
00169      * (currently unsupported) \param final_ents Range containing all entities received \param
00170      * incoming keep track if any messages are coming to this processor (newly added) \param
00171      * wait_all If true, wait until all messages received/sent complete
00172      */
00173     ErrorCode recv_entities( const int from_proc,
00174                              const bool store_remote_handles,
00175                              const bool is_iface,
00176                              Range& final_ents,
00177                              int& incomming1,
00178                              int& incoming2,
00179                              std::vector< std::vector< EntityHandle > >& L1hloc,
00180                              std::vector< std::vector< EntityHandle > >& L1hrem,
00181                              std::vector< std::vector< int > >& L1p,
00182                              std::vector< EntityHandle >& L2hloc,
00183                              std::vector< EntityHandle >& L2hrem,
00184                              std::vector< unsigned int >& L2p,
00185                              std::vector< MPI_Request >& recv_remoteh_reqs,
00186                              bool wait_all = true );
00187 
00188     ErrorCode recv_entities( std::set< unsigned int >& recv_procs,
00189                              int incoming1,
00190                              int incoming2,
00191                              const bool store_remote_handles,
00192                              const bool migrate = false );
00193 
00194     /** \brief Receive messages from another processor in while loop
00195      *
00196      * Receive messages from another processor.
00197      * \param from_proc Source processor
00198      * \param store_remote_handles If true, send message with new entity handles to source processor
00199      * (currently unsupported) \param final_ents Range containing all entities received \param
00200      * incoming keep track if any messages are coming to this processor (newly added)
00201      */
00202     ErrorCode recv_messages( const int from_proc,
00203                              const bool store_remote_handles,
00204                              const bool is_iface,
00205                              Range& final_ents,
00206                              int& incoming1,
00207                              int& incoming2,
00208                              std::vector< std::vector< EntityHandle > >& L1hloc,
00209                              std::vector< std::vector< EntityHandle > >& L1hrem,
00210                              std::vector< std::vector< int > >& L1p,
00211                              std::vector< EntityHandle >& L2hloc,
00212                              std::vector< EntityHandle >& L2hrem,
00213                              std::vector< unsigned int >& L2p,
00214                              std::vector< MPI_Request >& recv_remoteh_reqs );
00215 
00216     ErrorCode recv_remote_handle_messages( const int from_proc,
00217                                            int& incoming2,
00218                                            std::vector< EntityHandle >& L2hloc,
00219                                            std::vector< EntityHandle >& L2hrem,
00220                                            std::vector< unsigned int >& L2p,
00221                                            std::vector< MPI_Request >& recv_remoteh_reqs );
00222 
00223     /** \brief Exchange ghost cells with neighboring procs
00224      * Neighboring processors are those sharing an interface
00225      * with this processor.  All entities of dimension ghost_dim
00226      * within num_layers of interface, measured going through bridge_dim,
00227      * are exchanged.  See MeshTopoUtil::get_bridge_adjacencies for description
00228      * of bridge adjacencies.  If wait_all is false and store_remote_handles
00229      * is true, MPI_Request objects are available in the sendReqs[2*MAX_SHARING_PROCS]
00230      * member array, with inactive requests marked as MPI_REQUEST_NULL.  If
00231      * store_remote_handles or wait_all is false, this function returns after
00232      * all entities have been received and processed.
00233      * \param ghost_dim Dimension of ghost entities to be exchanged
00234      * \param bridge_dim Dimension of entities used to measure layers from interface
00235      * \param num_layers Number of layers of ghosts requested
00236      * \param addl_ents Dimension of additional adjacent entities to exchange with ghosts, 0 if none
00237      * \param store_remote_handles If true, send message with new entity handles to source processor
00238      * \param wait_all If true, function does not return until all send buffers
00239      *       are cleared.
00240      */
00241 
00242     ErrorCode exchange_ghost_cells( int ghost_dim,
00243                                     int bridge_dim,
00244                                     int num_layers,
00245                                     int addl_ents,
00246                                     bool store_remote_handles,
00247                                     bool wait_all          = true,
00248                                     EntityHandle* file_set = NULL );
00249 
00250     /** \brief Static version of exchange_ghost_cells, exchanging info through
00251      * buffers rather than messages
00252      */
00253     static ErrorCode exchange_ghost_cells( ParallelComm** pc,
00254                                            unsigned int num_procs,
00255                                            int ghost_dim,
00256                                            int bridge_dim,
00257                                            int num_layers,
00258                                            int addl_ents,
00259                                            bool store_remote_handles,
00260                                            EntityHandle* file_sets = NULL );
00261 
00262     /** \brief Post "MPI_Irecv" before meshing
00263      * \param exchange_procs processor vector exchanged
00264      */
00265     ErrorCode post_irecv( std::vector< unsigned int >& exchange_procs );
00266 
00267     ErrorCode post_irecv( std::vector< unsigned int >& shared_procs, std::set< unsigned int >& recv_procs );
00268 
00269     /** \brief Exchange owned mesh for input mesh entities and sets
00270      * This function should be called collectively over the communicator for this ParallelComm.
00271      * If this version is called, all shared exchanged entities should have a value for this
00272      * tag (or the tag should have a default value).
00273      * \param exchange_procs processor vector exchanged
00274      * \param exchange_ents exchanged entities for each processors
00275      * \param migrate if the owner if entities are changed or not
00276      */
00277     ErrorCode exchange_owned_meshs( std::vector< unsigned int >& exchange_procs,
00278                                     std::vector< Range* >& exchange_ents,
00279                                     std::vector< MPI_Request >& recv_ent_reqs,
00280                                     std::vector< MPI_Request >& recv_remoteh_reqs,
00281                                     bool store_remote_handles,
00282                                     bool wait_all = true,
00283                                     bool migrate  = false,
00284                                     int dim       = 0 );
00285 
00286     /** \brief Exchange owned mesh for input mesh entities and sets
00287      * This function is called twice by exchange_owned_meshs to exchange entities before sets
00288      * \param migrate if the owner if entities are changed or not
00289      */
00290     ErrorCode exchange_owned_mesh( std::vector< unsigned int >& exchange_procs,
00291                                    std::vector< Range* >& exchange_ents,
00292                                    std::vector< MPI_Request >& recv_ent_reqs,
00293                                    std::vector< MPI_Request >& recv_remoteh_reqs,
00294                                    const bool recv_posted,
00295                                    bool store_remote_handles,
00296                                    bool wait_all,
00297                                    bool migrate = false );
00298 
00299     /** \brief Exchange tags for all shared and ghosted entities
00300      * This function should be called collectively over the communicator for this ParallelComm.
00301      * If this version is called, all ghosted/shared entities should have a value for this
00302      * tag (or the tag should have a default value).  If the entities vector is empty, all shared
00303      * entities participate in the exchange.  If a proc has no owned entities this function must
00304      * still be called since it is collective. \param src_tags Vector of tag handles to be exchanged
00305      * \param dst_tags Tag handles to store the tags on the non-owning procs
00306      * \param entities Entities for which tags are exchanged
00307      */
00308     ErrorCode exchange_tags( const std::vector< Tag >& src_tags,
00309                              const std::vector< Tag >& dst_tags,
00310                              const Range& entities );
00311 
00312     /** \brief Exchange tags for all shared and ghosted entities
00313      * This function should be called collectively over the communicator for this ParallelComm.
00314      * If the entities vector is empty, all shared entities
00315      * participate in the exchange.  If a proc has no owned entities this function must still be
00316      * called since it is collective. \param tag_name Name of tag to be exchanged \param entities
00317      * Entities for which tags are exchanged
00318      */
00319     ErrorCode exchange_tags( const char* tag_name, const Range& entities );
00320 
00321     /** \brief Exchange tags for all shared and ghosted entities
00322      * This function should be called collectively over the communicator for this ParallelComm.
00323      * If the entities vector is empty, all shared entities
00324      * participate in the exchange.  If a proc has no owned entities this function must still be
00325      * called since it is collective. \param tagh Handle of tag to be exchanged \param entities
00326      * Entities for which tags are exchanged
00327      */
00328     ErrorCode exchange_tags( Tag tagh, const Range& entities );
00329 
00330     /** \brief Perform data reduction operation for all shared and ghosted entities
00331      * This function should be called collectively over the communicator for this ParallelComm.
00332      * If this version is called, all ghosted/shared entities should have a value for this
00333      * tag (or the tag should have a default value).  Operation is any MPI_Op, with result stored
00334      * in destination tag.
00335      * \param src_tags Vector of tag handles to be reduced
00336      * \param dst_tags Vector of tag handles in which the answer will be stored
00337      * \param mpi_op Operation type
00338      * \param entities Entities on which reduction will be made; if empty, operates on all shared
00339      *                 entities
00340      */
00341     ErrorCode reduce_tags( const std::vector< Tag >& src_tags,
00342                            const std::vector< Tag >& dst_tags,
00343                            const MPI_Op mpi_op,
00344                            const Range& entities );
00345 
00346     /** \brief Perform data reduction operation for all shared and ghosted entities
00347      * Same as std::vector variant except for one tag specified by name
00348      * \param tag_name Name of tag to be reduced
00349      * \param mpi_op Operation type
00350      * \param entities Entities on which reduction will be made; if empty, operates on all shared
00351      *                 entities
00352      */
00353     ErrorCode reduce_tags( const char* tag_name, const MPI_Op mpi_op, const Range& entities );
00354 
00355     /** \brief Perform data reduction operation for all shared and ghosted entities
00356      * Same as std::vector variant except for one tag specified by handle
00357      * \param tag_name Name of tag to be reduced
00358      * \param mpi_op Operation type
00359      * \param entities Entities on which reduction will be made; if empty, operates on all shared
00360      *                 entities
00361      */
00362     ErrorCode reduce_tags( Tag tag_handle, const MPI_Op mpi_op, const Range& entities );
00363 
00364     /** \brief Broadcast all entities resident on from_proc to other processors
00365      * This function assumes remote handles are *not* being stored, since (usually)
00366      * every processor will know about the whole mesh.
00367      * \param from_proc Processor having the mesh to be broadcast
00368      * \param entities On return, the entities sent or received in this call
00369      * \param adjacencies If true, adjacencies are sent for equiv entities (currently unsupported)
00370      * \param tags If true, all non-default-valued tags are sent for sent entities
00371      */
00372     ErrorCode broadcast_entities( const int from_proc,
00373                                   Range& entities,
00374                                   const bool adjacencies = false,
00375                                   const bool tags        = true );
00376 
00377     /** \brief Scatter entities on from_proc to other processors
00378      * This function assumes remote handles are *not* being stored, since (usually)
00379      * every processor will know about the whole mesh.
00380      * \param from_proc Processor having the mesh to be broadcast
00381      * \param entities On return, the entities sent or received in this call
00382      * \param adjacencies If true, adjacencies are sent for equiv entities (currently unsupported)
00383      * \param tags If true, all non-default-valued tags are sent for sent entities
00384      */
00385     ErrorCode scatter_entities( const int from_proc,
00386                                 std::vector< Range >& entities,
00387                                 const bool adjacencies = false,
00388                                 const bool tags        = true );
00389 
00390     /////////////////////////////////////////////////////////////////////////////////
00391     // Send and Receive routines for a sequence of entities: use case UMR
00392     /////////////////////////////////////////////////////////////////////////////////
00393 
00394     /** \brief Send and receives data from a set of processors
00395      */
00396     ErrorCode send_recv_entities( std::vector< int >& send_procs,
00397                                   std::vector< std::vector< int > >& msgsizes,
00398                                   std::vector< std::vector< EntityHandle > >& senddata,
00399                                   std::vector< std::vector< EntityHandle > >& recvdata );
00400 
00401     ErrorCode update_remote_data( EntityHandle entity,
00402                                   std::vector< int >& procs,
00403                                   std::vector< EntityHandle >& handles );
00404 
00405     ErrorCode get_remote_handles( EntityHandle* local_vec, EntityHandle* rem_vec, int num_ents, int to_proc );
00406 
00407     /////////////////////////////////////////////////////////////////////////////////
00408 
00409     // ==================================
00410     // \section INITIALIZATION OF PARALLEL DATA (resolve_shared_ents, etc.)
00411     // ==================================
00412 
00413     /** \brief Resolve shared entities between processors
00414      *
00415      * Resolve shared entities between processors for entities in proc_ents,
00416      * by comparing global id tag values on vertices on skin of elements in
00417      * proc_ents.  Shared entities are assigned a tag that's either
00418      * PARALLEL_SHARED_PROC_TAG_NAME, which is 1 integer in length, or
00419      * PARALLEL_SHARED_PROCS_TAG_NAME, whose length depends on the maximum
00420      * number of sharing processors.  Values in these tags denote the ranks
00421      * of sharing processors, and the list ends with the value -1.
00422      *
00423      * If shared_dim is input as -1 or not input, a value one less than the
00424      * maximum dimension of entities in proc_ents is used.
00425      *
00426      * \param proc_ents Entities for which to resolve shared entities
00427      * \param shared_dim Maximum dimension of shared entities to look for
00428      */
00429     ErrorCode resolve_shared_ents( EntityHandle this_set,
00430                                    Range& proc_ents,
00431                                    int resolve_dim   = -1,
00432                                    int shared_dim    = -1,
00433                                    Range* skin_ents  = NULL,
00434                                    const Tag* id_tag = 0 );
00435 
00436     /** \brief Resolve shared entities between processors
00437      *
00438      * Same as resolve_shared_ents(Range&), except works for
00439      * all entities in instance of dimension dim.
00440      *
00441      * If shared_dim is input as -1 or not input, a value one less than the
00442      * maximum dimension of entities is used.
00443 
00444      * \param dim Dimension of entities in the partition
00445      * \param shared_dim Maximum dimension of shared entities to look for
00446      */
00447     ErrorCode resolve_shared_ents( EntityHandle this_set,
00448                                    int resolve_dim   = 3,
00449                                    int shared_dim    = -1,
00450                                    const Tag* id_tag = 0 );
00451 
00452     static ErrorCode resolve_shared_ents( ParallelComm** pc,
00453                                           const unsigned int np,
00454                                           EntityHandle this_set,
00455                                           const int to_dim );
00456 
00457     /** Remove shared sets.
00458      *
00459      * Generates list of candidate sets using from those (directly)
00460      * contained in passed set and passes them to the other version
00461      * of \c resolve_shared_sets.
00462      *\param this_set  Set directly containing candidate sets (e.g. file set)
00463      *\param id_tag    Tag containing global IDs for entity sets.
00464      */
00465 
00466     ErrorCode resolve_shared_sets( EntityHandle this_set, const Tag* id_tag = 0 );
00467 
00468     /** Remove shared sets.
00469      *
00470      * Use values of id_tag to match sets across processes and populate
00471      * sharing data for sets.
00472      *\param candidate_sets  Sets to consider as potentially shared.
00473      *\param id_tag    Tag containing global IDs for entity sets.
00474      */
00475     ErrorCode resolve_shared_sets( Range& candidate_sets, Tag id_tag );
00476 
00477     /** extend shared sets with ghost entities
00478      * After ghosting, ghost entities do not have yet information about
00479      * the material set, partition set, Neumann or Dirichlet set they could
00480      * belong to
00481      * This method will assign ghosted entities to the those special entity sets
00482      * In some case we might even have to create those sets, if they do not exist yet on
00483      * the local processor
00484      *
00485      * The special entity sets all have an unique identifier, in a form of an integer
00486      * tag to the set.
00487      * The shared sets data is not used, because we do not use the geometry sets, as they are
00488      * not uniquely identified
00489      *
00490      *
00491      * \param file_set : file set used per application
00492      *
00493      */
00494     ErrorCode augment_default_sets_with_ghosts( EntityHandle file_set );
00495     // ==================================
00496     // \section GET PARALLEL DATA (shared/owned/iface entities, etc.)
00497     // ==================================
00498 
00499     /** \brief Get parallel status of an entity
00500      * Returns the parallel status of an entity
00501      *
00502      * \param entity The entity being queried
00503      * \param pstatus_val Parallel status of the entity
00504      */
00505     ErrorCode get_pstatus( EntityHandle entity, unsigned char& pstatus_val );
00506 
00507     /** \brief Get entities with the given pstatus bit(s) set
00508      * Returns any entities whose pstatus tag value v satisfies (v & pstatus_val)
00509      *
00510      * \param dim Dimension of entities to be returned, or -1 if any
00511      * \param pstatus_val pstatus value of desired entities
00512      * \param pstatus_ents Entities returned from function
00513      */
00514     ErrorCode get_pstatus_entities( int dim, unsigned char pstatus_val, Range& pstatus_ents );
00515 
00516     /** \brief Return the rank of the entity owner
00517      */
00518     ErrorCode get_owner( EntityHandle entity, int& owner );
00519 
00520     /** \brief Return the owner processor and handle of a given entity
00521      */
00522     ErrorCode get_owner_handle( EntityHandle entity, int& owner, EntityHandle& handle );
00523 
00524     /** \brief Get the shared processors/handles for an entity
00525      * Get the shared processors/handles for an entity.  Arrays must
00526      * be large enough to receive data for all sharing procs.  Does *not* include
00527      * this proc if only shared with one other proc.
00528      * \param entity Entity being queried
00529      * \param ps Pointer to sharing proc data
00530      * \param hs Pointer to shared proc handle data
00531      * \param pstat Reference to pstatus data returned from this function
00532      */
00533     ErrorCode get_sharing_data( const EntityHandle entity,
00534                                 int* ps,
00535                                 EntityHandle* hs,
00536                                 unsigned char& pstat,
00537                                 unsigned int& num_ps );
00538 
00539     /** \brief Get the shared processors/handles for an entity
00540      * Same as other version but with int num_ps
00541      * \param entity Entity being queried
00542      * \param ps Pointer to sharing proc data
00543      * \param hs Pointer to shared proc handle data
00544      * \param pstat Reference to pstatus data returned from this function
00545      */
00546     ErrorCode get_sharing_data( const EntityHandle entity,
00547                                 int* ps,
00548                                 EntityHandle* hs,
00549                                 unsigned char& pstat,
00550                                 int& num_ps );
00551 
00552     /** \brief Get the intersection or union of all sharing processors
00553      * Get the intersection or union of all sharing processors.  Processor set
00554      * is cleared as part of this function.
00555      * \param entities Entity list ptr
00556      * \param num_entities Number of entities
00557      * \param procs Processors returned
00558      * \param op Either Interface::UNION or Interface::INTERSECT
00559      */
00560     ErrorCode get_sharing_data( const EntityHandle* entities,
00561                                 int num_entities,
00562                                 std::set< int >& procs,
00563                                 int op = Interface::INTERSECT );
00564 
00565     /** \brief Get the intersection or union of all sharing processors
00566      * Same as previous variant but with range as input
00567      */
00568     ErrorCode get_sharing_data( const Range& entities, std::set< int >& procs, int op = Interface::INTERSECT );
00569 
00570     /** \brief Get shared entities of specified dimension
00571      * If other_proc is -1, any shared entities are returned.  If dim is -1,
00572      * entities of all dimensions on interface are returned.
00573      * \param other_proc Rank of processor for which interface entities are requested
00574      * \param shared_ents Entities returned from function
00575      * \param dim Dimension of interface entities requested
00576      * \param iface If true, return only entities on the interface
00577      * \param owned_filter If true, return only owned shared entities
00578      */
00579     ErrorCode get_shared_entities( int other_proc,
00580                                    Range& shared_ents,
00581                                    int dim                 = -1,
00582                                    const bool iface        = false,
00583                                    const bool owned_filter = false );
00584     /*
00585     //! return partition sets; if tag_name is input, gets sets with
00586     //! that tag name, otherwise uses PARALLEL_PARTITION tag
00587     ErrorCode get_partition_sets(EntityHandle this_set,
00588     Range &part_sets,
00589     const char *tag_name = NULL);
00590     */
00591     //! get processors with which this processor shares an interface
00592     ErrorCode get_interface_procs( std::set< unsigned int >& iface_procs, const bool get_buffs = false );
00593 
00594     //! get processors with which this processor communicates
00595     ErrorCode get_comm_procs( std::set< unsigned int >& procs );
00596 
00597     // ==================================
00598     // \section SHARED SETS
00599     // ==================================
00600 
00601     //! Get array of process IDs sharing a set.  Returns zero
00602     //! and passes back NULL if set is not shared.
00603     ErrorCode get_entityset_procs( EntityHandle entity_set, std::vector< unsigned >& ranks ) const;
00604 
00605     //! Get rank of the owner of a shared set.
00606     //! Returns this proc if set is not shared.
00607     //! Optionally returns handle on owning process for shared set.
00608     ErrorCode get_entityset_owner( EntityHandle entity_set,
00609                                    unsigned& owner_rank,
00610                                    EntityHandle* remote_handle = 0 ) const;
00611 
00612     //! Given set owner and handle on owner, find local set handle
00613     ErrorCode get_entityset_local_handle( unsigned owning_rank,
00614                                           EntityHandle remote_handle,
00615                                           EntityHandle& local_handle ) const;
00616 
00617     //! Get all shared sets
00618     ErrorCode get_shared_sets( Range& result ) const;
00619 
00620     //! Get ranks of all processes that own at least one set that is
00621     //! shared with this process.  Will include the rank of this process
00622     //! if this process owns any shared set.
00623     ErrorCode get_entityset_owners( std::vector< unsigned >& ranks ) const;
00624 
00625     //! Get shared sets owned by process with specified rank.
00626     ErrorCode get_owned_sets( unsigned owning_rank, Range& sets_out ) const;
00627 
00628     // ==================================
00629     // \section LOW-LEVEL DATA (tags, sets on interface/partition, etc.)
00630     // ==================================
00631 
00632     //! Get proc config for this communication object
00633     const ProcConfig& proc_config() const
00634     {
00635         return procConfig;
00636     }
00637 
00638     //! Get proc config for this communication object
00639     ProcConfig& proc_config()
00640     {
00641         return procConfig;
00642     }
00643 
00644     unsigned rank() const
00645     {
00646         return proc_config().proc_rank();
00647     }
00648     unsigned size() const
00649     {
00650         return proc_config().proc_size();
00651     }
00652     MPI_Comm comm() const
00653     {
00654         return proc_config().proc_comm();
00655     }
00656 
00657     //! return the tags used to indicate shared procs and handles
00658     ErrorCode get_shared_proc_tags( Tag& sharedp_tag,
00659                                     Tag& sharedps_tag,
00660                                     Tag& sharedh_tag,
00661                                     Tag& sharedhs_tag,
00662                                     Tag& pstatus_tag );
00663 
00664     //! return partition, interface set ranges
00665     Range& partition_sets()
00666     {
00667         return partitionSets;
00668     }
00669     const Range& partition_sets() const
00670     {
00671         return partitionSets;
00672     }
00673     Range& interface_sets()
00674     {
00675         return interfaceSets;
00676     }
00677     const Range& interface_sets() const
00678     {
00679         return interfaceSets;
00680     }
00681 
00682     //! return sharedp tag
00683     Tag sharedp_tag();
00684 
00685     //! return sharedps tag
00686     Tag sharedps_tag();
00687 
00688     //! return sharedh tag
00689     Tag sharedh_tag();
00690 
00691     //! return sharedhs tag
00692     Tag sharedhs_tag();
00693 
00694     //! return pstatus tag
00695     Tag pstatus_tag();
00696 
00697     //! return pcomm tag; static because might not have a pcomm before going
00698     //! to look for one on the interface
00699     static Tag pcomm_tag( Interface* impl, bool create_if_missing = true );
00700 
00701     //! return partitions set tag
00702     Tag partition_tag();
00703     Tag part_tag()
00704     {
00705         return partition_tag();
00706     }
00707 
00708     // ==================================
00709     // \section DEBUGGING AIDS
00710     // ==================================
00711 
00712     //! print contents of pstatus value in human-readable form
00713     void print_pstatus( unsigned char pstat, std::string& ostr );
00714 
00715     //! print contents of pstatus value in human-readable form to std::cut
00716     void print_pstatus( unsigned char pstat );
00717 
00718     // ==================================
00719     // \section IMESHP-RELATED FUNCTIONS
00720     // ==================================
00721 
00722     //! return all the entities in parts owned locally
00723     ErrorCode get_part_entities( Range& ents, int dim = -1 );
00724 
00725     EntityHandle get_partitioning() const
00726     {
00727         return partitioningSet;
00728     }
00729     ErrorCode set_partitioning( EntityHandle h );
00730     ErrorCode get_global_part_count( int& count_out ) const;
00731     ErrorCode get_part_owner( int part_id, int& owner_out ) const;
00732     ErrorCode get_part_id( EntityHandle part, int& id_out ) const;
00733     ErrorCode get_part_handle( int id, EntityHandle& handle_out ) const;
00734     ErrorCode create_part( EntityHandle& part_out );
00735     ErrorCode destroy_part( EntityHandle part );
00736     ErrorCode collective_sync_partition();
00737     ErrorCode get_part_neighbor_ids( EntityHandle part, int neighbors_out[MAX_SHARING_PROCS], int& num_neighbors_out );
00738     ErrorCode get_interface_sets( EntityHandle part, Range& iface_sets_out, int* adj_part_id = 0 );
00739     ErrorCode get_owning_part( EntityHandle entity, int& owning_part_id_out, EntityHandle* owning_handle = 0 );
00740     ErrorCode get_sharing_parts( EntityHandle entity,
00741                                  int part_ids_out[MAX_SHARING_PROCS],
00742                                  int& num_part_ids_out,
00743                                  EntityHandle remote_handles[MAX_SHARING_PROCS] = 0 );
00744 
00745     /** Filter the entities by pstatus tag.
00746      * op is one of PSTATUS_ AND, OR, NOT; an entity is output if:
00747      * AND: all bits set in pstatus_val are also set on entity
00748      * OR: any bits set in pstatus_val also set on entity
00749      * NOT: any bits set in pstatus_val are not set on entity
00750      *
00751      * Results returned in input list, unless result_ents is passed in non-null,
00752      * in which case results are returned in result_ents.
00753      *
00754      * If ents is passed in empty, filter is done on shared entities in this
00755      * pcomm instance, i.e. contents of sharedEnts.
00756      *
00757      *\param ents       Input entities to filter
00758      *\param pstatus_val pstatus value to which entities are compared
00759      *\param op Bitwise operation performed between pstatus values
00760      *\param to_proc If non-negative and PSTATUS_SHARED is set on pstatus_val,
00761      *               only entities shared with to_proc are returned
00762      *\param result_ents If non-null, results of filter are put in the
00763      *       pointed-to range
00764      */
00765     ErrorCode filter_pstatus( Range& ents,
00766                               const unsigned char pstatus_val,
00767                               const unsigned char op,
00768                               int to_proc          = -1,
00769                               Range* returned_ents = NULL );
00770 
00771     /** \brief Get entities on interfaces shared with another proc
00772      *
00773      * \param other_proc Other proc sharing the interface
00774      * \param dim Dimension of entities to return, -1 if all dims
00775      * \param iface_ents Returned entities
00776      */
00777     ErrorCode get_iface_entities( int other_proc, int dim, Range& iface_ents );
00778 
00779     Interface* get_moab() const
00780     {
00781         return mbImpl;
00782     }
00783 
00784     ErrorCode clean_shared_tags( std::vector< Range* >& exchange_ents );
00785 
00786     class Buffer
00787     {
00788       public:
00789         unsigned char* mem_ptr;
00790         unsigned char* buff_ptr;
00791         unsigned int alloc_size;
00792 
00793         Buffer( unsigned int sz = 0 );
00794         Buffer( const Buffer& );
00795         ~Buffer();
00796         void reset_buffer( size_t buff_pos = 0 )
00797         {
00798             reset_ptr( buff_pos );
00799             reserve( INITIAL_BUFF_SIZE );
00800         }
00801         void reset_ptr( size_t buff_pos = 0 )
00802         {
00803             assert( ( !mem_ptr && !buff_pos ) || ( alloc_size >= buff_pos ) );
00804             buff_ptr = mem_ptr + buff_pos;
00805         }
00806         inline void reserve( unsigned int new_size );
00807         void set_stored_size()
00808         {
00809             *( (int*)mem_ptr ) = (int)( buff_ptr - mem_ptr );
00810         }
00811         int get_stored_size()
00812         {
00813             return *( (int*)mem_ptr );
00814         }
00815         int get_current_size()
00816         {
00817             return (int)( buff_ptr - mem_ptr );
00818         }
00819 
00820         void check_space( unsigned int addl_space );
00821     };
00822 
00823     //! public 'cuz we want to unit test these externally
00824     ErrorCode pack_buffer( Range& orig_ents,
00825                            const bool adjacencies,
00826                            const bool tags,
00827                            const bool store_remote_handles,
00828                            const int to_proc,
00829                            Buffer* buff,
00830                            TupleList* entprocs = NULL,
00831                            Range* allsent      = NULL );
00832 
00833     ErrorCode unpack_buffer( unsigned char* buff_ptr,
00834                              const bool store_remote_handles,
00835                              const int from_proc,
00836                              const int ind,
00837                              std::vector< std::vector< EntityHandle > >& L1hloc,
00838                              std::vector< std::vector< EntityHandle > >& L1hrem,
00839                              std::vector< std::vector< int > >& L1p,
00840                              std::vector< EntityHandle >& L2hloc,
00841                              std::vector< EntityHandle >& L2hrem,
00842                              std::vector< unsigned int >& L2p,
00843                              std::vector< EntityHandle >& new_ents,
00844                              const bool created_iface = false );
00845 
00846     ErrorCode pack_entities( Range& entities,
00847                              Buffer* buff,
00848                              const bool store_remote_handles,
00849                              const int to_proc,
00850                              const bool is_iface,
00851                              TupleList* entprocs = NULL,
00852                              Range* allsent      = NULL );
00853 
00854     //! unpack entities in buff_ptr
00855     ErrorCode unpack_entities( unsigned char*& buff_ptr,
00856                                const bool store_remote_handles,
00857                                const int from_ind,
00858                                const bool is_iface,
00859                                std::vector< std::vector< EntityHandle > >& L1hloc,
00860                                std::vector< std::vector< EntityHandle > >& L1hrem,
00861                                std::vector< std::vector< int > >& L1p,
00862                                std::vector< EntityHandle >& L2hloc,
00863                                std::vector< EntityHandle >& L2hrem,
00864                                std::vector< unsigned int >& L2p,
00865                                std::vector< EntityHandle >& new_ents,
00866                                const bool created_iface = false );
00867 
00868     //! Call exchange_all_shared_handles, then compare the results with tag data
00869     //! on local shared entities.
00870     ErrorCode check_all_shared_handles( bool print_em = false );
00871 
00872     static ErrorCode check_all_shared_handles( ParallelComm** pcs, int num_pcs );
00873 
00874     struct SharedEntityData
00875     {
00876         EntityHandle local;
00877         EntityHandle remote;
00878         EntityID owner;
00879     };
00880 
00881     ErrorCode pack_shared_handles( std::vector< std::vector< SharedEntityData > >& send_data );
00882 
00883     // check consistency of sharedEnts against their tags and their
00884     // vertices' tags
00885     ErrorCode check_local_shared();
00886 
00887     // check contents of communicated shared entity data against tags
00888     ErrorCode check_my_shared_handles( std::vector< std::vector< SharedEntityData > >& shents,
00889                                        const char* prefix = NULL );
00890 
00891     //! set rank for this pcomm; USED FOR TESTING ONLY!
00892     void set_rank( unsigned int r );
00893 
00894     //! set rank for this pcomm; USED FOR TESTING ONLY!
00895     void set_size( unsigned int r );
00896 
00897     //! get (and possibly allocate) buffers for messages to/from to_proc; returns
00898     //! index of to_proc in buffProcs vector; if is_new is non-NULL, sets to
00899     //! whether new buffer was allocated
00900     //! PUBLIC ONLY FOR TESTING!
00901     int get_buffers( int to_proc, bool* is_new = NULL );
00902 
00903     //! get buff processor vector
00904     const std::vector< unsigned int >& buff_procs() const;
00905 
00906     /* \brief Unpack message with remote handles
00907      * PUBLIC ONLY FOR TESTING!
00908      */
00909     ErrorCode unpack_remote_handles( unsigned int from_proc,
00910                                      unsigned char*& buff_ptr,
00911                                      std::vector< EntityHandle >& L2hloc,
00912                                      std::vector< EntityHandle >& L2hrem,
00913                                      std::vector< unsigned int >& L2p );
00914 
00915     /* \brief Pack message with remote handles
00916      * PUBLIC ONLY FOR TESTING!
00917      */
00918     ErrorCode pack_remote_handles( std::vector< EntityHandle >& L1hloc,
00919                                    std::vector< EntityHandle >& L1hrem,
00920                                    std::vector< int >& procs,
00921                                    unsigned int to_proc,
00922                                    Buffer* buff );
00923 
00924     // each iterate in proc_nvecs contains a set of procs and the entities *possibly*
00925     // on the interface between those procs; this function makes sets for each,
00926     // and tags the set with the procs sharing it; interface sets are optionally
00927     // returned; NOTE: a subsequent step is used to verify entities on the interface
00928     // and remove them if they're not shared
00929     ErrorCode create_interface_sets( std::map< std::vector< int >, std::vector< EntityHandle > >& proc_nvecs );
00930 
00931     // do the same but working straight from sharedEnts
00932     ErrorCode create_interface_sets( EntityHandle this_set, int resolve_dim, int shared_dim );
00933 
00934     ErrorCode tag_shared_verts( TupleList& shared_ents,
00935                                 std::map< std::vector< int >, std::vector< EntityHandle > >& proc_nvecs,
00936                                 Range& proc_verts,
00937                                 unsigned int i_extra = 1 );
00938 
00939     ErrorCode list_entities( const EntityHandle* ents, int num_ents );
00940 
00941     ErrorCode list_entities( const Range& ents );
00942 
00943     void set_send_request( int n_request );  // set send request array
00944 
00945     void set_recv_request( int n_request );  // set recv request array
00946 
00947     //! reset message buffers to their initial state
00948     // changed to public function (HJK)
00949     void reset_all_buffers();
00950 
00951     static const unsigned int INITIAL_BUFF_SIZE;
00952 
00953     //! set the verbosity level of output from this pcomm
00954     void set_debug_verbosity( int verb );
00955 
00956     //! get the verbosity level of output from this pcomm
00957     int get_debug_verbosity();
00958 
00959     /* \brief Gather tag value from entities down to a specified root proc
00960      * This function gathers data from a domain-decomposed mesh onto a global mesh
00961      * represented on the root processor.  On the root, this gather mesh is distinct from
00962      * the root's domain-decomposed subdomain.  Entities are matched by global id, or by
00963      * another tag if its handle is input.  The dimension of all entities in gather_ents should
00964      * be the same, since this is the dimension of entities in gather_set that are queried for
00965      * matching global id tags.
00966      * \param gather_ents (Local) entities from which to gather data
00967      * \param tag_handle Tag whose values are being gathered
00968      * \param id_tag Tag to use for matching entities (global id used by default)
00969      * \param gather_set On root, set containing global mesh onto which to put data
00970      * \param root_proc_rank Rank of the specified root processor (default rank is 0)
00971      */
00972     ErrorCode gather_data( Range& gather_ents,
00973                            Tag& tag_handle,
00974                            Tag id_tag              = 0,
00975                            EntityHandle gather_set = 0,
00976                            int root_proc_rank      = 0 );
00977 
00978     /* \brief communicate extra points positions on boundary
00979      * This function is called after intersection of 2 meshes, to settle the
00980      * position of the intersection points on the boundary (interface)
00981      * The initial mesh distributed on each processor is decomposed after
00982      * intersection with another mesh, such as that new points are created on the
00983      * boundary. these points should better match at the interface !
00984      * we perform an extra caution step, to ensure the robustness of the
00985      * intersection algorithm;  only shared edges extra nodes
00986      *  will be actually needed to be communicated, but we just pass by reference
00987      *  the whole extraNodesVec structure, we do
00988      *  not need to construct another data structure
00989      *  The node positions on edges that are owned will be communicated to other
00990      *  processors
00991      *
00992      * \param edges total range of entities
00993      * \param shared_edges_owned edges for which to communicate data
00994      * \param extraNodesVec handles of intersection vertices on all edges;
00995      */
00996     ErrorCode settle_intersection_points( Range& edges,
00997                                           Range& shared_edges_owned,
00998                                           std::vector< std::vector< EntityHandle >* >& extraNodesVec,
00999                                           double tolerance );
01000 
01001     /* \brief delete entities from moab database
01002      * will check the shared ents array, and clean it if necessary
01003      *
01004      */
01005     ErrorCode delete_entities( Range& to_delete );
01006 
01007     /*
01008      * \brief correct multi-sharing info for thin layers
01009      *
01010      * will be used for at least 3 processes, when there are thin ghost layers
01011      * right now it is public, for allowing users to call it directly
01012      * eventually, it should become private, and be called automatically
01013      */
01014 
01015     ErrorCode correct_thin_ghost_layers();
01016 
01017   private:
01018     ErrorCode reduce_void( int tag_data_type, const MPI_Op mpi_op, int num_ents, void* old_vals, void* new_vals );
01019 
01020     template < class T >
01021     ErrorCode reduce( const MPI_Op mpi_op, int num_ents, void* old_vals, void* new_vals );
01022 
01023     void print_debug_isend( int from, int to, unsigned char* buff, int tag, int size );
01024 
01025     void print_debug_irecv( int to, int from, unsigned char* buff, int size, int tag, int incoming );
01026 
01027     void print_debug_recd( MPI_Status status );
01028 
01029     void print_debug_waitany( std::vector< MPI_Request >& reqs, int tag, int proc );
01030 
01031     // common initialization code, called from various constructors
01032     void initialize();
01033 
01034     ErrorCode set_sharing_data( EntityHandle ent,
01035                                 unsigned char pstatus,
01036                                 int old_nump,
01037                                 int new_nump,
01038                                 int* ps,
01039                                 EntityHandle* hs );
01040 
01041     ErrorCode check_clean_iface( Range& allsent );
01042 
01043     void define_mpe();
01044 
01045     ErrorCode get_sent_ents( const bool is_iface,
01046                              const int bridge_dim,
01047                              const int ghost_dim,
01048                              const int num_layers,
01049                              const int addl_ents,
01050                              Range* sent_ents,
01051                              Range& allsent,
01052                              TupleList& entprocs );
01053 
01054     /** \brief Set pstatus values on entities
01055      *
01056      * \param pstatus_ents Entities to be set
01057      * \param pstatus_val Pstatus value to be set
01058      * \param lower_dim_ents If true, lower-dimensional ents (incl. vertices) set too
01059      *        (and created if they don't exist)
01060      * \param verts_too If true, vertices also set
01061      * \param operation If UNION, pstatus_val is OR-d with existing value, otherwise
01062      *        existing value is over-written
01063      */
01064     ErrorCode set_pstatus_entities( Range& pstatus_ents,
01065                                     unsigned char pstatus_val,
01066                                     bool lower_dim_ents = false,
01067                                     bool verts_too      = true,
01068                                     int operation       = Interface::UNION );
01069 
01070     /** \brief Set pstatus values on entities (vector-based function)
01071      *
01072      * \param pstatus_ents Entities to be set
01073      * \param pstatus_val Pstatus value to be set
01074      * \param lower_dim_ents If true, lower-dimensional ents (incl. vertices) set too
01075      *        (and created if they don't exist)
01076      * \param verts_too If true, vertices also set
01077      * \param operation If UNION, pstatus_val is OR-d with existing value, otherwise
01078      *        existing value is over-written
01079      */
01080     ErrorCode set_pstatus_entities( EntityHandle* pstatus_ents,
01081                                     int num_ents,
01082                                     unsigned char pstatus_val,
01083                                     bool lower_dim_ents = false,
01084                                     bool verts_too      = true,
01085                                     int operation       = Interface::UNION );
01086 
01087     //! estimate size required to pack entities
01088     int estimate_ents_buffer_size( Range& entities, const bool store_remote_handles );
01089 
01090     //! estimate size required to pack sets
01091     int estimate_sets_buffer_size( Range& entities, const bool store_remote_handles );
01092 
01093     //! send the indicated buffer, possibly sending size first
01094     ErrorCode send_buffer( const unsigned int to_proc,
01095                            Buffer* send_buff,
01096                            const int msg_tag,
01097                            MPI_Request& send_req,
01098                            MPI_Request& ack_recv_req,
01099                            int* ack_buff,
01100                            int& this_incoming,
01101                            int next_mesg_tag          = -1,
01102                            Buffer* next_recv_buff     = NULL,
01103                            MPI_Request* next_recv_req = NULL,
01104                            int* next_incoming         = NULL );
01105 
01106     //! process incoming message; if longer than the initial size, post
01107     //! recv for next part then send ack; if ack, send second part; else
01108     //! indicate that we're done and buffer is ready for processing
01109     ErrorCode recv_buffer( int mesg_tag_expected,
01110                            const MPI_Status& mpi_status,
01111                            Buffer* recv_buff,
01112                            MPI_Request& recv_2nd_req,
01113                            MPI_Request& ack_req,
01114                            int& this_incoming,
01115                            Buffer* send_buff,
01116                            MPI_Request& send_req,
01117                            MPI_Request& sent_ack_req,
01118                            bool& done,
01119                            Buffer* next_buff     = NULL,
01120                            int next_tag          = -1,
01121                            MPI_Request* next_req = NULL,
01122                            int* next_incoming    = NULL );
01123 
01124     //! pack a range of entities with equal # verts per entity, along with
01125     //! the range on the sending proc
01126     ErrorCode pack_entity_seq( const int nodes_per_entity,
01127                                const bool store_remote_handles,
01128                                const int to_proc,
01129                                Range& these_ents,
01130                                std::vector< EntityHandle >& entities,
01131                                Buffer* buff );
01132 
01133     ErrorCode print_buffer( unsigned char* buff_ptr, int mesg_type, int from_proc, bool sent );
01134 
01135     //! for all the entities in the received buffer; for each, save
01136     //! entities in this instance which match connectivity, or zero if none found
01137     ErrorCode unpack_iface_entities( unsigned char*& buff_ptr,
01138                                      const int from_proc,
01139                                      const int ind,
01140                                      std::vector< EntityHandle >& recd_ents );
01141 
01142     ErrorCode pack_sets( Range& entities, Buffer* buff, const bool store_handles, const int to_proc );
01143 
01144     ErrorCode unpack_sets( unsigned char*& buff_ptr,
01145                            std::vector< EntityHandle >& entities,
01146                            const bool store_handles,
01147                            const int to_proc );
01148 
01149     ErrorCode pack_adjacencies( Range& entities,
01150                                 Range::const_iterator& start_rit,
01151                                 Range& whole_range,
01152                                 unsigned char*& buff_ptr,
01153                                 int& count,
01154                                 const bool just_count,
01155                                 const bool store_handles,
01156                                 const int to_proc );
01157 
01158     ErrorCode unpack_adjacencies( unsigned char*& buff_ptr,
01159                                   Range& entities,
01160                                   const bool store_handles,
01161                                   const int from_proc );
01162 
01163     /* \brief Unpack message with remote handles (const pointer to buffer)
01164      */
01165     ErrorCode unpack_remote_handles( unsigned int from_proc,
01166                                      const unsigned char* buff_ptr,
01167                                      std::vector< EntityHandle >& L2hloc,
01168                                      std::vector< EntityHandle >& L2hrem,
01169                                      std::vector< unsigned int >& L2p );
01170 
01171     //! given connectivity and type, find an existing entity, if there is one
01172     ErrorCode find_existing_entity( const bool is_iface,
01173                                     const int owner_p,
01174                                     const EntityHandle owner_h,
01175                                     const int num_ents,
01176                                     const EntityHandle* connect,
01177                                     const int num_connect,
01178                                     const EntityType this_type,
01179                                     std::vector< EntityHandle >& L2hloc,
01180                                     std::vector< EntityHandle >& L2hrem,
01181                                     std::vector< unsigned int >& L2p,
01182                                     EntityHandle& new_h );
01183 
01184     ErrorCode build_sharedhps_list( const EntityHandle entity,
01185                                     const unsigned char pstatus,
01186                                     const int sharedp,
01187                                     const std::set< unsigned int >& procs,
01188                                     unsigned int& num_ents,
01189                                     int* tmp_procs,
01190                                     EntityHandle* tmp_handles );
01191 
01192     /**\brief Get list of tags for which to exchange data
01193      *
01194      * Get tags and entities for which to exchange tag data.  This function
01195      * was originally part of 'pack_tags' requested with the
01196      * 'all_possible_tags' parameter.
01197      *
01198      *\param all_entities  Input.  The set of entities for which data is to
01199      *                      be communicated.
01200      *\param all_tags      Output.  Populated with the handles of tags to be
01201      *                      sent.
01202      *\param tag_ranges    Output.  For each corresponding tag in all_tags, the
01203      *                      subset of 'all_entities' for which a tag value has
01204      *                      been set.
01205      */
01206     ErrorCode get_tag_send_list( const Range& all_entities,
01207                                  std::vector< Tag >& all_tags,
01208                                  std::vector< Range >& tag_ranges );
01209 
01210     /**\brief Serialize entity tag data
01211      *
01212      * This function operates in two passes.  The first phase,
01213      * specified by 'just_count == true' calculates the necessary
01214      * buffer size for the serialized data.  The second phase
01215      * writes the actual binary serialized representation of the
01216      * data to the passed buffer.
01217      *
01218      *\NOTE First two arguments are not used.  (Legacy interface?)
01219      *
01220      *\param entities      NOT USED
01221      *\param start_rit     NOT USED
01222      *\param whole_range   Should be the union of the sets of entities for
01223      *                     which tag values are to be serialized.  Also
01224      *                     specifies ordering for indexes for tag values and
01225      *                     serves as the superset from which to compose entity
01226      *                     lists from individual tags if just_count and
01227      *                     all_possible_tags are both true.
01228      *\param buff_ptr      Buffer into which to write binary serialized data
01229      *\param count         Output:  The size of the serialized data is added
01230      *                     to this parameter.  NOTE: Should probably initialize
01231      *                     to zero before calling.
01232      *\param just_count    If true, just calculate the buffer size required to
01233      *                     hold the serialized data.  Will also append to
01234      *                     'all_tags' and 'tag_ranges' if all_possible_tags
01235      *                     == true.
01236      *\param store_handles The data for each tag is preceded by a list of
01237      *                     EntityHandles designating the entity each of
01238      *                     the subsequent tag values corresponds to.  This value
01239      *                     may be one of:
01240      *                     1) If store_handles == false:
01241      *                        An invalid handle composed of {MBMAXTYPE,idx}, where
01242      *                        idx is the position of the entity in "whole_range".
01243      *                     2) If store_hanldes == true and a valid remote
01244      *                        handle exists, the remote handle.
01245      *                     3) If store_hanldes == true and no valid remote
01246      *                        handle is defined for the entity, the same as 1).
01247      *\param to_proc       If 'store_handles' is true, the processor rank for
01248      *                     which to store the corresponding remote entity
01249      *                     handles.
01250      *\param all_tags      List of tags to write
01251      *\param tag_ranges    List of entities to serialize tag data, one
01252      *                            for each corresponding tag handle in 'all_tags.
01253      */
01254     ErrorCode pack_tags( Range& entities,
01255                          const std::vector< Tag >& src_tags,
01256                          const std::vector< Tag >& dst_tags,
01257                          const std::vector< Range >& tag_ranges,
01258                          Buffer* buff,
01259                          const bool store_handles,
01260                          const int to_proc );
01261 
01262     /**\brief Calculate buffer size required to pack tag data
01263      *\param source_tag The tag for which data will be serialized
01264      *\param entities    The entities for which tag values will be serialized
01265      *\param count_out  Output: The required buffer size, in bytes.
01266      */
01267     ErrorCode packed_tag_size( Tag source_tag, const Range& entities, int& count_out );
01268 
01269     /**\brief Serialize tag data
01270      *\param source_tag    The tag for which data will be serialized
01271      *\param destination_tag Tag in which to store unpacked tag data.  Typically
01272      *                     the same as source_tag.
01273      *\param entities       The entities for which tag values will be serialized
01274      *\param whole_range   Calculate entity indices as location in this range
01275      *\param buff_ptr      Input/Output: As input, pointer to the start of the
01276      *                     buffer in which to serialize data.  As output, the
01277      *                     position just passed the serialized data.
01278      *\param count_out     Output: The required buffer size, in bytes.
01279      *\param store_handles The data for each tag is preceded by a list of
01280      *                     EntityHandles designating the entity each of
01281      *                     the subsequent tag values corresponds to.  This value
01282      *                     may be one of:
01283      *                     1) If store_handles == false:
01284      *                        An invalid handle composed of {MBMAXTYPE,idx}, where
01285      *                        idx is the position of the entity in "whole_range".
01286      *                     2) If store_hanldes == true and a valid remote
01287      *                        handle exists, the remote handle.
01288      *                     3) If store_hanldes == true and no valid remote
01289      *                        handle is defined for the entity, the same as 1).
01290      *\param to_proc       If 'store_handles' is true, the processor rank for
01291      *                     which to store the corresponding remote entity
01292      *                     handles.
01293      */
01294     ErrorCode pack_tag( Tag source_tag,
01295                         Tag destination_tag,
01296                         const Range& entities,
01297                         const std::vector< EntityHandle >& whole_range,
01298                         Buffer* buff,
01299                         const bool store_remote_handles,
01300                         const int to_proc );
01301 
01302     ErrorCode unpack_tags( unsigned char*& buff_ptr,
01303                            std::vector< EntityHandle >& entities,
01304                            const bool store_handles,
01305                            const int to_proc,
01306                            const MPI_Op* const mpi_op = NULL );
01307 
01308     ErrorCode tag_shared_verts( TupleList& shared_verts,
01309                                 Range* skin_ents,
01310                                 std::map< std::vector< int >, std::vector< EntityHandle > >& proc_nvecs,
01311                                 Range& proc_verts );
01312 
01313     ErrorCode get_proc_nvecs( int resolve_dim,
01314                               int shared_dim,
01315                               Range* skin_ents,
01316                               std::map< std::vector< int >, std::vector< EntityHandle > >& proc_nvecs );
01317 
01318     // after verifying shared entities, now parent/child links between sets can be established
01319     ErrorCode create_iface_pc_links();
01320 
01321     //! pack a range map with keys in this_range and values a contiguous series
01322     //! of handles starting at actual_start
01323     ErrorCode pack_range_map( Range& this_range, EntityHandle actual_start, HandleMap& handle_map );
01324 
01325     //! returns true if the set is an interface shared with to_proc
01326     bool is_iface_proc( EntityHandle this_set, int to_proc );
01327 
01328     //! for any remote_handles set to zero, remove corresponding sent_ents from
01329     //! iface_sets corresponding to from_proc
01330     ErrorCode update_iface_sets( Range& sent_ents, std::vector< EntityHandle >& remote_handles, int from_proc );
01331 
01332     //! for specified bridge/ghost dimension, to_proc, and number
01333     //! of layers, get the entities to be ghosted, and info on additional procs
01334     //! needing to communicate with to_proc
01335     ErrorCode get_ghosted_entities( int bridge_dim,
01336                                     int ghost_dim,
01337                                     int to_proc,
01338                                     int num_layers,
01339                                     int addl_ents,
01340                                     Range& ghosted_ents );
01341 
01342     //! add vertices adjacent to entities in this list
01343     ErrorCode add_verts( Range& sent_ents );
01344 
01345     //! Every processor sends shared entity handle data to every other processor
01346     //! that it shares entities with.  Passed back map is all received data,
01347     //! indexed by processor ID. This function is intended to be used for
01348     //! debugging.
01349     ErrorCode exchange_all_shared_handles( std::vector< std::vector< SharedEntityData > >& send_data,
01350                                            std::vector< std::vector< SharedEntityData > >& result );
01351 
01352     //! replace handles in from_vec with corresponding handles on
01353     //! to_proc (by checking shared[p/h]_tag and shared[p/h]s_tag;
01354     //! if no remote handle and new_ents is non-null, substitute
01355     //! instead CREATE_HANDLE(MBMAXTYPE, index) where index is handle's
01356     //! position in new_ents
01357     ErrorCode get_remote_handles( const bool store_remote_handles,
01358                                   EntityHandle* from_vec,
01359                                   EntityHandle* to_vec_tmp,
01360                                   int num_ents,
01361                                   int to_proc,
01362                                   const std::vector< EntityHandle >& new_ents );
01363 
01364     //! same as other version, except from_range and to_range should be
01365     //! different here
01366     ErrorCode get_remote_handles( const bool store_remote_handles,
01367                                   const Range& from_range,
01368                                   Range& to_range,
01369                                   int to_proc,
01370                                   const std::vector< EntityHandle >& new_ents );
01371 
01372     //! same as other version, except packs range into vector
01373     ErrorCode get_remote_handles( const bool store_remote_handles,
01374                                   const Range& from_range,
01375                                   EntityHandle* to_vec,
01376                                   int to_proc,
01377                                   const std::vector< EntityHandle >& new_ents );
01378 
01379     //! goes through from_vec, and for any with type MBMAXTYPE, replaces with
01380     //! new_ents value at index corresponding to id of entity in from_vec
01381     ErrorCode get_local_handles( EntityHandle* from_vec, int num_ents, const Range& new_ents );
01382 
01383     //! same as above except puts results in range
01384     ErrorCode get_local_handles( const Range& remote_handles,
01385                                  Range& local_handles,
01386                                  const std::vector< EntityHandle >& new_ents );
01387 
01388     //! same as above except gets new_ents from vector
01389     ErrorCode get_local_handles( EntityHandle* from_vec, int num_ents, const std::vector< EntityHandle >& new_ents );
01390 
01391     ErrorCode update_remote_data( Range& local_range,
01392                                   Range& remote_range,
01393                                   int other_proc,
01394                                   const unsigned char add_pstat );
01395 
01396     ErrorCode update_remote_data( const EntityHandle new_h,
01397                                   const int* ps,
01398                                   const EntityHandle* hs,
01399                                   const int num_ps,
01400                                   const unsigned char add_pstat );
01401 
01402     ErrorCode update_remote_data_old( const EntityHandle new_h,
01403                                       const int* ps,
01404                                       const EntityHandle* hs,
01405                                       const int num_ps,
01406                                       const unsigned char add_pstat );
01407 
01408     /** \brief Set pstatus tag interface bit on entities in sets passed in
01409      */
01410     ErrorCode tag_iface_entities();
01411 
01412     //! add a pc to the iface instance tag PARALLEL_COMM
01413     int add_pcomm( ParallelComm* pc );
01414 
01415     //! remove a pc from the iface instance tag PARALLEL_COMM
01416     void remove_pcomm( ParallelComm* pc );
01417 
01418     //! check entities to make sure there are no zero-valued remote handles
01419     //! where they shouldn't be
01420     ErrorCode check_sent_ents( Range& allsent );
01421 
01422     //! assign entities to the input processor part
01423     ErrorCode assign_entities_part( std::vector< EntityHandle >& entities, const int proc );
01424 
01425     //! remove entities to the input processor part
01426     ErrorCode remove_entities_part( Range& entities, const int proc );
01427 
01428     //! MB interface associated with this writer
01429     Interface* mbImpl;
01430 
01431     //! Proc config object, keeps info on parallel stuff
01432     ProcConfig procConfig;
01433 
01434     //! Sequence manager, to get more efficient access to entities
01435     SequenceManager* sequenceManager;
01436 
01437     //! Error handler
01438     Error* errorHandler;
01439 
01440     //! more data buffers, proc-specific
01441     std::vector< Buffer* > localOwnedBuffs, remoteOwnedBuffs;
01442 
01443     //! reset message buffers to their initial state
01444     // void reset_all_buffers();
01445 
01446     //! delete all buffers, freeing up any memory held by them
01447     void delete_all_buffers();
01448 
01449     //! request objects, may be used if store_remote_handles is used
01450     std::vector< MPI_Request > sendReqs;
01451 
01452     //! receive request objects
01453     std::vector< MPI_Request > recvReqs, recvRemotehReqs;
01454 
01455     //! processor rank for each buffer index
01456     std::vector< unsigned int > buffProcs;
01457 
01458     //! the partition, interface sets for this comm'n instance
01459     Range partitionSets, interfaceSets;
01460 
01461     //! all local entities shared with others, whether ghost or ghosted
01462     std::set< EntityHandle > sharedEnts;
01463 
01464     //! tags used to save sharing procs and handles
01465     Tag sharedpTag, sharedpsTag, sharedhTag, sharedhsTag, pstatusTag, ifaceSetsTag, partitionTag;
01466 
01467     int globalPartCount;  //!< Cache of global part count
01468 
01469     EntityHandle partitioningSet;  //!< entity set containing all parts
01470 
01471     std::ofstream myFile;
01472 
01473     int pcommID;
01474 
01475     int ackbuff;
01476 
01477     //! used to set verbosity level and to report output
01478     DebugOutput* myDebug;
01479 
01480     //! Data about shared sets
01481     SharedSetData* sharedSetData;
01482 };
01483 
01484 inline ParallelComm::Buffer::Buffer( const Buffer& other_buff )
01485 {
01486     alloc_size = other_buff.alloc_size;
01487     mem_ptr    = (unsigned char*)malloc( alloc_size );
01488     memcpy( mem_ptr, other_buff.mem_ptr, alloc_size );
01489     buff_ptr = mem_ptr + ( other_buff.buff_ptr - other_buff.mem_ptr );
01490 }
01491 
01492 inline ParallelComm::Buffer::Buffer( unsigned int new_size ) : mem_ptr( NULL ), buff_ptr( NULL ), alloc_size( 0 )
01493 {
01494     if( new_size ) this->reserve( new_size );
01495 }
01496 
01497 inline ParallelComm::Buffer::~Buffer()
01498 {
01499     if( mem_ptr )
01500     {
01501         free( mem_ptr );
01502         mem_ptr = NULL;
01503     }
01504 }
01505 
01506 #define DEBUG_BUFFER 0
01507 
01508 inline void ParallelComm::Buffer::reserve( unsigned int new_size )
01509 {
01510 
01511 #ifdef DEBUG_BUFFER
01512     int tmp_pos = 0;
01513     if( mem_ptr )
01514     {
01515         tmp_pos = buff_ptr - mem_ptr;
01516     }
01517     buff_ptr = (unsigned char*)malloc( new_size );
01518     assert( 0 <= tmp_pos && tmp_pos <= (int)alloc_size );
01519     if( tmp_pos ) memcpy( buff_ptr, mem_ptr, tmp_pos );
01520     if( mem_ptr ) free( mem_ptr );
01521     mem_ptr    = buff_ptr;
01522     alloc_size = new_size;
01523     buff_ptr   = mem_ptr + tmp_pos;
01524 #else
01525     if( mem_ptr && alloc_size < new_size )
01526     {
01527         size_t tmp_pos = mem_ptr ? buff_ptr - mem_ptr : 0;
01528         mem_ptr        = (unsigned char*)realloc( mem_ptr, new_size );
01529         alloc_size     = new_size;
01530         buff_ptr       = mem_ptr + tmp_pos;
01531     }
01532     else if( !mem_ptr )
01533     {
01534         mem_ptr    = (unsigned char*)malloc( new_size );
01535         alloc_size = new_size;
01536         buff_ptr   = mem_ptr;
01537     }
01538 #endif
01539 }
01540 
01541 inline void ParallelComm::Buffer::check_space( unsigned int addl_space )
01542 {
01543     assert( buff_ptr >= mem_ptr && buff_ptr <= mem_ptr + alloc_size );
01544     unsigned int new_size = buff_ptr - mem_ptr + addl_space;
01545     if( new_size > alloc_size ) reserve( 3 * new_size / 2 );
01546 }
01547 
01548 inline void ParallelComm::reset_all_buffers()
01549 {
01550     std::vector< Buffer* >::iterator vit;
01551     for( vit = localOwnedBuffs.begin(); vit != localOwnedBuffs.end(); ++vit )
01552         ( *vit )->reset_buffer();
01553     for( vit = remoteOwnedBuffs.begin(); vit != remoteOwnedBuffs.end(); ++vit )
01554         ( *vit )->reset_buffer();
01555 }
01556 
01557 inline void ParallelComm::delete_all_buffers()
01558 {
01559     std::vector< Buffer* >::iterator vit;
01560     for( vit = localOwnedBuffs.begin(); vit != localOwnedBuffs.end(); ++vit )
01561         delete( *vit );
01562     localOwnedBuffs.clear();
01563 
01564     for( vit = remoteOwnedBuffs.begin(); vit != remoteOwnedBuffs.end(); ++vit )
01565         delete( *vit );
01566     remoteOwnedBuffs.clear();
01567 }
01568 
01569 inline const std::vector< unsigned int >& ParallelComm::buff_procs() const
01570 {
01571     return buffProcs;
01572 }
01573 
01574 inline ErrorCode ParallelComm::get_shared_proc_tags( Tag& sharedp,
01575                                                      Tag& sharedps,
01576                                                      Tag& sharedh,
01577                                                      Tag& sharedhs,
01578                                                      Tag& pstatus )
01579 {
01580     sharedp  = sharedp_tag();
01581     sharedps = sharedps_tag();
01582     sharedh  = sharedh_tag();
01583     sharedhs = sharedhs_tag();
01584     pstatus  = pstatus_tag();
01585 
01586     return MB_SUCCESS;
01587 }
01588 
01589 inline ErrorCode ParallelComm::exchange_tags( const char* tag_name, const Range& entities )
01590 {
01591     // get the tag handle
01592     std::vector< Tag > tags( 1 );
01593     ErrorCode result = mbImpl->tag_get_handle( tag_name, 0, MB_TYPE_OPAQUE, tags[0], MB_TAG_ANY );
01594     if( MB_SUCCESS != result )
01595         return result;
01596     else if( !tags[0] )
01597         return MB_TAG_NOT_FOUND;
01598 
01599     return exchange_tags( tags, tags, entities );
01600 }
01601 
01602 inline ErrorCode ParallelComm::exchange_tags( Tag tagh, const Range& entities )
01603 {
01604     // get the tag handle
01605     std::vector< Tag > tags;
01606     tags.push_back( tagh );
01607 
01608     return exchange_tags( tags, tags, entities );
01609 }
01610 
01611 inline ErrorCode ParallelComm::reduce_tags( const char* tag_name, const MPI_Op mpi_op, const Range& entities )
01612 {
01613     // get the tag handle
01614     std::vector< Tag > tags( 1 );
01615     ErrorCode result = mbImpl->tag_get_handle( tag_name, 0, MB_TYPE_OPAQUE, tags[0], MB_TAG_ANY );
01616     if( MB_SUCCESS != result )
01617         return result;
01618     else if( !tags[0] )
01619         return MB_TAG_NOT_FOUND;
01620 
01621     return reduce_tags( tags, tags, mpi_op, entities );
01622 }
01623 
01624 inline ErrorCode ParallelComm::reduce_tags( Tag tagh, const MPI_Op mpi_op, const Range& entities )
01625 {
01626     // get the tag handle
01627     std::vector< Tag > tags;
01628     tags.push_back( tagh );
01629 
01630     return reduce_tags( tags, tags, mpi_op, entities );
01631 }
01632 
01633 inline ErrorCode ParallelComm::get_comm_procs( std::set< unsigned int >& procs )
01634 {
01635     ErrorCode result = get_interface_procs( procs );
01636     if( MB_SUCCESS != result ) return result;
01637 
01638     std::copy( buffProcs.begin(), buffProcs.end(), std::inserter( procs, procs.begin() ) );
01639 
01640     return MB_SUCCESS;
01641 }
01642 
01643 inline ErrorCode ParallelComm::get_owner( EntityHandle entity, int& owner )
01644 {
01645     EntityHandle tmp_handle;
01646     return get_owner_handle( entity, owner, tmp_handle );
01647 }
01648 
01649 /* \brief Unpack message with remote handles (const pointer to buffer)
01650  */
01651 inline ErrorCode ParallelComm::unpack_remote_handles( unsigned int from_proc,
01652                                                       const unsigned char* buff_ptr,
01653                                                       std::vector< EntityHandle >& L2hloc,
01654                                                       std::vector< EntityHandle >& L2hrem,
01655                                                       std::vector< unsigned int >& L2p )
01656 {
01657     // cast away const-ness, we won't be passing back a modified ptr
01658     unsigned char* tmp_buff = const_cast< unsigned char* >( buff_ptr );
01659     return unpack_remote_handles( from_proc, tmp_buff, L2hloc, L2hrem, L2p );
01660 }
01661 
01662 inline void ParallelComm::set_rank( unsigned int r )
01663 {
01664     procConfig.proc_rank( r );
01665     if( procConfig.proc_size() < r ) procConfig.proc_size( r + 1 );
01666 }
01667 
01668 inline void ParallelComm::set_size( unsigned int s )
01669 {
01670     procConfig.proc_size( s );
01671 }
01672 
01673 inline ErrorCode ParallelComm::get_sharing_data( const EntityHandle* entities,
01674                                                  int num_entities,
01675                                                  std::set< int >& procs,
01676                                                  int op )
01677 {
01678     Range dum_range;
01679     // cast away constness 'cuz the range is passed as const
01680     EntityHandle* ents_cast = const_cast< EntityHandle* >( entities );
01681     std::copy( ents_cast, ents_cast + num_entities, range_inserter( dum_range ) );
01682     return get_sharing_data( dum_range, procs, op );
01683 }
01684 
01685 inline ErrorCode ParallelComm::get_sharing_data( const EntityHandle entity,
01686                                                  int* ps,
01687                                                  EntityHandle* hs,
01688                                                  unsigned char& pstat,
01689                                                  int& num_ps )
01690 {
01691     unsigned int dum_ps;
01692     ErrorCode result = get_sharing_data( entity, ps, hs, pstat, dum_ps );
01693     if( MB_SUCCESS == result ) num_ps = dum_ps;
01694     return result;
01695 }
01696 
01697 inline void ParallelComm::set_send_request( int n_request )
01698 {
01699     sendReqs.resize( n_request, MPI_REQUEST_NULL );
01700 }
01701 
01702 inline void ParallelComm::set_recv_request( int n_request )
01703 {
01704     recvReqs.resize( n_request, MPI_REQUEST_NULL );
01705 }
01706 }  // namespace moab
01707 
01708 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines