Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
ScdInterface.hpp
Go to the documentation of this file.
00001 /** \file ScdInterface.hpp
00002  */
00003 #ifndef SCD_INTERFACE
00004 #define SCD_INTERFACE
00005 
00006 #include "moab/Interface.hpp"
00007 #include "moab/HomXform.hpp"
00008 
00009 #include <iostream>
00010 #include <vector>
00011 #include <cassert>
00012 
00013 #include "moab/win32_config.h"
00014 
00015 namespace moab
00016 {
00017 
00018 class StructuredElementSeq;
00019 class EntitySequence;
00020 class ScdVertexData;
00021 class EntitySequence;
00022 class ScdBox;
00023 class ParallelComm;
00024 
00025 /** \class ScdInterface ScdInterface.hpp "moab/ScdInterface.hpp"
00026  * \brief A structured mesh interface for MOAB-based data
00027  *
00028  * Structured mesh in MOAB is created and accessed through the ScdInterface and ScdBox classes.
00029  *
00030  * \section Construction Construction and Representation
00031  * Structured mesh can be constructed in one of two ways.  First, a rectangular block of mesh,
00032  * both vertices and edges/quads/hexes, can be created in one shot, using the construct_box method.
00033  * In this case, there are single sequences of vertices/entities.  The second method for creating
00034  * structured mesh is to create the structured blocks of vertices and elements separately.  In
00035  * this case, different blocks of elements can share blocks of vertices, and each block of
00036  * elements has its own independent parametric space.  The algorithms behind this representation
00037  * are described in T. Tautges, "MOAB-SD: Integrated structured and unstructured mesh
00038  * representation", Eng. w Comp, vol 20 no. 3.
00039  *
00040  * Structured mesh is represented in MOAB down at the element sequence level, which is something
00041  * applications don't see.  In addition, when structured mesh is created, entity sets are also
00042  * created and tagged with information about the parametric space.  In particular, the BOX_DIMS
00043  * tag is used to indicate the lower and upper corners in parametric space (this
00044  * tag is integer size 6).  Structured mesh blocks are also available through ScdBox class objects
00045  * returned by ScdInterface.  These class objects should be treated only as references to the
00046  * structured mesh blocks; that is, the structured mesh referenced by these objects is not deleted
00047  * when the ScdBox instance is destroyed.  Functions for destroying the actual mesh are available
00048  * on this class, though.
00049  *
00050  * Structured mesh blocks are returned in the form of ScdBox class objects.  Each ScdBox instance
00051  * represents a rectangular block of vertices and possibly elements (edges, quads, or hexes).  The
00052  * edge/quad/hex entity handles for a ScdBox are guaranteed to be contiguous, starting at a starting
00053  * value which is also available through the ScdBox class.  However, vertex handles may or may not
00054  * be contiguous, depending on the construction method.  The start vertex handle is also available
00055  * from the ScdBox class.
00056  *
00057  * \section Parameters Parametric Space
00058  *
00059  * Each structured box has a parametric (ijk) space, which can be queried through the ScdBox
00060  * interface. For non-periodic boxes, the edge/quad/hex parameter bounds are one less in each
00061  * dimension than that of the vertices, otherwise they are the same as the vertex parameter bounds.
00062  * In a parallel representation, boxes are locally non-periodic by default, but global ids are
00063  * assigned such that the last set of vertices in a periodic direction match those of the first set
00064  * of vertices in that direction.
00065  *
00066  * Entity handles are allocated with the i parameter varying fastest, then j, then k.
00067  *
00068  * \section Per Periodic Meshes
00069  * Boxes can be periodic in i, or j, or both i and j.  If only i or j is periodic, the corresponding
00070  * mesh is a strip or an annular cylinder; if both i and j are periodic, the corresponding mesh is
00071  * an annular torus.  A box cannot be periodic in all three parameters.  If i and/or j is periodic,
00072  * and assuming IMIN/JMIN is zero, the parameter extents in the/each periodic direction (IMAX/JMAX)
00073  * for vertices and edges/faces/hexes are the same, and the vertices on the "top" end in the
00074  * periodic direction are at parameter value IMIN/JMIN.
00075  *
00076  * \section Par Parallel Representation
00077  *
00078  * For parallel structured meshes, each local mesh (the mesh on a given process) looks like a
00079  * non-periodic structured mesh, and there are both local and global parameters of the structured
00080  * mesh.  If the mesh is periodic in a given direction, the last process in the periodic direction
00081  * has local IMAX/JMAX that is one greater than the global IMAX/JMAX.
00082  *
00083  *
00084  * In parallel, the periodicity described in the previous paragraph is "local periodicity"; there is
00085  * also the notion of global periodicity.  For serial meshes, those concepts are the same.  In
00086  * parallel, a mesh can be locally non-periodic but globally periodic in a given direction.  In that
00087  * case, the local mesh is still non-periodic, i.e. the parametric extents for edges is one fewer
00088  * than that of vertices in that direction. However, vertices are given global ids such that they
00089  * match those of the parametric minimum in that direction. Geometric positions of the vertices at
00090  * the high end should still be greater than the ones just below.
00091  *
00092  * \section Adjs Adjacent Entities
00093  * This interface supports parametric access to intermediate-dimension entities, e.g. adjacent faces
00094  * and edges in a 3d mesh.  In this case, a direction parameter is added, to identify the parametric
00095  * direction of the entities being requested.  For example, to retrieve the faces adjacent to a hex
00096  * with parameters ijk, in the i parametric direction, you would use the parameters ijk0.  These
00097  * intermediate entities are not stored in a structured representation, but their parametric
00098  * positions can be evaluated based on their adjacencies to higher-dimensional entities.  Thanks to
00099  * Milad Fatenejad for the thinking behind this.
00100  *
00101  * \section Evaluation Evaluation
00102  * The ScdBox class provides functions for evaluating the mesh based on the ijk parameter space.
00103  * These functions are inlined where possible, for efficiency.
00104  */
00105 
00106 //! struct for keeping parallel data in one place
00107 class ScdParData
00108 {
00109   public:
00110     ScdParData() : partMethod( NOPART ), pComm( NULL )
00111     {
00112         gDims[0] = gDims[1] = gDims[2] = gDims[3] = gDims[4] = gDims[5] = 0;
00113         gPeriodic[0] = gPeriodic[1] = gPeriodic[2] = 0;
00114         pDims[0] = pDims[1] = pDims[2] = 0;
00115     }
00116 
00117     //! Partition method enumeration; these strategies are described in comments for
00118     //! compute_partition_alljorkori, compute_partition_alljkbal, compute_partition_sqij,
00119     //! compute_partition_sqjk, and compute_partition_sqijk
00120     enum PartitionMethod
00121     {
00122         ALLJORKORI = 0,
00123         ALLJKBAL,
00124         SQIJ,
00125         SQJK,
00126         SQIJK,
00127         TRIVIAL,
00128         RCBZOLTAN,
00129         NOPART
00130     };
00131 
00132     //! Partition method names
00133     static MOAB_EXPORT const char* PartitionMethodNames[NOPART + 1];
00134 
00135     //! partition method used to partition global parametric space
00136     int partMethod;
00137 
00138     //! lower and upper corners of global box
00139     int gDims[6];
00140 
00141     //! is globally periodic in i or j or k
00142     int gPeriodic[3];
00143 
00144     //! number of procs in each direction
00145     int pDims[3];
00146 
00147     //! parallel communicator object for this par scd mesh
00148     ParallelComm* pComm;
00149 };
00150 
00151 class MOAB_EXPORT ScdInterface
00152 {
00153   public:
00154     friend class ScdBox;
00155 
00156     //! Constructor
00157     /** Constructor; if find_boxes is true, this will search for entity sets marked as
00158      * structured blocks, based on the BOX_DIMS tag.  Structured mesh blocks will be stored
00159      * in this interface class for future retrieval.  Structured mesh blocks created through
00160      * this interface will also be stored here.
00161      * \param impl MOAB instance
00162      * \param find_boxes If true, search all the entity sets, caching the structured mesh blocks
00163      */
00164     ScdInterface( Interface* impl, bool find_boxes = false );
00165 
00166     // Destructor
00167     ~ScdInterface();
00168 
00169     //! Return the MOAB Interface instance *
00170     Interface* impl() const;
00171 
00172     //! Construct new structured mesh box, including both vertices and elements
00173     /** Parameter range
00174      * for vertex box is [low-high], for elements is [low-high).  Construct quads by passing
00175      * in low[2] == high[2], and edges by passing in low[1] == high[1] and low[2] == high[2].
00176      * The result is passed back in a ScdBox*, which is a *reference* to the box of structured mesh.
00177      * That is, the actual mesh is retained in MOAB when the ScdBox is destroyed.  To actually
00178      * destroy the mesh, call the destroy_mesh function on the ScdBox object first, before
00179      * destroying it. \param low Lower corner in parameter space \param high Higher corner in
00180      * parameter space \param coords Coordinates of vertices, interleaved (xyzxyz...); if NULL,
00181      * coords are set to parametric values \param num_coords Number of coordinate values \param
00182      * new_box Reference to box of structured mesh \param lperiodic[3] If lperiodic[s] != 0,
00183      * direction s is locally periodic \param par_data If non-NULL, this will get stored on the
00184      * ScdBox once created, contains info about global parallel nature of ScdBox across procs \param
00185      * assign_global_ids If true, assigns 1-based global ids to vertices using GLOBAL_ID_TAG_NAME
00186      * \param resolve_shared_ents If != -1, resolves shared entities up to and including dimension
00187      * equal to value
00188      */
00189     ErrorCode construct_box( HomCoord low,
00190                              HomCoord high,
00191                              const double* const coords,
00192                              unsigned int num_coords,
00193                              ScdBox*& new_box,
00194                              int* const lperiodic       = NULL,
00195                              ScdParData* const par_data = NULL,
00196                              bool assign_global_ids     = false,
00197                              int resolve_shared_ents    = -1 );
00198 
00199     //! Create a structured sequence of vertices, quads, or hexes
00200     /** Starting handle for the sequence is available from the returned ScdBox.
00201      * If creating a structured quad or hex box, subsequent calls must be made to ScdBox::add_vbox,
00202      * until all the vertices have been filled in for the box.
00203      * \param low Lower corner of structured box
00204      * \param high Higher corner of structured box
00205      * \param type EntityType, one of MBVERTEX, MBEDGE, MBQUAD, MBHEX
00206      * \param starting_id Requested start id of entities
00207      * \param new_box Reference to the newly created box of entities
00208      * \param is_periodic[3] If is_periodic[s] is non-zero, mesh should be periodic in direction s
00209      * (s=[0,1,2])
00210      */
00211     ErrorCode create_scd_sequence( const HomCoord& low,
00212                                    const HomCoord& high,
00213                                    EntityType type,
00214                                    int starting_id,
00215                                    ScdBox*& new_box,
00216                                    int* is_periodic = NULL );
00217 
00218     //! Return all the structured mesh blocks in this MOAB instance, as ScdBox objects
00219     /** Return the structured blocks in this MOAB instance.  If these were not searched for
00220      * at instantiation time, then the search is done now.
00221      * \param boxes Vector of ScdBox objects representing structured mesh blocks
00222      */
00223     ErrorCode find_boxes( std::vector< ScdBox* >& boxes );
00224 
00225     //! Return all the structured mesh blocks in this MOAB instance, as entity set handles
00226     /** Return the structured blocks in this MOAB instance.  If these were not searched for
00227      * at instantiation time, then the search is done now.
00228      * \param boxes Range of entity set objects representing structured mesh blocks
00229      */
00230     ErrorCode find_boxes( Range& boxes );
00231 
00232     //! Return all the structured mesh blocks known by ScdInterface (does not search)
00233     /** Return the structured blocks in this ScdInterface instance.  Does not search for new boxes,
00234      * just returns the contents of the list.
00235      * \param boxes Structured boxes
00236      */
00237     ErrorCode get_boxes( std::vector< ScdBox* >& boxes );
00238 
00239     //! Return the tag marking the lower and upper corners of boxes
00240     /**
00241      * \param create_if_missing If the tag does not yet exist, create it
00242      */
00243     Tag box_dims_tag( bool create_if_missing = true );
00244 
00245     //! Return the tag marking the global lower and upper corners of boxes
00246     /**
00247      * \param create_if_missing If the tag does not yet exist, create it
00248      */
00249     Tag global_box_dims_tag( bool create_if_missing = true );
00250 
00251     //! Return the tag marking the partitioning method used to partition the box in parallel
00252     /**
00253      * \param create_if_missing If the tag does not yet exist, create it
00254      */
00255     Tag part_method_tag( bool create_if_missing = true );
00256 
00257     //! Return the tag marking whether box is periodic in i and j
00258     /**
00259      * \param create_if_missing If the tag does not yet exist, create it
00260      */
00261     Tag box_periodic_tag( bool create_if_missing = true );
00262 
00263     //! Return the tag marking the ScdBox for a set
00264     /**
00265      * \param create_if_missing If the tag does not yet exist, create it
00266      */
00267     Tag box_set_tag( bool create_if_missing = true );
00268 
00269     //! Return the ScdBox corresponding to the entity set passed in
00270     /** If the entity isn't a structured box set, NULL is returned.
00271      * \param eh Entity whose box is being queried
00272      */
00273     ScdBox* get_scd_box( EntityHandle eh );
00274 
00275     //! Compute a partition of structured parameter space
00276     /** Compute a partition of structured parameter space, based on data in the ScdParData
00277      * passed in.  Results are passed back in arguments, which application can set back into
00278      * par_data argument if they so desire.
00279      * \param np Number of processors
00280      * \param nr Rank of this processor
00281      * \param par_data ScdParData object that contains input global parameter space, desired
00282      *           partitioning method, and information about global periodicity.
00283      * \param ldims Local parameters for grid
00284      * \param lperiodic Whether or not a given dimension is locally periodic
00285      * \param pdims Number of procs in i, j, k directions
00286      */
00287     static ErrorCode compute_partition( int np,
00288                                         int nr,
00289                                         const ScdParData& par_data,
00290                                         int* ldims,
00291                                         int* lperiodic = NULL,
00292                                         int* pdims     = NULL );
00293 
00294     //! Get information about the neighbor in the dijk[] direction, where dijk can be -1 or 1 for
00295     //! all 3 params
00296     /** Get information about the neighbor in the dijk[] direction, where dijk can be -1 or 1 for
00297      * all 3 params \param np (in) Total # procs \param nr Processor from which neighbor is
00298      * requested \param spd (in) ScdParData containing part method, gdims, gperiodic data \param
00299      * dijk(*) (in) Direction being queried, = +/-1 or 0 \param pto (out) Processor holding the
00300      * destination part \param rdims(6) (out) Parametric min/max of destination part \param
00301      * facedims(6) (out) Parametric min/max of interface between pfrom and pto; if at the max in a
00302      * periodic direction, set to global min of that direction \param across_bdy(3) (out) If
00303      * across_bdy[i] is -1(1), interface with pto is across periodic lower(upper) bdy in parameter
00304      * i, 0 otherwise
00305      */
00306     static ErrorCode get_neighbor( int np,
00307                                    int nr,
00308                                    const ScdParData& spd,
00309                                    const int* const dijk,
00310                                    int& pto,
00311                                    int* rdims,
00312                                    int* facedims,
00313                                    int* across_bdy );
00314 
00315     //! Tag vertices with sharing data for parallel representations
00316     /** Given the ParallelComm object to use, tag the vertices shared with other processors
00317      */
00318     ErrorCode tag_shared_vertices( ParallelComm* pcomm, EntityHandle seth );
00319 
00320     //! Tag vertices with sharing data for parallel representations
00321     /** Given the ParallelComm object to use, tag the vertices shared with other processors
00322      */
00323     ErrorCode tag_shared_vertices( ParallelComm* pcomm, ScdBox* box );
00324 
00325   protected:
00326     //! Remove the box from the list on ScdInterface
00327     ErrorCode remove_box( ScdBox* box );
00328 
00329     //! Add the box to the list on ScdInterface
00330     ErrorCode add_box( ScdBox* box );
00331 
00332   private:
00333     //! Create an entity set for a box, and tag with the parameters
00334     /** \param low Lower corner parameters for this box
00335      * \param high Upper corner parameters for this box
00336      * \param scd_set Entity set created
00337      * \param is_periodic[3] If is_periodic[s] is non-zero, mesh should be periodic in direction s
00338      * (s=[0,1,2])
00339      */
00340     ErrorCode create_box_set( const HomCoord& low,
00341                               const HomCoord& high,
00342                               EntityHandle& scd_set,
00343                               int* is_periodic = NULL );
00344 
00345     //! Compute a partition of structured parameter space
00346     /** Partitions the structured parametric space by partitioning j, k, or i only.
00347      * If j is greater than #procs, partition that, else k, else i.
00348      * For description of arguments, see ScdInterface::compute_partition.
00349      */
00350     inline static ErrorCode compute_partition_alljorkori( int np,
00351                                                           int nr,
00352                                                           const int gijk[6],
00353                                                           const int* const gperiodic,
00354                                                           int* lijk,
00355                                                           int* lperiodic,
00356                                                           int* pijk );
00357 
00358     //! Compute a partition of structured parameter space
00359     /** Partitions the structured parametric space by partitioning j, and possibly k,
00360      * seeking square regions of jk space
00361      * For description of arguments, see ScdInterface::compute_partition.
00362      */
00363     inline static ErrorCode compute_partition_alljkbal( int np,
00364                                                         int nr,
00365                                                         const int gijk[6],
00366                                                         const int* const gperiodic,
00367                                                         int* lijk,
00368                                                         int* lperiodic,
00369                                                         int* pijk );
00370 
00371     //! Compute a partition of structured parameter space
00372     /** Partitions the structured parametric space by seeking square ij partitions
00373      * For description of arguments, see ScdInterface::compute_partition.
00374      */
00375     inline static ErrorCode compute_partition_sqij( int np,
00376                                                     int nr,
00377                                                     const int gijk[6],
00378                                                     const int* const gperiodic,
00379                                                     int* lijk,
00380                                                     int* lperiodic,
00381                                                     int* pijk );
00382 
00383     //! Compute a partition of structured parameter space
00384     /** Partitions the structured parametric space by seeking square jk partitions
00385      * For description of arguments, see ScdInterface::compute_partition.
00386      */
00387     inline static ErrorCode compute_partition_sqjk( int np,
00388                                                     int nr,
00389                                                     const int gijk[6],
00390                                                     const int* const gperiodic,
00391                                                     int* lijk,
00392                                                     int* lperiodic,
00393                                                     int* pijk );
00394 
00395     //! Compute a partition of structured parameter space
00396     /** Partitions the structured parametric space by seeking square ijk partitions
00397      * For description of arguments, see ScdInterface::compute_partition.
00398      */
00399     inline static ErrorCode compute_partition_sqijk( int np,
00400                                                      int nr,
00401                                                      const int gijk[6],
00402                                                      const int* const gperiodic,
00403                                                      int* lijk,
00404                                                      int* lperiodic,
00405                                                      int* pijk );
00406 
00407     //! Get vertices shared with other processors
00408     /** Shared vertices returned as indices into each proc's handle space
00409      * \param box Box used to get parametric space info
00410      * \param procs Procs this proc shares vertices with
00411      * \param offsets Offsets into indices list for each proc
00412      * \param shared_indices local/remote indices of shared vertices
00413      */
00414     static ErrorCode get_shared_vertices( ParallelComm* pcomm,
00415                                           ScdBox* box,
00416                                           std::vector< int >& procs,
00417                                           std::vector< int >& offsets,
00418                                           std::vector< int >& shared_indices );
00419 
00420     static ErrorCode get_indices( const int* const ldims,
00421                                   const int* const rdims,
00422                                   const int* const across_bdy,
00423                                   int* face_dims,
00424                                   std::vector< int >& shared_indices );
00425 
00426     static ErrorCode get_neighbor_alljorkori( int np,
00427                                               int pfrom,
00428                                               const int* const gdims,
00429                                               const int* const gperiodic,
00430                                               const int* const dijk,
00431                                               int& pto,
00432                                               int* rdims,
00433                                               int* facedims,
00434                                               int* across_bdy );
00435 
00436     static ErrorCode get_neighbor_alljkbal( int np,
00437                                             int pfrom,
00438                                             const int* const gdims,
00439                                             const int* const gperiodic,
00440                                             const int* const dijk,
00441                                             int& pto,
00442                                             int* rdims,
00443                                             int* facedims,
00444                                             int* across_bdy );
00445 
00446     static ErrorCode get_neighbor_sqij( int np,
00447                                         int pfrom,
00448                                         const int* const gdims,
00449                                         const int* const gperiodic,
00450                                         const int* const dijk,
00451                                         int& pto,
00452                                         int* rdims,
00453                                         int* facedims,
00454                                         int* across_bdy );
00455 
00456     static ErrorCode get_neighbor_sqjk( int np,
00457                                         int pfrom,
00458                                         const int* const gdims,
00459                                         const int* const gperiodic,
00460                                         const int* const dijk,
00461                                         int& pto,
00462                                         int* rdims,
00463                                         int* facedims,
00464                                         int* across_bdy );
00465 
00466     static ErrorCode get_neighbor_sqijk( int np,
00467                                          int pfrom,
00468                                          const int* const gdims,
00469                                          const int* const gperiodic,
00470                                          const int* const dijk,
00471                                          int& pto,
00472                                          int* rdims,
00473                                          int* facedims,
00474                                          int* across_bdy );
00475 
00476     static int gtol( const int* gijk, int i, int j, int k );
00477 
00478     //! assign global ids to vertices in this box
00479     ErrorCode assign_global_ids( ScdBox* box );
00480 
00481     //! interface instance
00482     Interface* mbImpl;
00483 
00484     //! whether we've searched the database for boxes yet
00485     bool searchedBoxes;
00486 
00487     //! structured mesh blocks; stored as ScdBox objects, can get sets from those
00488     std::vector< ScdBox* > scdBoxes;
00489 
00490     //! tag representing whether box is periodic in i and j
00491     Tag boxPeriodicTag;
00492 
00493     //! tag representing box lower and upper corners
00494     Tag boxDimsTag;
00495 
00496     //! tag representing global lower and upper corners
00497     Tag globalBoxDimsTag;
00498 
00499     //! tag representing partition method
00500     Tag partMethodTag;
00501 
00502     //! tag pointing from set to ScdBox
00503     Tag boxSetTag;
00504 };
00505 
00506 class MOAB_EXPORT ScdBox
00507 {
00508     friend class ScdInterface;
00509 
00510   public:
00511     //! Destructor
00512     ~ScdBox();
00513 
00514     //! Return the ScdInterface responsible for this box
00515     inline ScdInterface* sc_impl() const;
00516 
00517     //! Add a vertex box to this box
00518     /* Add a vertex box to the element sequence referenced by this box.  The passed in vbox must
00519      * be a vertex box, with parametric extents no larger than that of this box.  This vbox is
00520      * oriented to this box by matching parameters from1-from3 in vbox to to1-to3 in this box.
00521      * If bb_input is true, only the part of the vertex sequence between bb_min and bb_max is
00522      * referenced \param vbox The vertex box being added to this box \param from1 1st reference
00523      * point on vbox \param to1 1st reference point on this box \param from2 2nd reference point on
00524      * vbox \param to2 2nd reference point on this box \param from3 3rd reference point on vbox
00525      * \param to3 3rd reference point on this box
00526      * \param bb_input If true, subsequent parameters list extents of vbox referenced
00527      * \param bb_min Lower corner of rectangle referenced
00528      * \param bb_max Upper corner of rectangle referenced
00529      */
00530     ErrorCode add_vbox( ScdBox* vbox,
00531                         HomCoord from1,
00532                         HomCoord to1,
00533                         HomCoord from2,
00534                         HomCoord to2,
00535                         HomCoord from3,
00536                         HomCoord to3,
00537                         bool bb_input          = false,
00538                         const HomCoord& bb_min = HomCoord::getUnitv( 0 ),
00539                         const HomCoord& bb_max = HomCoord::getUnitv( 0 ) );
00540     // const HomCoord &bb_min = HomCoord::unitv[0],
00541     // const HomCoord &bb_max = HomCoord::unitv[0]);
00542 
00543     //! Return whether this box has all its vertices defined
00544     /** Tests whether vertex boxs added with add_vbox have completely defined the vertex parametric
00545      * space for this box.
00546      *
00547      */
00548     bool boundary_complete() const;
00549 
00550     //! Return highest topological dimension of box
00551     inline int box_dimension() const;
00552 
00553     //! Starting vertex handle for this box
00554     inline EntityHandle start_vertex() const;
00555 
00556     //! Starting entity handle for this box
00557     /** If this is a vertex box, the start vertex handle is returned.
00558      */
00559     inline EntityHandle start_element() const;
00560 
00561     //! Return the number of elements in the box
00562     /* Number of elements is (boxSize[0]-1)(boxSize[1]-1)(boxSize[2]-1)
00563      */
00564     inline int num_elements() const;
00565 
00566     //! Return the number of vertices in the box
00567     /* Number of vertices is boxSize[0] * boxSize[1] * boxSize[2]
00568      */
00569     inline int num_vertices() const;
00570 
00571     //! Return the parametric coordinates for this box
00572     /**
00573      * \return IJK parameters of lower and upper corners
00574      */
00575     inline const int* box_dims() const;
00576 
00577     //! Return the lower corner parametric coordinates for this box
00578     inline HomCoord box_min() const;
00579 
00580     //! Return the upper corner parametric coordinates for this box
00581     inline HomCoord box_max() const;
00582 
00583     //! Return the parameter extents for this box
00584     inline HomCoord box_size() const;
00585 
00586     //! Return the parametric extents for this box
00587     /**
00588      * \param ijk IJK extents of this box
00589      */
00590     inline void box_size( int* ijk ) const;
00591 
00592     //! Return the parametric extents for this box
00593     /**
00594      * \param i I extent of this box
00595      * \param j J extent of this box
00596      * \param k K extent of this box
00597      */
00598     void box_size( int& i, int& j, int& k ) const;
00599 
00600     //! Get the element at the specified coordinates
00601     /**
00602      * \param ijk Parametric coordinates being evaluated
00603      */
00604     EntityHandle get_element( const HomCoord& ijk ) const;
00605 
00606     //! Get the element at the specified coordinates
00607     /**
00608      * \param i Parametric coordinates being evaluated
00609      * \param j Parametric coordinates being evaluated
00610      * \param k Parametric coordinates being evaluated
00611      */
00612     EntityHandle get_element( int i, int j = 0, int k = 0 ) const;
00613 
00614     //! Get the vertex at the specified coordinates
00615     /**
00616      * \param ijk Parametric coordinates being evaluated
00617      */
00618     EntityHandle get_vertex( const HomCoord& ijk ) const;
00619 
00620     //! Get the vertex at the specified coordinates
00621     /**
00622      * \param i Parametric coordinates being evaluated
00623      * \param j Parametric coordinates being evaluated
00624      * \param k Parametric coordinates being evaluated
00625      */
00626     EntityHandle get_vertex( int i, int j = 0, int k = 0 ) const;
00627 
00628     //! Get parametric coordinates of the specified entity
00629     /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
00630      * in this ScdBox.
00631      * \param ent Entity being queried
00632      * \param i Parametric coordinates returned
00633      * \param j Parametric coordinates returned
00634      * \param k Parametric coordinates returned
00635      * \param dir Parametric coordinate direction returned (in case of getting adjacent
00636      *            edges (2d, 3d) or faces (3d); not modified otherwise
00637      */
00638     ErrorCode get_params( EntityHandle ent, int& i, int& j, int& k, int& dir ) const;
00639 
00640     //! Get parametric coordinates of the specified entity, intermediate entities not allowed (no
00641     //! dir parameter)
00642     /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
00643      * in this ScdBox, or MB_FAILURE if the entity is an intermediate-dimension entity.
00644      * \param ent Entity being queried
00645      * \param i Parametric coordinates returned
00646      * \param j Parametric coordinates returned
00647      * \param k Parametric coordinates returned
00648      */
00649     ErrorCode get_params( EntityHandle ent, int& i, int& j, int& k ) const;
00650 
00651     //! Get parametric coordinates of the specified entity
00652     /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
00653      * in this ScdBox.
00654      * \param ent Entity being queried
00655      * \param ijkd Parametric coordinates returned (including direction, in case of
00656      *            getting adjacent edges (2d, 3d) or faces (3d))
00657      */
00658     ErrorCode get_params( EntityHandle ent, HomCoord& ijkd ) const;
00659 
00660     /** \brief Get the adjacent edge or face at a parametric location
00661      * This function gets the left (i=0), front (j=0), or bottom (k=0) edge or face for a parametric
00662      * element. Left, front, or bottom is indicated by dir = 0, 1, or 2, resp.  All edges and faces
00663      * in a structured mesh block can be accessed using these parameters. \param dim Dimension of
00664      * adjacent entity being requested \param i Parametric coordinates of cell being evaluated
00665      * \param j Parametric coordinates of cell being evaluated
00666      * \param k Parametric coordinates of cell being evaluated
00667      * \param dir Direction (0, 1, or 2), for getting adjacent edges (2d, 3d) or faces (3d)
00668      * \param ent Entity returned from this function
00669      * \param create_if_missing If true, creates the entity if it doesn't already exist
00670      */
00671     ErrorCode get_adj_edge_or_face( int dim,
00672                                     int i,
00673                                     int j,
00674                                     int k,
00675                                     int dir,
00676                                     EntityHandle& ent,
00677                                     bool create_if_missing = true ) const;
00678 
00679     //! Return whether the box contains the parameters passed in
00680     /**
00681      * \param i Parametric coordinates being evaluated
00682      * \param j Parametric coordinates being evaluated
00683      * \param k Parametric coordinates being evaluated
00684      */
00685     bool contains( int i, int j, int k ) const;
00686 
00687     //! Return whether the box contains the parameters passed in
00688     /**
00689      * \param i Parametric coordinates being evaluated
00690      * \param j Parametric coordinates being evaluated
00691      * \param k Parametric coordinates being evaluated
00692      */
00693     bool contains( const HomCoord& ijk ) const;
00694 
00695     //! Set/Get the entity set representing the box
00696     void box_set( EntityHandle this_set );
00697     EntityHandle box_set();
00698 
00699     //! Get coordinate arrays for vertex coordinates for a structured block
00700     /** Returns error if there isn't a single vertex sequence associated with this structured block
00701      * \param xc X coordinate array pointer returned
00702      * \param yc Y coordinate array pointer returned
00703      * \param zc Z coordinate array pointer returned
00704      */
00705     ErrorCode get_coordinate_arrays( double*& xc, double*& yc, double*& zc );
00706 
00707     //! Get read-only coordinate arrays for vertex coordinates for a structured block
00708     /** Returns error if there isn't a single vertex sequence associated with this structured block
00709      * \param xc X coordinate array pointer returned
00710      * \param yc Y coordinate array pointer returned
00711      * \param zc Z coordinate array pointer returned
00712      */
00713     ErrorCode get_coordinate_arrays( const double*& xc, const double*& yc, const double*& zc ) const;
00714 
00715     //! Return whether box is locally periodic in i
00716     /** Return whether box is locally periodic in i
00717      * \return True if box is locally periodic in i direction
00718      */
00719     bool locally_periodic_i() const;
00720 
00721     //! Return whether box is locally periodic in j
00722     /** Return whether box is locally periodic in j
00723      * \return True if box is locally periodic in j direction
00724      */
00725     bool locally_periodic_j() const;
00726 
00727     //! Return whether box is locally periodic in k
00728     /** Return whether box is locally periodic in k
00729      * \return True if box is locally periodic in k direction
00730      */
00731     bool locally_periodic_k() const;
00732 
00733     //! Set local periodicity
00734     /**
00735      * \param lperiodic Vector of ijk periodicities to set this box to
00736      */
00737     void locally_periodic( bool lperiodic[3] );
00738 
00739     //! Get local periodicity
00740     /**
00741      * \return Vector of ijk periodicities for this box
00742      */
00743     const int* locally_periodic() const;
00744 
00745     //! Return parallel data
00746     /** Return parallel data, if there is any
00747      * \return par_data Parallel data set on this box
00748      */
00749     ScdParData& par_data()
00750     {
00751         return parData;
00752     }
00753 
00754     //! Return parallel data
00755     /** Return parallel data, if there is any
00756      * \return par_data Parallel data set on this box
00757      */
00758     const ScdParData& par_data() const
00759     {
00760         return parData;
00761     }
00762 
00763     //! set parallel data
00764     /** Set parallel data for this box
00765      * \param par_data Parallel data to be set on this box
00766      */
00767     void par_data( const ScdParData& par_datap )
00768     {
00769         parData = par_datap;
00770     }
00771 
00772   private:
00773     //! Constructor
00774     /** Create a structured box instance; this constructor is private because it should only be
00775      * called from ScdInterface, a friend class.  This constructor takes two sequences, one of which
00776      * can be NULL.  If both sequences come in non-NULL, the first should be a VertexSequence*
00777      * corresponding to a structured vertex sequence and the second should be a
00778      * StructuredElementSeq*.  If the 2nd is NULL, the first can be either of those types.  The
00779      * other members of this class are taken from the sequences (e.g. parametric space) or the box
00780      * set argument.  Tags on the box set should be set from the caller. \param sc_impl A
00781      * ScdInterface instance \param box_set Entity set representing this rectangle \param seq1 An
00782      * EntitySequence (see ScdBox description) \param seq2 An EntitySequence (see ScdBox
00783      * description), or NULL
00784      */
00785     ScdBox( ScdInterface* sc_impl, EntityHandle box_set, EntitySequence* seq1, EntitySequence* seq2 = NULL );
00786 
00787     //! function to get vertex handle directly from sequence
00788     /** \param i Parameter being queried
00789      * \param j Parameter being queried
00790      * \param k Parameter being queried
00791      */
00792     EntityHandle get_vertex_from_seq( int i, int j, int k ) const;
00793 
00794     //! set the vertex sequence
00795     ErrorCode vert_dat( ScdVertexData* vert_dat );
00796 
00797     //! get the vertex sequence
00798     ScdVertexData* vert_dat() const;
00799 
00800     //! set the element sequence
00801     ErrorCode elem_seq( EntitySequence* elem_seq );
00802 
00803     //! get the element sequence
00804     StructuredElementSeq* elem_seq() const;
00805 
00806     //! Set the starting vertex handle for this box
00807     void start_vertex( EntityHandle startv );
00808 
00809     //! Set the starting entity handle for this box
00810     void start_element( EntityHandle starte );
00811 
00812     //! interface instance
00813     ScdInterface* scImpl;
00814 
00815     //! entity set representing this box
00816     EntityHandle boxSet;
00817 
00818     //! vertex sequence this box represents, if there's only one, otherwise they're
00819     //! retrieved from the element sequence
00820     ScdVertexData* vertDat;
00821 
00822     //! element sequence this box represents
00823     StructuredElementSeq* elemSeq;
00824 
00825     //! starting vertex handle for this box
00826     EntityHandle startVertex;
00827 
00828     //! starting element handle for this box
00829     EntityHandle startElem;
00830 
00831     //! lower and upper corners
00832     int boxDims[6];
00833 
00834     //! is locally periodic in i or j or k
00835     int locallyPeriodic[3];
00836 
00837     //! parallel data associated with this box, if any
00838     ScdParData parData;
00839 
00840     //! parameter extents
00841     HomCoord boxSize;
00842 
00843     //! convenience parameters, (boxSize[1]-1)*(boxSize[0]-1) and boxSize[0]-1
00844     int boxSizeIJ;
00845     int boxSizeIJM1;
00846     int boxSizeIM1;
00847 };
00848 
00849 inline ErrorCode ScdInterface::compute_partition( int np,
00850                                                   int nr,
00851                                                   const ScdParData& par_data,
00852                                                   int* ldims,
00853                                                   int* lperiodic,
00854                                                   int* pdims )
00855 {
00856     ErrorCode rval = MB_SUCCESS;
00857     switch( par_data.partMethod )
00858     {
00859         case ScdParData::ALLJORKORI:
00860         case -1:
00861             rval = compute_partition_alljorkori( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
00862             break;
00863         case ScdParData::ALLJKBAL:
00864             rval = compute_partition_alljkbal( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
00865             break;
00866         case ScdParData::SQIJ:
00867             rval = compute_partition_sqij( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
00868             break;
00869         case ScdParData::SQJK:
00870             rval = compute_partition_sqjk( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
00871             break;
00872         case ScdParData::SQIJK:
00873             rval = compute_partition_sqijk( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
00874             break;
00875         default:
00876             rval = MB_FAILURE;
00877             break;
00878     }
00879 
00880     return rval;
00881 }
00882 
00883 inline ErrorCode ScdInterface::compute_partition_alljorkori( int np,
00884                                                              int nr,
00885                                                              const int gijk[6],
00886                                                              const int* const gperiodic,
00887                                                              int* ldims,
00888                                                              int* lperiodic,
00889                                                              int* pijk )
00890 {
00891     // partition *the elements* over the parametric space; 1d partition for now, in the j, k, or i
00892     // parameters
00893     int tmp_lp[3], tmp_pijk[3];
00894     if( !lperiodic ) lperiodic = tmp_lp;
00895     if( !pijk ) pijk = tmp_pijk;
00896 
00897     for( int i = 0; i < 3; i++ )
00898         lperiodic[i] = gperiodic[i];
00899 
00900     if( np == 1 )
00901     {
00902         if( ldims )
00903         {
00904             ldims[0] = gijk[0];
00905             ldims[3] = gijk[3];
00906             ldims[1] = gijk[1];
00907             ldims[4] = gijk[4];
00908             ldims[2] = gijk[2];
00909             ldims[5] = gijk[5];
00910         }
00911         pijk[0] = pijk[1] = pijk[2] = 1;
00912     }
00913     else
00914     {
00915         if( gijk[4] - gijk[1] > np )
00916         {
00917             // partition j over procs
00918             int dj    = ( gijk[4] - gijk[1] ) / np;
00919             int extra = ( gijk[4] - gijk[1] ) % np;
00920             ldims[1]  = gijk[1] + nr * dj + std::min( nr, extra );
00921             ldims[4]  = ldims[1] + dj + ( nr < extra ? 1 : 0 );
00922 
00923             if( gperiodic[1] && np > 1 )
00924             {
00925                 lperiodic[1] = 0;
00926                 ldims[4]++;
00927             }
00928 
00929             ldims[2] = gijk[2];
00930             ldims[5] = gijk[5];
00931             ldims[0] = gijk[0];
00932             ldims[3] = gijk[3];
00933             pijk[0] = pijk[2] = 1;
00934             pijk[1]           = np;
00935         }
00936         else if( gijk[5] - gijk[2] > np )
00937         {
00938             // partition k over procs
00939             int dk    = ( gijk[5] - gijk[2] ) / np;
00940             int extra = ( gijk[5] - gijk[2] ) % np;
00941             ldims[2]  = gijk[2] + nr * dk + std::min( nr, extra );
00942             ldims[5]  = ldims[2] + dk + ( nr < extra ? 1 : 0 );
00943 
00944             ldims[1] = gijk[1];
00945             ldims[4] = gijk[4];
00946             ldims[0] = gijk[0];
00947             ldims[3] = gijk[3];
00948             pijk[0] = pijk[1] = 1;
00949             pijk[2]           = np;
00950         }
00951         else if( gijk[3] - gijk[0] > np )
00952         {
00953             // partition i over procs
00954             int di    = ( gijk[3] - gijk[0] ) / np;
00955             int extra = ( gijk[3] - gijk[0] ) % np;
00956             ldims[0]  = gijk[0] + nr * di + std::min( nr, extra );
00957             ldims[3]  = ldims[0] + di + ( nr < extra ? 1 : 0 );
00958 
00959             if( gperiodic[0] && np > 1 )
00960             {
00961                 lperiodic[0] = 0;
00962                 ldims[3]++;
00963             }
00964 
00965             ldims[2] = gijk[2];
00966             ldims[5] = gijk[5];
00967             ldims[1] = gijk[1];
00968             ldims[4] = gijk[4];
00969 
00970             pijk[1] = pijk[2] = 1;
00971             pijk[0]           = np;
00972         }
00973         else
00974         {
00975             // Couldn't find a suitable partition...
00976             return MB_FAILURE;
00977         }
00978     }
00979 
00980     return MB_SUCCESS;
00981 }
00982 
00983 inline ErrorCode ScdInterface::compute_partition_alljkbal( int np,
00984                                                            int nr,
00985                                                            const int gijk[6],
00986                                                            const int* const gperiodic,
00987                                                            int* ldims,
00988                                                            int* lperiodic,
00989                                                            int* pijk )
00990 {
00991     int tmp_lp[3], tmp_pijk[3];
00992     if( !lperiodic ) lperiodic = tmp_lp;
00993     if( !pijk ) pijk = tmp_pijk;
00994 
00995     for( int i = 0; i < 3; i++ )
00996         lperiodic[i] = gperiodic[i];
00997 
00998     if( np == 1 )
00999     {
01000         if( ldims )
01001         {
01002             ldims[0] = gijk[0];
01003             ldims[3] = gijk[3];
01004             ldims[1] = gijk[1];
01005             ldims[4] = gijk[4];
01006             ldims[2] = gijk[2];
01007             ldims[5] = gijk[5];
01008         }
01009         pijk[0] = pijk[1] = pijk[2] = 1;
01010     }
01011     else
01012     {
01013         // improved, possibly 2-d partition
01014         std::vector< double > kfactors;
01015         kfactors.push_back( 1 );
01016         int K = gijk[5] - gijk[2];
01017         for( int i = 2; i < K; i++ )
01018             if( !( K % i ) && !( np % i ) ) kfactors.push_back( i );
01019         kfactors.push_back( K );
01020 
01021         // compute the ideal nj and nk
01022         int J          = gijk[4] - gijk[1];
01023         double njideal = sqrt( ( (double)( np * J ) ) / ( (double)K ) );
01024         double nkideal = ( njideal * K ) / J;
01025 
01026         int nk, nj;
01027         if( nkideal < 1.0 )
01028         {
01029             nk = 1;
01030             nj = np;
01031         }
01032         else
01033         {
01034             std::vector< double >::iterator vit = std::lower_bound( kfactors.begin(), kfactors.end(), nkideal );
01035             if( vit == kfactors.begin() )
01036                 nk = 1;
01037             else
01038                 nk = (int)*( --vit );
01039             nj = np / nk;
01040         }
01041 
01042         int dk = K / nk;
01043         int dj = J / nj;
01044 
01045         ldims[2] = gijk[2] + ( nr % nk ) * dk;
01046         ldims[5] = ldims[2] + dk;
01047 
01048         int extra = J % nj;
01049 
01050         ldims[1] = gijk[1] + ( nr / nk ) * dj + std::min( nr / nk, extra );
01051         ldims[4] = ldims[1] + dj + ( nr / nk < extra ? 1 : 0 );
01052 
01053         ldims[0] = gijk[0];
01054         ldims[3] = gijk[3];
01055 
01056         if( gperiodic[1] && np > 1 )
01057         {
01058             lperiodic[1] = 0;
01059             if( nr / nk == nj - 1 )
01060             {
01061                 ldims[1]++;
01062             }
01063         }
01064 
01065         pijk[0] = 1;
01066         pijk[1] = nj;
01067         pijk[2] = nk;
01068     }
01069 
01070     return MB_SUCCESS;
01071 }
01072 
01073 inline ErrorCode ScdInterface::compute_partition_sqij( int np,
01074                                                        int nr,
01075                                                        const int gijk[6],
01076                                                        const int* const gperiodic,
01077                                                        int* ldims,
01078                                                        int* lperiodic,
01079                                                        int* pijk )
01080 {
01081     int tmp_lp[3], tmp_pijk[3];
01082     if( !lperiodic ) lperiodic = tmp_lp;
01083     if( !pijk ) pijk = tmp_pijk;
01084 
01085     // square IxJ partition
01086 
01087     for( int i = 0; i < 3; i++ )
01088         lperiodic[i] = gperiodic[i];
01089 
01090     if( np == 1 )
01091     {
01092         if( ldims )
01093         {
01094             ldims[0] = gijk[0];
01095             ldims[3] = gijk[3];
01096             ldims[1] = gijk[1];
01097             ldims[4] = gijk[4];
01098             ldims[2] = gijk[2];
01099             ldims[5] = gijk[5];
01100         }
01101         pijk[0] = pijk[1] = pijk[2] = 1;
01102     }
01103     else
01104     {
01105         std::vector< double > pfactors, ppfactors;
01106         for( int i = 2; i <= np / 2; i++ )
01107             if( !( np % i ) )
01108             {
01109                 pfactors.push_back( i );
01110                 ppfactors.push_back( ( (double)( i * i ) ) / np );
01111             }
01112         pfactors.push_back( np );
01113         ppfactors.push_back( (double)np );
01114 
01115         // ideally, Px/Py = I/J
01116         double ijratio = ( (double)( gijk[3] - gijk[0] ) ) / ( (double)( gijk[4] - gijk[1] ) );
01117 
01118         unsigned int ind                        = 0;
01119         std::vector< double >::iterator optimal = std::lower_bound( ppfactors.begin(), ppfactors.end(), ijratio );
01120         if( optimal == ppfactors.end() )
01121         {
01122             ind = ppfactors.size() - 1;
01123         }
01124         else
01125         {
01126             ind = optimal - ppfactors.begin();
01127             if( ind && fabs( ppfactors[ind - 1] - ijratio ) < fabs( ppfactors[ind] - ijratio ) ) ind--;
01128         }
01129 
01130         // VARIABLES DESCRIBING THE MESH:
01131         // pi, pj = # procs in i and j directions
01132         // nri, nrj = my proc's position in i, j directions
01133         // I, J = # edges/elements in i, j directions
01134         // iextra, jextra = # procs having extra edge in i/j direction
01135         // top_i, top_j = if true, I'm the last proc in the i/j direction
01136         // i, j = # edges locally in i/j direction, *not* including one for iextra/jextra
01137         int pi = pfactors[ind];
01138         int pj = np / pi;
01139 
01140         int I = ( gijk[3] - gijk[0] ), J = ( gijk[4] - gijk[1] );
01141         int iextra = I % pi, jextra = J % pj, i = I / pi, j = J / pj;
01142         int nri = nr % pi, nrj = nr / pi;
01143 
01144         if( ldims )
01145         {
01146             ldims[0] = gijk[0] + i * nri + std::min( iextra, nri );
01147             ldims[3] = ldims[0] + i + ( nri < iextra ? 1 : 0 );
01148             ldims[1] = gijk[1] + j * nrj + std::min( jextra, nrj );
01149             ldims[4] = ldims[1] + j + ( nrj < jextra ? 1 : 0 );
01150 
01151             ldims[2] = gijk[2];
01152             ldims[5] = gijk[5];
01153 
01154             if( gperiodic[0] && pi > 1 )
01155             {
01156                 lperiodic[0] = 0;
01157                 if( nri == pi - 1 ) ldims[3]++;
01158             }
01159             if( gperiodic[1] && pj > 1 )
01160             {
01161                 lperiodic[1] = 0;
01162                 if( nrj == pj - 1 ) ldims[4]++;
01163             }
01164         }
01165 
01166         pijk[0] = pi;
01167         pijk[1] = pj;
01168         pijk[2] = 1;
01169     }
01170 
01171     return MB_SUCCESS;
01172 }
01173 
01174 inline ErrorCode ScdInterface::compute_partition_sqjk( int np,
01175                                                        int nr,
01176                                                        const int gijk[6],
01177                                                        const int* const gperiodic,
01178                                                        int* ldims,
01179                                                        int* lperiodic,
01180                                                        int* pijk )
01181 {
01182     int tmp_lp[3], tmp_pijk[3];
01183     if( !lperiodic ) lperiodic = tmp_lp;
01184     if( !pijk ) pijk = tmp_pijk;
01185 
01186     // square JxK partition
01187     for( int i = 0; i < 3; i++ )
01188         lperiodic[i] = gperiodic[i];
01189 
01190     if( np == 1 )
01191     {
01192         if( ldims )
01193         {
01194             ldims[0] = gijk[0];
01195             ldims[3] = gijk[3];
01196             ldims[1] = gijk[1];
01197             ldims[4] = gijk[4];
01198             ldims[2] = gijk[2];
01199             ldims[5] = gijk[5];
01200         }
01201         pijk[0] = pijk[1] = pijk[2] = 1;
01202     }
01203     else
01204     {
01205         std::vector< double > pfactors, ppfactors;
01206         for( int p = 2; p <= np; p++ )
01207             if( !( np % p ) )
01208             {
01209                 pfactors.push_back( p );
01210                 ppfactors.push_back( ( (double)( p * p ) ) / np );
01211             }
01212 
01213         // ideally, Pj/Pk = J/K
01214         int pj, pk;
01215         if( gijk[5] == gijk[2] )
01216         {
01217             pk = 1;
01218             pj = np;
01219         }
01220         else
01221         {
01222             double jkratio = ( (double)( gijk[4] - gijk[1] ) ) / ( (double)( gijk[5] - gijk[2] ) );
01223 
01224             std::vector< double >::iterator vit = std::lower_bound( ppfactors.begin(), ppfactors.end(), jkratio );
01225             if( vit == ppfactors.end() )
01226                 --vit;
01227             else if( vit != ppfactors.begin() && fabs( *( vit - 1 ) - jkratio ) < fabs( ( *vit ) - jkratio ) )
01228                 --vit;
01229             int ind = vit - ppfactors.begin();
01230 
01231             pj = 1;
01232             if( ind >= 0 && !pfactors.empty() ) pfactors[ind];
01233             pk = np / pj;
01234         }
01235 
01236         int K = ( gijk[5] - gijk[2] ), J = ( gijk[4] - gijk[1] );
01237         int jextra = J % pj, kextra = K % pk, j = J / pj, k = K / pk;
01238         int nrj = nr % pj, nrk = nr / pj;
01239         ldims[1] = gijk[1] + j * nrj + std::min( jextra, nrj );
01240         ldims[4] = ldims[1] + j + ( nrj < jextra ? 1 : 0 );
01241         ldims[2] = gijk[2] + k * nrk + std::min( kextra, nrk );
01242         ldims[5] = ldims[2] + k + ( nrk < kextra ? 1 : 0 );
01243 
01244         ldims[0] = gijk[0];
01245         ldims[3] = gijk[3];
01246 
01247         if( gperiodic[1] && pj > 1 )
01248         {
01249             lperiodic[1] = 0;
01250             if( nrj == pj - 1 ) ldims[4]++;
01251         }
01252 
01253         pijk[0] = 1;
01254         pijk[1] = pj;
01255         pijk[2] = pk;
01256     }
01257 
01258     return MB_SUCCESS;
01259 }
01260 
01261 inline ErrorCode ScdInterface::compute_partition_sqijk( int np,
01262                                                         int nr,
01263                                                         const int* const gijk,
01264                                                         const int* const gperiodic,
01265                                                         int* ldims,
01266                                                         int* lperiodic,
01267                                                         int* pijk )
01268 {
01269     if( gperiodic[0] || gperiodic[1] || gperiodic[2] ) return MB_FAILURE;
01270 
01271     int tmp_lp[3], tmp_pijk[3];
01272     if( !lperiodic ) lperiodic = tmp_lp;
01273     if( !pijk ) pijk = tmp_pijk;
01274 
01275     // square IxJxK partition
01276 
01277     for( int i = 0; i < 3; i++ )
01278         lperiodic[i] = gperiodic[i];
01279 
01280     if( np == 1 )
01281     {
01282         if( ldims )
01283             for( int i = 0; i < 6; i++ )
01284                 ldims[i] = gijk[i];
01285         pijk[0] = pijk[1] = pijk[2] = 1;
01286         return MB_SUCCESS;
01287     }
01288 
01289     std::vector< int > pfactors;
01290     pfactors.push_back( 1 );
01291     for( int i = 2; i <= np / 2; i++ )
01292         if( !( np % i ) ) pfactors.push_back( i );
01293     pfactors.push_back( np );
01294 
01295     // test for IJ, JK, IK
01296     int IJK[3], dIJK[3];
01297     for( int i = 0; i < 3; i++ )
01298         IJK[i] = std::max( gijk[3 + i] - gijk[i], 1 );
01299     // order IJK from lo to hi
01300     int lo = 0, hi = 0;
01301     for( int i = 1; i < 3; i++ )
01302     {
01303         if( IJK[i] < IJK[lo] ) lo = i;
01304         if( IJK[i] > IJK[hi] ) hi = i;
01305     }
01306     if( lo == hi ) hi = ( lo + 1 ) % 3;
01307     int mid = 3 - lo - hi;
01308     // search for perfect subdivision of np that balances #cells
01309     int perfa_best = -1, perfb_best = -1;
01310     double ratio = 0.0;
01311     for( int po = 0; po < (int)pfactors.size(); po++ )
01312     {
01313         for( int pi = po; pi < (int)pfactors.size() && np / ( pfactors[po] * pfactors[pi] ) >= pfactors[pi]; pi++ )
01314         {
01315             int p3 =
01316                 std::find( pfactors.begin(), pfactors.end(), np / ( pfactors[po] * pfactors[pi] ) ) - pfactors.begin();
01317             if( p3 == (int)pfactors.size() || pfactors[po] * pfactors[pi] * pfactors[p3] != np )
01318                 continue;  // po*pi should exactly factor np
01319             assert( po <= pi && pi <= p3 );
01320             // by definition, po <= pi <= p3
01321             double minl =
01322                        std::min( std::min( IJK[lo] / pfactors[po], IJK[mid] / pfactors[pi] ), IJK[hi] / pfactors[p3] ),
01323                    maxl =
01324                        std::max( std::max( IJK[lo] / pfactors[po], IJK[mid] / pfactors[pi] ), IJK[hi] / pfactors[p3] );
01325             if( minl / maxl > ratio )
01326             {
01327                 ratio      = minl / maxl;
01328                 perfa_best = po;
01329                 perfb_best = pi;
01330             }
01331         }
01332     }
01333     if( perfa_best == -1 || perfb_best == -1 ) return MB_FAILURE;
01334 
01335     // VARIABLES DESCRIBING THE MESH:
01336     // pijk[i] = # procs in direction i
01337     // numr[i] = my proc's position in direction i
01338     // dIJK[i] = # edges/elements in direction i
01339     // extra[i]= # procs having extra edge in direction i
01340     // top[i] = if true, I'm the last proc in direction i
01341 
01342     pijk[lo]     = pfactors[perfa_best];
01343     pijk[mid]    = pfactors[perfb_best];
01344     pijk[hi]     = ( np / ( pfactors[perfa_best] * pfactors[perfb_best] ) );
01345     int extra[3] = { 0, 0, 0 }, numr[3];
01346     for( int i = 0; i < 3; i++ )
01347     {
01348         dIJK[i]  = IJK[i] / pijk[i];
01349         extra[i] = IJK[i] % pijk[i];
01350     }
01351     numr[2] = nr / ( pijk[0] * pijk[1] );
01352     int rem = nr % ( pijk[0] * pijk[1] );
01353     numr[1] = rem / pijk[0];
01354     numr[0] = rem % pijk[0];
01355     for( int i = 0; i < 3; i++ )
01356     {
01357         extra[i]     = IJK[i] % dIJK[i];
01358         ldims[i]     = gijk[i] + numr[i] * dIJK[i] + std::min( extra[i], numr[i] );
01359         ldims[3 + i] = ldims[i] + dIJK[i] + ( numr[i] < extra[i] ? 1 : 0 );
01360     }
01361 
01362     return MB_SUCCESS;
01363 }
01364 
01365 inline int ScdInterface::gtol( const int* gijk, int i, int j, int k )
01366 {
01367     return ( ( k - gijk[2] ) * ( gijk[3] - gijk[0] + 1 ) * ( gijk[4] - gijk[1] + 1 ) +
01368              ( j - gijk[1] ) * ( gijk[3] - gijk[0] + 1 ) + i - gijk[0] );
01369 }
01370 
01371 inline ErrorCode ScdInterface::get_indices( const int* const ldims,
01372                                             const int* const rdims,
01373                                             const int* const across_bdy,
01374                                             int* face_dims,
01375                                             std::vector< int >& shared_indices )
01376 {
01377     // check for going across periodic bdy and face_dims not in my ldims (I'll always be on top in
01378     // that case)...
01379     if( across_bdy[0] > 0 && face_dims[0] != ldims[3] )
01380         face_dims[0] = face_dims[3] = ldims[3];
01381     else if( across_bdy[0] < 0 && face_dims[0] != ldims[0] )
01382         face_dims[0] = face_dims[3] = ldims[0];
01383     if( across_bdy[1] > 0 && face_dims[1] != ldims[4] )
01384         face_dims[1] = face_dims[4] = ldims[4];
01385     else if( across_bdy[1] < 0 && face_dims[1] != ldims[1] )
01386         face_dims[0] = face_dims[3] = ldims[1];
01387 
01388     for( int k = face_dims[2]; k <= face_dims[5]; k++ )
01389         for( int j = face_dims[1]; j <= face_dims[4]; j++ )
01390             for( int i = face_dims[0]; i <= face_dims[3]; i++ )
01391                 shared_indices.push_back( gtol( ldims, i, j, k ) );
01392 
01393     if( across_bdy[0] > 0 && face_dims[0] != rdims[0] )
01394         face_dims[0] = face_dims[3] = rdims[0];
01395     else if( across_bdy[0] < 0 && face_dims[0] != rdims[3] )
01396         face_dims[0] = face_dims[3] = rdims[3];
01397     if( across_bdy[1] > 0 && face_dims[1] != rdims[1] )
01398         face_dims[1] = face_dims[4] = rdims[1];
01399     else if( across_bdy[1] < 0 && face_dims[1] != rdims[4] )
01400         face_dims[0] = face_dims[3] = rdims[4];
01401 
01402     for( int k = face_dims[2]; k <= face_dims[5]; k++ )
01403         for( int j = face_dims[1]; j <= face_dims[4]; j++ )
01404             for( int i = face_dims[0]; i <= face_dims[3]; i++ )
01405                 shared_indices.push_back( gtol( rdims, i, j, k ) );
01406 
01407     return MB_SUCCESS;
01408 }
01409 
01410 inline ErrorCode ScdInterface::get_neighbor( int np,
01411                                              int pfrom,
01412                                              const ScdParData& spd,
01413                                              const int* const dijk,
01414                                              int& pto,
01415                                              int* rdims,
01416                                              int* facedims,
01417                                              int* across_bdy )
01418 {
01419     if( !dijk[0] && !dijk[1] && !dijk[2] )
01420     {
01421         // not going anywhere, return
01422         pto = -1;
01423         return MB_SUCCESS;
01424     }
01425 
01426     switch( spd.partMethod )
01427     {
01428         case ScdParData::ALLJORKORI:
01429         case -1:
01430             return get_neighbor_alljorkori( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims,
01431                                             across_bdy );
01432         case ScdParData::ALLJKBAL:
01433             return get_neighbor_alljkbal( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
01434         case ScdParData::SQIJ:
01435             return get_neighbor_sqij( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
01436         case ScdParData::SQJK:
01437             return get_neighbor_sqjk( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
01438         case ScdParData::SQIJK:
01439             return get_neighbor_sqijk( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
01440         default:
01441             break;
01442     }
01443 
01444     return MB_FAILURE;
01445 }
01446 
01447 inline ErrorCode ScdInterface::tag_shared_vertices( ParallelComm* pcomm, EntityHandle seth )
01448 {
01449     ScdBox* box = get_scd_box( seth );
01450     if( !box )
01451     {
01452         // look for contained boxes
01453         Range tmp_range;
01454         ErrorCode rval = mbImpl->get_entities_by_type( seth, MBENTITYSET, tmp_range );
01455         if( MB_SUCCESS != rval ) return rval;
01456         for( Range::iterator rit = tmp_range.begin(); rit != tmp_range.end(); ++rit )
01457         {
01458             box = get_scd_box( *rit );
01459             if( box ) break;
01460         }
01461     }
01462 
01463     if( !box ) return MB_FAILURE;
01464 
01465     return tag_shared_vertices( pcomm, box );
01466 }
01467 
01468 inline ScdInterface* ScdBox::sc_impl() const
01469 {
01470     return scImpl;
01471 }
01472 
01473 inline EntityHandle ScdBox::start_vertex() const
01474 {
01475     return startVertex;
01476 }
01477 
01478 inline void ScdBox::start_vertex( EntityHandle startv )
01479 {
01480     startVertex = startv;
01481 }
01482 
01483 inline EntityHandle ScdBox::start_element() const
01484 {
01485     return startElem;
01486 }
01487 
01488 inline void ScdBox::start_element( EntityHandle starte )
01489 {
01490     startElem = starte;
01491 }
01492 
01493 inline int ScdBox::num_elements() const
01494 {
01495     if( !startElem ) return 0;  // not initialized yet
01496 
01497     /* for a structured mesh, total number of elements is obtained by multiplying
01498         number of elements in each direction
01499       number of elements in each direction is given by number of vertices in that direction minus 1
01500       if periodic in that direction, the last vertex is the same as first one, count one more
01501       element
01502       */
01503     int num_e_i = ( -1 == boxSize[0] || 1 == boxSize[0] ) ? 1 : boxSize[0] - 1;
01504     if( locallyPeriodic[0] ) ++num_e_i;
01505 
01506     int num_e_j = ( -1 == boxSize[1] || 1 == boxSize[1] ) ? 1 : boxSize[1] - 1;
01507     if( locallyPeriodic[1] ) ++num_e_j;
01508 
01509     int num_e_k = ( -1 == boxSize[2] || 1 == boxSize[2] ) ? 1 : boxSize[2] - 1;
01510     if( locallyPeriodic[2] ) ++num_e_k;
01511 
01512     return num_e_i * num_e_j * num_e_k;
01513 }
01514 
01515 inline int ScdBox::num_vertices() const
01516 {
01517     return boxSize[0] * ( !boxSize[1] ? 1 : boxSize[1] ) * ( !boxSize[2] ? 1 : boxSize[2] );
01518 }
01519 
01520 inline const int* ScdBox::box_dims() const
01521 {
01522     return boxDims;
01523 }
01524 
01525 inline HomCoord ScdBox::box_min() const
01526 {
01527     return HomCoord( boxDims, 3 );
01528 }
01529 
01530 inline HomCoord ScdBox::box_max() const
01531 {
01532     return HomCoord( boxDims + 3, 3 );
01533 }
01534 
01535 inline HomCoord ScdBox::box_size() const
01536 {
01537     return boxSize;
01538 }
01539 
01540 inline void ScdBox::box_size( int* ijk ) const
01541 {
01542     ijk[0] = boxSize[0];
01543     ijk[1] = boxSize[1];
01544     ijk[2] = boxSize[2];
01545 }
01546 
01547 inline void ScdBox::box_size( int& i, int& j, int& k ) const
01548 {
01549     i = boxSize[0];
01550     j = boxSize[1];
01551     k = boxSize[2];
01552 }
01553 
01554 inline EntityHandle ScdBox::get_element( int i, int j, int k ) const
01555 {
01556     return ( !startElem
01557                  ? 0
01558                  : startElem + ( k - boxDims[2] ) * boxSizeIJM1 + ( j - boxDims[1] ) * boxSizeIM1 + i - boxDims[0] );
01559 }
01560 
01561 inline EntityHandle ScdBox::get_element( const HomCoord& ijk ) const
01562 {
01563     return get_element( ijk[0], ijk[1], ijk[2] );
01564 }
01565 
01566 inline EntityHandle ScdBox::get_vertex( int i, int j, int k ) const
01567 {
01568     return ( vertDat
01569                  ? startVertex + ( boxDims[2] == -1 && boxDims[5] == -1 ? 0 : ( k - boxDims[2] ) ) * boxSizeIJ +
01570                        ( boxDims[1] == -1 && boxDims[4] == -1 ? 0 : ( j - boxDims[1] ) ) * boxSize[0] + i - boxDims[0]
01571                  : get_vertex_from_seq( i, j, k ) );
01572 }
01573 
01574 inline EntityHandle ScdBox::get_vertex( const HomCoord& ijk ) const
01575 {
01576     return get_vertex( ijk[0], ijk[1], ijk[2] );
01577 }
01578 
01579 inline bool ScdBox::contains( const HomCoord& ijk ) const
01580 {
01581     return ( ijk >= HomCoord( boxDims, 3 ) && ijk <= HomCoord( boxDims + 3, 3 ) );
01582 }
01583 
01584 inline bool ScdBox::contains( int i, int j, int k ) const
01585 {
01586     return contains( HomCoord( i, j, k ) );
01587 }
01588 
01589 inline void ScdBox::box_set( EntityHandle this_set )
01590 {
01591     boxSet = this_set;
01592 }
01593 
01594 inline EntityHandle ScdBox::box_set()
01595 {
01596     return boxSet;
01597 }
01598 
01599 inline ScdVertexData* ScdBox::vert_dat() const
01600 {
01601     return vertDat;
01602 }
01603 
01604 inline StructuredElementSeq* ScdBox::elem_seq() const
01605 {
01606     return elemSeq;
01607 }
01608 
01609 inline ErrorCode ScdBox::get_params( EntityHandle ent, int& i, int& j, int& k, int& dir ) const
01610 {
01611     HomCoord hc;
01612     ErrorCode rval = get_params( ent, hc );
01613     if( MB_SUCCESS == rval )
01614     {
01615         i   = hc[0];
01616         j   = hc[1];
01617         k   = hc[2];
01618         dir = hc[3];
01619     }
01620 
01621     return rval;
01622 }
01623 
01624 inline ErrorCode ScdBox::get_params( EntityHandle ent, int& i, int& j, int& k ) const
01625 {
01626     HomCoord hc;
01627     ErrorCode rval = get_params( ent, hc );
01628     if( MB_SUCCESS == rval )
01629     {
01630         i = hc[0];
01631         j = hc[1];
01632         k = hc[2];
01633     }
01634 
01635     return rval;
01636 }
01637 
01638 inline bool ScdBox::locally_periodic_i() const
01639 {
01640     return locallyPeriodic[0];
01641 }
01642 
01643 inline bool ScdBox::locally_periodic_j() const
01644 {
01645     return locallyPeriodic[1];
01646 }
01647 
01648 inline bool ScdBox::locally_periodic_k() const
01649 {
01650     return locallyPeriodic[2];
01651 }
01652 
01653 inline void ScdBox::locally_periodic( bool lperiodic[3] )
01654 {
01655     for( int i = 0; i < 3; i++ )
01656         locallyPeriodic[i] = lperiodic[i];
01657 }
01658 
01659 inline const int* ScdBox::locally_periodic() const
01660 {
01661     return locallyPeriodic;
01662 }
01663 
01664 std::ostream& operator<<( std::ostream& str, const ScdParData& pd );
01665 
01666 }  // namespace moab
01667 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines