1 /** \file ScdInterface.hpp
2 */
3 #ifndef SCD_INTERFACE
4 #define SCD_INTERFACE
5
6 #include "moab/Interface.hpp"
7 #include "moab/HomXform.hpp"
8
9 #include <iostream>
10 #include <vector>
11 #include <cassert>
12
13 #include "moab/win32_config.h"
14
15 namespace moab
16 {
17
18 class StructuredElementSeq;
19 class EntitySequence;
20 class ScdVertexData;
21 class EntitySequence;
22 class ScdBox;
23 class ParallelComm;
24
25 /** \class ScdInterface ScdInterface.hpp "moab/ScdInterface.hpp"
26 * \brief A structured mesh interface for MOAB-based data
27 *
28 * Structured mesh in MOAB is created and accessed through the ScdInterface and ScdBox classes.
29 *
30 * \section Construction Construction and Representation
31 * Structured mesh can be constructed in one of two ways. First, a rectangular block of mesh,
32 * both vertices and edges/quads/hexes, can be created in one shot, using the construct_box method.
33 * In this case, there are single sequences of vertices/entities. The second method for creating
34 * structured mesh is to create the structured blocks of vertices and elements separately. In
35 * this case, different blocks of elements can share blocks of vertices, and each block of
36 * elements has its own independent parametric space. The algorithms behind this representation
37 * are described in T. Tautges, "MOAB-SD: Integrated structured and unstructured mesh
38 * representation", Eng. w Comp, vol 20 no. 3.
39 *
40 * Structured mesh is represented in MOAB down at the element sequence level, which is something
41 * applications don't see. In addition, when structured mesh is created, entity sets are also
42 * created and tagged with information about the parametric space. In particular, the BOX_DIMS
43 * tag is used to indicate the lower and upper corners in parametric space (this
44 * tag is integer size 6). Structured mesh blocks are also available through ScdBox class objects
45 * returned by ScdInterface. These class objects should be treated only as references to the
46 * structured mesh blocks; that is, the structured mesh referenced by these objects is not deleted
47 * when the ScdBox instance is destroyed. Functions for destroying the actual mesh are available
48 * on this class, though.
49 *
50 * Structured mesh blocks are returned in the form of ScdBox class objects. Each ScdBox instance
51 * represents a rectangular block of vertices and possibly elements (edges, quads, or hexes). The
52 * edge/quad/hex entity handles for a ScdBox are guaranteed to be contiguous, starting at a starting
53 * value which is also available through the ScdBox class. However, vertex handles may or may not
54 * be contiguous, depending on the construction method. The start vertex handle is also available
55 * from the ScdBox class.
56 *
57 * \section Parameters Parametric Space
58 *
59 * Each structured box has a parametric (ijk) space, which can be queried through the ScdBox
60 * interface. For non-periodic boxes, the edge/quad/hex parameter bounds are one less in each
61 * dimension than that of the vertices, otherwise they are the same as the vertex parameter bounds.
62 * In a parallel representation, boxes are locally non-periodic by default, but global ids are
63 * assigned such that the last set of vertices in a periodic direction match those of the first set
64 * of vertices in that direction.
65 *
66 * Entity handles are allocated with the i parameter varying fastest, then j, then k.
67 *
68 * \section Per Periodic Meshes
69 * Boxes can be periodic in i, or j, or both i and j. If only i or j is periodic, the corresponding
70 * mesh is a strip or an annular cylinder; if both i and j are periodic, the corresponding mesh is
71 * an annular torus. A box cannot be periodic in all three parameters. If i and/or j is periodic,
72 * and assuming IMIN/JMIN is zero, the parameter extents in the/each periodic direction (IMAX/JMAX)
73 * for vertices and edges/faces/hexes are the same, and the vertices on the "top" end in the
74 * periodic direction are at parameter value IMIN/JMIN.
75 *
76 * \section Par Parallel Representation
77 *
78 * For parallel structured meshes, each local mesh (the mesh on a given process) looks like a
79 * non-periodic structured mesh, and there are both local and global parameters of the structured
80 * mesh. If the mesh is periodic in a given direction, the last process in the periodic direction
81 * has local IMAX/JMAX that is one greater than the global IMAX/JMAX.
82 *
83 *
84 * In parallel, the periodicity described in the previous paragraph is "local periodicity"; there is
85 * also the notion of global periodicity. For serial meshes, those concepts are the same. In
86 * parallel, a mesh can be locally non-periodic but globally periodic in a given direction. In that
87 * case, the local mesh is still non-periodic, i.e. the parametric extents for edges is one fewer
88 * than that of vertices in that direction. However, vertices are given global ids such that they
89 * match those of the parametric minimum in that direction. Geometric positions of the vertices at
90 * the high end should still be greater than the ones just below.
91 *
92 * \section Adjs Adjacent Entities
93 * This interface supports parametric access to intermediate-dimension entities, e.g. adjacent faces
94 * and edges in a 3d mesh. In this case, a direction parameter is added, to identify the parametric
95 * direction of the entities being requested. For example, to retrieve the faces adjacent to a hex
96 * with parameters ijk, in the i parametric direction, you would use the parameters ijk0. These
97 * intermediate entities are not stored in a structured representation, but their parametric
98 * positions can be evaluated based on their adjacencies to higher-dimensional entities. Thanks to
99 * Milad Fatenejad for the thinking behind this.
100 *
101 * \section Evaluation Evaluation
102 * The ScdBox class provides functions for evaluating the mesh based on the ijk parameter space.
103 * These functions are inlined where possible, for efficiency.
104 */
105
106 //! struct for keeping parallel data in one place
107 class ScdParData
108 {
109 public:
110 ScdParData() : partMethod( NOPART ), pComm( NULL )
111 {
112 gDims[0] = gDims[1] = gDims[2] = gDims[3] = gDims[4] = gDims[5] = 0;
113 gPeriodic[0] = gPeriodic[1] = gPeriodic[2] = 0;
114 pDims[0] = pDims[1] = pDims[2] = 0;
115 }
116
117 //! Partition method enumeration; these strategies are described in comments for
118 //! compute_partition_alljorkori, compute_partition_alljkbal, compute_partition_sqij,
119 //! compute_partition_sqjk, and compute_partition_sqijk
120 enum PartitionMethod
121 {
122 ALLJORKORI = 0,
123 ALLJKBAL,
124 SQIJ,
125 SQJK,
126 SQIJK,
127 TRIVIAL,
128 RCBZOLTAN,
129 NOPART
130 };
131
132 //! Partition method names
133 static MOAB_EXPORT const char* PartitionMethodNames[NOPART + 1];
134
135 //! partition method used to partition global parametric space
136 int partMethod;
137
138 //! lower and upper corners of global box
139 int gDims[6];
140
141 //! is globally periodic in i or j or k
142 int gPeriodic[3];
143
144 //! number of procs in each direction
145 int pDims[3];
146
147 //! parallel communicator object for this par scd mesh
148 ParallelComm* pComm;
149 };
150
151 class MOAB_EXPORT ScdInterface
152 {
153 public:
154 friend class ScdBox;
155
156 //! Constructor
157 /** Constructor; if find_boxes is true, this will search for entity sets marked as
158 * structured blocks, based on the BOX_DIMS tag. Structured mesh blocks will be stored
159 * in this interface class for future retrieval. Structured mesh blocks created through
160 * this interface will also be stored here.
161 * \param impl MOAB instance
162 * \param find_boxes If true, search all the entity sets, caching the structured mesh blocks
163 */
164 ScdInterface( Interface* impl, bool find_boxes = false );
165
166 // Destructor
167 ~ScdInterface();
168
169 //! Return the MOAB Interface instance *
170 Interface* impl() const;
171
172 //! Construct new structured mesh box, including both vertices and elements
173 /** Parameter range
174 * for vertex box is [low-high], for elements is [low-high). Construct quads by passing
175 * in low[2] == high[2], and edges by passing in low[1] == high[1] and low[2] == high[2].
176 * The result is passed back in a ScdBox*, which is a *reference* to the box of structured mesh.
177 * That is, the actual mesh is retained in MOAB when the ScdBox is destroyed. To actually
178 * destroy the mesh, call the destroy_mesh function on the ScdBox object first, before
179 * destroying it. \param low Lower corner in parameter space \param high Higher corner in
180 * parameter space \param coords Coordinates of vertices, interleaved (xyzxyz...); if NULL,
181 * coords are set to parametric values \param num_coords Number of coordinate values \param
182 * new_box Reference to box of structured mesh \param lperiodic[3] If lperiodic[s] != 0,
183 * direction s is locally periodic \param par_data If non-NULL, this will get stored on the
184 * ScdBox once created, contains info about global parallel nature of ScdBox across procs \param
185 * assign_global_ids If true, assigns 1-based global ids to vertices using GLOBAL_ID_TAG_NAME
186 * \param resolve_shared_ents If != -1, resolves shared entities up to and including dimension
187 * equal to value
188 */
189 ErrorCode construct_box( HomCoord low,
190 HomCoord high,
191 const double* const coords,
192 unsigned int num_coords,
193 ScdBox*& new_box,
194 int* const lperiodic = NULL,
195 ScdParData* const par_data = NULL,
196 bool assign_global_ids = false,
197 int resolve_shared_ents = -1 );
198
199 //! Create a structured sequence of vertices, quads, or hexes
200 /** Starting handle for the sequence is available from the returned ScdBox.
201 * If creating a structured quad or hex box, subsequent calls must be made to ScdBox::add_vbox,
202 * until all the vertices have been filled in for the box.
203 * \param low Lower corner of structured box
204 * \param high Higher corner of structured box
205 * \param type EntityType, one of MBVERTEX, MBEDGE, MBQUAD, MBHEX
206 * \param starting_id Requested start id of entities
207 * \param new_box Reference to the newly created box of entities
208 * \param is_periodic[3] If is_periodic[s] is non-zero, mesh should be periodic in direction s
209 * (s=[0,1,2])
210 */
211 ErrorCode create_scd_sequence( const HomCoord& low,
212 const HomCoord& high,
213 EntityType type,
214 int starting_id,
215 ScdBox*& new_box,
216 int* is_periodic = NULL );
217
218 //! Return all the structured mesh blocks in this MOAB instance, as ScdBox objects
219 /** Return the structured blocks in this MOAB instance. If these were not searched for
220 * at instantiation time, then the search is done now.
221 * \param boxes Vector of ScdBox objects representing structured mesh blocks
222 */
223 ErrorCode find_boxes( std::vector< ScdBox* >& boxes );
224
225 //! Return all the structured mesh blocks in this MOAB instance, as entity set handles
226 /** Return the structured blocks in this MOAB instance. If these were not searched for
227 * at instantiation time, then the search is done now.
228 * \param boxes Range of entity set objects representing structured mesh blocks
229 */
230 ErrorCode find_boxes( Range& boxes );
231
232 //! Return all the structured mesh blocks known by ScdInterface (does not search)
233 /** Return the structured blocks in this ScdInterface instance. Does not search for new boxes,
234 * just returns the contents of the list.
235 * \param boxes Structured boxes
236 */
237 ErrorCode get_boxes( std::vector< ScdBox* >& boxes );
238
239 //! Return the tag marking the lower and upper corners of boxes
240 /**
241 * \param create_if_missing If the tag does not yet exist, create it
242 */
243 Tag box_dims_tag( bool create_if_missing = true );
244
245 //! Return the tag marking the global lower and upper corners of boxes
246 /**
247 * \param create_if_missing If the tag does not yet exist, create it
248 */
249 Tag global_box_dims_tag( bool create_if_missing = true );
250
251 //! Return the tag marking the partitioning method used to partition the box in parallel
252 /**
253 * \param create_if_missing If the tag does not yet exist, create it
254 */
255 Tag part_method_tag( bool create_if_missing = true );
256
257 //! Return the tag marking whether box is periodic in i and j
258 /**
259 * \param create_if_missing If the tag does not yet exist, create it
260 */
261 Tag box_periodic_tag( bool create_if_missing = true );
262
263 //! Return the tag marking the ScdBox for a set
264 /**
265 * \param create_if_missing If the tag does not yet exist, create it
266 */
267 Tag box_set_tag( bool create_if_missing = true );
268
269 //! Return the ScdBox corresponding to the entity set passed in
270 /** If the entity isn't a structured box set, NULL is returned.
271 * \param eh Entity whose box is being queried
272 */
273 ScdBox* get_scd_box( EntityHandle eh );
274
275 //! Compute a partition of structured parameter space
276 /** Compute a partition of structured parameter space, based on data in the ScdParData
277 * passed in. Results are passed back in arguments, which application can set back into
278 * par_data argument if they so desire.
279 * \param np Number of processors
280 * \param nr Rank of this processor
281 * \param par_data ScdParData object that contains input global parameter space, desired
282 * partitioning method, and information about global periodicity.
283 * \param ldims Local parameters for grid
284 * \param lperiodic Whether or not a given dimension is locally periodic
285 * \param pdims Number of procs in i, j, k directions
286 */
287 static ErrorCode compute_partition( int np,
288 int nr,
289 const ScdParData& par_data,
290 int* ldims,
291 int* lperiodic = NULL,
292 int* pdims = NULL );
293
294 //! Get information about the neighbor in the dijk[] direction, where dijk can be -1 or 1 for
295 //! all 3 params
296 /** Get information about the neighbor in the dijk[] direction, where dijk can be -1 or 1 for
297 * all 3 params \param np (in) Total # procs \param nr Processor from which neighbor is
298 * requested \param spd (in) ScdParData containing part method, gdims, gperiodic data \param
299 * dijk(*) (in) Direction being queried, = +/-1 or 0 \param pto (out) Processor holding the
300 * destination part \param rdims(6) (out) Parametric min/max of destination part \param
301 * facedims(6) (out) Parametric min/max of interface between pfrom and pto; if at the max in a
302 * periodic direction, set to global min of that direction \param across_bdy(3) (out) If
303 * across_bdy[i] is -1(1), interface with pto is across periodic lower(upper) bdy in parameter
304 * i, 0 otherwise
305 */
306 static ErrorCode get_neighbor( int np,
307 int nr,
308 const ScdParData& spd,
309 const int* const dijk,
310 int& pto,
311 int* rdims,
312 int* facedims,
313 int* across_bdy );
314
315 //! Tag vertices with sharing data for parallel representations
316 /** Given the ParallelComm object to use, tag the vertices shared with other processors
317 */
318 ErrorCode tag_shared_vertices( ParallelComm* pcomm, EntityHandle seth );
319
320 //! Tag vertices with sharing data for parallel representations
321 /** Given the ParallelComm object to use, tag the vertices shared with other processors
322 */
323 ErrorCode tag_shared_vertices( ParallelComm* pcomm, ScdBox* box );
324
325 protected:
326 //! Remove the box from the list on ScdInterface
327 ErrorCode remove_box( ScdBox* box );
328
329 //! Add the box to the list on ScdInterface
330 ErrorCode add_box( ScdBox* box );
331
332 private:
333 //! Create an entity set for a box, and tag with the parameters
334 /** \param low Lower corner parameters for this box
335 * \param high Upper corner parameters for this box
336 * \param scd_set Entity set created
337 * \param is_periodic[3] If is_periodic[s] is non-zero, mesh should be periodic in direction s
338 * (s=[0,1,2])
339 */
340 ErrorCode create_box_set( const HomCoord& low,
341 const HomCoord& high,
342 EntityHandle& scd_set,
343 int* is_periodic = NULL );
344
345 //! Compute a partition of structured parameter space
346 /** Partitions the structured parametric space by partitioning j, k, or i only.
347 * If j is greater than #procs, partition that, else k, else i.
348 * For description of arguments, see ScdInterface::compute_partition.
349 */
350 inline static ErrorCode compute_partition_alljorkori( int np,
351 int nr,
352 const int gijk[6],
353 const int* const gperiodic,
354 int* lijk,
355 int* lperiodic,
356 int* pijk );
357
358 //! Compute a partition of structured parameter space
359 /** Partitions the structured parametric space by partitioning j, and possibly k,
360 * seeking square regions of jk space
361 * For description of arguments, see ScdInterface::compute_partition.
362 */
363 inline static ErrorCode compute_partition_alljkbal( int np,
364 int nr,
365 const int gijk[6],
366 const int* const gperiodic,
367 int* lijk,
368 int* lperiodic,
369 int* pijk );
370
371 //! Compute a partition of structured parameter space
372 /** Partitions the structured parametric space by seeking square ij partitions
373 * For description of arguments, see ScdInterface::compute_partition.
374 */
375 inline static ErrorCode compute_partition_sqij( int np,
376 int nr,
377 const int gijk[6],
378 const int* const gperiodic,
379 int* lijk,
380 int* lperiodic,
381 int* pijk );
382
383 //! Compute a partition of structured parameter space
384 /** Partitions the structured parametric space by seeking square jk partitions
385 * For description of arguments, see ScdInterface::compute_partition.
386 */
387 inline static ErrorCode compute_partition_sqjk( int np,
388 int nr,
389 const int gijk[6],
390 const int* const gperiodic,
391 int* lijk,
392 int* lperiodic,
393 int* pijk );
394
395 //! Compute a partition of structured parameter space
396 /** Partitions the structured parametric space by seeking square ijk partitions
397 * For description of arguments, see ScdInterface::compute_partition.
398 */
399 inline static ErrorCode compute_partition_sqijk( int np,
400 int nr,
401 const int gijk[6],
402 const int* const gperiodic,
403 int* lijk,
404 int* lperiodic,
405 int* pijk );
406
407 //! Get vertices shared with other processors
408 /** Shared vertices returned as indices into each proc's handle space
409 * \param box Box used to get parametric space info
410 * \param procs Procs this proc shares vertices with
411 * \param offsets Offsets into indices list for each proc
412 * \param shared_indices local/remote indices of shared vertices
413 */
414 static ErrorCode get_shared_vertices( ParallelComm* pcomm,
415 ScdBox* box,
416 std::vector< int >& procs,
417 std::vector< int >& offsets,
418 std::vector< int >& shared_indices );
419
420 static ErrorCode get_indices( const int* const ldims,
421 const int* const rdims,
422 const int* const across_bdy,
423 int* face_dims,
424 std::vector< int >& shared_indices );
425
426 static ErrorCode get_neighbor_alljorkori( int np,
427 int pfrom,
428 const int* const gdims,
429 const int* const gperiodic,
430 const int* const dijk,
431 int& pto,
432 int* rdims,
433 int* facedims,
434 int* across_bdy );
435
436 static ErrorCode get_neighbor_alljkbal( int np,
437 int pfrom,
438 const int* const gdims,
439 const int* const gperiodic,
440 const int* const dijk,
441 int& pto,
442 int* rdims,
443 int* facedims,
444 int* across_bdy );
445
446 static ErrorCode get_neighbor_sqij( int np,
447 int pfrom,
448 const int* const gdims,
449 const int* const gperiodic,
450 const int* const dijk,
451 int& pto,
452 int* rdims,
453 int* facedims,
454 int* across_bdy );
455
456 static ErrorCode get_neighbor_sqjk( int np,
457 int pfrom,
458 const int* const gdims,
459 const int* const gperiodic,
460 const int* const dijk,
461 int& pto,
462 int* rdims,
463 int* facedims,
464 int* across_bdy );
465
466 static ErrorCode get_neighbor_sqijk( int np,
467 int pfrom,
468 const int* const gdims,
469 const int* const gperiodic,
470 const int* const dijk,
471 int& pto,
472 int* rdims,
473 int* facedims,
474 int* across_bdy );
475
476 static int gtol( const int* gijk, int i, int j, int k );
477
478 //! assign global ids to vertices in this box
479 ErrorCode assign_global_ids( ScdBox* box );
480
481 //! interface instance
482 Interface* mbImpl;
483
484 //! whether we've searched the database for boxes yet
485 bool searchedBoxes;
486
487 //! structured mesh blocks; stored as ScdBox objects, can get sets from those
488 std::vector< ScdBox* > scdBoxes;
489
490 //! tag representing whether box is periodic in i and j
491 Tag boxPeriodicTag;
492
493 //! tag representing box lower and upper corners
494 Tag boxDimsTag;
495
496 //! tag representing global lower and upper corners
497 Tag globalBoxDimsTag;
498
499 //! tag representing partition method
500 Tag partMethodTag;
501
502 //! tag pointing from set to ScdBox
503 Tag boxSetTag;
504 };
505
506 class MOAB_EXPORT ScdBox
507 {
508 friend class ScdInterface;
509
510 public:
511 //! Destructor
512 ~ScdBox();
513
514 //! Return the ScdInterface responsible for this box
515 inline ScdInterface* sc_impl() const;
516
517 //! Add a vertex box to this box
518 /* Add a vertex box to the element sequence referenced by this box. The passed in vbox must
519 * be a vertex box, with parametric extents no larger than that of this box. This vbox is
520 * oriented to this box by matching parameters from1-from3 in vbox to to1-to3 in this box.
521 * If bb_input is true, only the part of the vertex sequence between bb_min and bb_max is
522 * referenced \param vbox The vertex box being added to this box \param from1 1st reference
523 * point on vbox \param to1 1st reference point on this box \param from2 2nd reference point on
524 * vbox \param to2 2nd reference point on this box \param from3 3rd reference point on vbox
525 * \param to3 3rd reference point on this box
526 * \param bb_input If true, subsequent parameters list extents of vbox referenced
527 * \param bb_min Lower corner of rectangle referenced
528 * \param bb_max Upper corner of rectangle referenced
529 */
530 ErrorCode add_vbox( ScdBox* vbox,
531 HomCoord from1,
532 HomCoord to1,
533 HomCoord from2,
534 HomCoord to2,
535 HomCoord from3,
536 HomCoord to3,
537 bool bb_input = false,
538 const HomCoord& bb_min = HomCoord::getUnitv( 0 ),
539 const HomCoord& bb_max = HomCoord::getUnitv( 0 ) );
540 // const HomCoord &bb_min = HomCoord::unitv[0],
541 // const HomCoord &bb_max = HomCoord::unitv[0]);
542
543 //! Return whether this box has all its vertices defined
544 /** Tests whether vertex boxs added with add_vbox have completely defined the vertex parametric
545 * space for this box.
546 *
547 */
548 bool boundary_complete() const;
549
550 //! Return highest topological dimension of box
551 inline int box_dimension() const;
552
553 //! Starting vertex handle for this box
554 inline EntityHandle start_vertex() const;
555
556 //! Starting entity handle for this box
557 /** If this is a vertex box, the start vertex handle is returned.
558 */
559 inline EntityHandle start_element() const;
560
561 //! Return the number of elements in the box
562 /* Number of elements is (boxSize[0]-1)(boxSize[1]-1)(boxSize[2]-1)
563 */
564 inline int num_elements() const;
565
566 //! Return the number of vertices in the box
567 /* Number of vertices is boxSize[0] * boxSize[1] * boxSize[2]
568 */
569 inline int num_vertices() const;
570
571 //! Return the parametric coordinates for this box
572 /**
573 * \return IJK parameters of lower and upper corners
574 */
575 inline const int* box_dims() const;
576
577 //! Return the lower corner parametric coordinates for this box
578 inline HomCoord box_min() const;
579
580 //! Return the upper corner parametric coordinates for this box
581 inline HomCoord box_max() const;
582
583 //! Return the parameter extents for this box
584 inline HomCoord box_size() const;
585
586 //! Return the parametric extents for this box
587 /**
588 * \param ijk IJK extents of this box
589 */
590 inline void box_size( int* ijk ) const;
591
592 //! Return the parametric extents for this box
593 /**
594 * \param i I extent of this box
595 * \param j J extent of this box
596 * \param k K extent of this box
597 */
598 void box_size( int& i, int& j, int& k ) const;
599
600 //! Get the element at the specified coordinates
601 /**
602 * \param ijk Parametric coordinates being evaluated
603 */
604 EntityHandle get_element( const HomCoord& ijk ) const;
605
606 //! Get the element at the specified coordinates
607 /**
608 * \param i Parametric coordinates being evaluated
609 * \param j Parametric coordinates being evaluated
610 * \param k Parametric coordinates being evaluated
611 */
612 EntityHandle get_element( int i, int j = 0, int k = 0 ) const;
613
614 //! Get the vertex at the specified coordinates
615 /**
616 * \param ijk Parametric coordinates being evaluated
617 */
618 EntityHandle get_vertex( const HomCoord& ijk ) const;
619
620 //! Get the vertex at the specified coordinates
621 /**
622 * \param i Parametric coordinates being evaluated
623 * \param j Parametric coordinates being evaluated
624 * \param k Parametric coordinates being evaluated
625 */
626 EntityHandle get_vertex( int i, int j = 0, int k = 0 ) const;
627
628 //! Get parametric coordinates of the specified entity
629 /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
630 * in this ScdBox.
631 * \param ent Entity being queried
632 * \param i Parametric coordinates returned
633 * \param j Parametric coordinates returned
634 * \param k Parametric coordinates returned
635 * \param dir Parametric coordinate direction returned (in case of getting adjacent
636 * edges (2d, 3d) or faces (3d); not modified otherwise
637 */
638 ErrorCode get_params( EntityHandle ent, int& i, int& j, int& k, int& dir ) const;
639
640 //! Get parametric coordinates of the specified entity, intermediate entities not allowed (no
641 //! dir parameter)
642 /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
643 * in this ScdBox, or MB_FAILURE if the entity is an intermediate-dimension entity.
644 * \param ent Entity being queried
645 * \param i Parametric coordinates returned
646 * \param j Parametric coordinates returned
647 * \param k Parametric coordinates returned
648 */
649 ErrorCode get_params( EntityHandle ent, int& i, int& j, int& k ) const;
650
651 //! Get parametric coordinates of the specified entity
652 /** This function returns MB_ENTITY_NOT_FOUND if the entity is not
653 * in this ScdBox.
654 * \param ent Entity being queried
655 * \param ijkd Parametric coordinates returned (including direction, in case of
656 * getting adjacent edges (2d, 3d) or faces (3d))
657 */
658 ErrorCode get_params( EntityHandle ent, HomCoord& ijkd ) const;
659
660 /** \brief Get the adjacent edge or face at a parametric location
661 * This function gets the left (i=0), front (j=0), or bottom (k=0) edge or face for a parametric
662 * element. Left, front, or bottom is indicated by dir = 0, 1, or 2, resp. All edges and faces
663 * in a structured mesh block can be accessed using these parameters. \param dim Dimension of
664 * adjacent entity being requested \param i Parametric coordinates of cell being evaluated
665 * \param j Parametric coordinates of cell being evaluated
666 * \param k Parametric coordinates of cell being evaluated
667 * \param dir Direction (0, 1, or 2), for getting adjacent edges (2d, 3d) or faces (3d)
668 * \param ent Entity returned from this function
669 * \param create_if_missing If true, creates the entity if it doesn't already exist
670 */
671 ErrorCode get_adj_edge_or_face( int dim,
672 int i,
673 int j,
674 int k,
675 int dir,
676 EntityHandle& ent,
677 bool create_if_missing = true ) const;
678
679 //! Return whether the box contains the parameters passed in
680 /**
681 * \param i Parametric coordinates being evaluated
682 * \param j Parametric coordinates being evaluated
683 * \param k Parametric coordinates being evaluated
684 */
685 bool contains( int i, int j, int k ) const;
686
687 //! Return whether the box contains the parameters passed in
688 /**
689 * \param i Parametric coordinates being evaluated
690 * \param j Parametric coordinates being evaluated
691 * \param k Parametric coordinates being evaluated
692 */
693 bool contains( const HomCoord& ijk ) const;
694
695 //! Set/Get the entity set representing the box
696 void box_set( EntityHandle this_set );
697 EntityHandle box_set();
698
699 //! Get coordinate arrays for vertex coordinates for a structured block
700 /** Returns error if there isn't a single vertex sequence associated with this structured block
701 * \param xc X coordinate array pointer returned
702 * \param yc Y coordinate array pointer returned
703 * \param zc Z coordinate array pointer returned
704 */
705 ErrorCode get_coordinate_arrays( double*& xc, double*& yc, double*& zc );
706
707 //! Get read-only coordinate arrays for vertex coordinates for a structured block
708 /** Returns error if there isn't a single vertex sequence associated with this structured block
709 * \param xc X coordinate array pointer returned
710 * \param yc Y coordinate array pointer returned
711 * \param zc Z coordinate array pointer returned
712 */
713 ErrorCode get_coordinate_arrays( const double*& xc, const double*& yc, const double*& zc ) const;
714
715 //! Return whether box is locally periodic in i
716 /** Return whether box is locally periodic in i
717 * \return True if box is locally periodic in i direction
718 */
719 bool locally_periodic_i() const;
720
721 //! Return whether box is locally periodic in j
722 /** Return whether box is locally periodic in j
723 * \return True if box is locally periodic in j direction
724 */
725 bool locally_periodic_j() const;
726
727 //! Return whether box is locally periodic in k
728 /** Return whether box is locally periodic in k
729 * \return True if box is locally periodic in k direction
730 */
731 bool locally_periodic_k() const;
732
733 //! Set local periodicity
734 /**
735 * \param lperiodic Vector of ijk periodicities to set this box to
736 */
737 void locally_periodic( bool lperiodic[3] );
738
739 //! Get local periodicity
740 /**
741 * \return Vector of ijk periodicities for this box
742 */
743 const int* locally_periodic() const;
744
745 //! Return parallel data
746 /** Return parallel data, if there is any
747 * \return par_data Parallel data set on this box
748 */
749 ScdParData& par_data()
750 {
751 return parData;
752 }
753
754 //! Return parallel data
755 /** Return parallel data, if there is any
756 * \return par_data Parallel data set on this box
757 */
758 const ScdParData& par_data() const
759 {
760 return parData;
761 }
762
763 //! set parallel data
764 /** Set parallel data for this box
765 * \param par_data Parallel data to be set on this box
766 */
767 void par_data( const ScdParData& par_datap )
768 {
769 parData = par_datap;
770 }
771
772 private:
773 //! Constructor
774 /** Create a structured box instance; this constructor is private because it should only be
775 * called from ScdInterface, a friend class. This constructor takes two sequences, one of which
776 * can be NULL. If both sequences come in non-NULL, the first should be a VertexSequence*
777 * corresponding to a structured vertex sequence and the second should be a
778 * StructuredElementSeq*. If the 2nd is NULL, the first can be either of those types. The
779 * other members of this class are taken from the sequences (e.g. parametric space) or the box
780 * set argument. Tags on the box set should be set from the caller. \param sc_impl A
781 * ScdInterface instance \param box_set Entity set representing this rectangle \param seq1 An
782 * EntitySequence (see ScdBox description) \param seq2 An EntitySequence (see ScdBox
783 * description), or NULL
784 */
785 ScdBox( ScdInterface* sc_impl, EntityHandle box_set, EntitySequence* seq1, EntitySequence* seq2 = NULL );
786
787 //! function to get vertex handle directly from sequence
788 /** \param i Parameter being queried
789 * \param j Parameter being queried
790 * \param k Parameter being queried
791 */
792 EntityHandle get_vertex_from_seq( int i, int j, int k ) const;
793
794 //! set the vertex sequence
795 ErrorCode vert_dat( ScdVertexData* vert_dat );
796
797 //! get the vertex sequence
798 ScdVertexData* vert_dat() const;
799
800 //! set the element sequence
801 ErrorCode elem_seq( EntitySequence* elem_seq );
802
803 //! get the element sequence
804 StructuredElementSeq* elem_seq() const;
805
806 //! Set the starting vertex handle for this box
807 void start_vertex( EntityHandle startv );
808
809 //! Set the starting entity handle for this box
810 void start_element( EntityHandle starte );
811
812 //! interface instance
813 ScdInterface* scImpl;
814
815 //! entity set representing this box
816 EntityHandle boxSet;
817
818 //! vertex sequence this box represents, if there's only one, otherwise they're
819 //! retrieved from the element sequence
820 ScdVertexData* vertDat;
821
822 //! element sequence this box represents
823 StructuredElementSeq* elemSeq;
824
825 //! starting vertex handle for this box
826 EntityHandle startVertex;
827
828 //! starting element handle for this box
829 EntityHandle startElem;
830
831 //! lower and upper corners
832 int boxDims[6];
833
834 //! is locally periodic in i or j or k
835 int locallyPeriodic[3];
836
837 //! parallel data associated with this box, if any
838 ScdParData parData;
839
840 //! parameter extents
841 HomCoord boxSize;
842
843 //! convenience parameters, (boxSize[1]-1)*(boxSize[0]-1) and boxSize[0]-1
844 int boxSizeIJ;
845 int boxSizeIJM1;
846 int boxSizeIM1;
847 };
848
849 inline ErrorCode ScdInterface::compute_partition( int np,
850 int nr,
851 const ScdParData& par_data,
852 int* ldims,
853 int* lperiodic,
854 int* pdims )
855 {
856 ErrorCode rval = MB_SUCCESS;
857 switch( par_data.partMethod )
858 {
859 case ScdParData::ALLJORKORI:
860 case -1:
861 rval = compute_partition_alljorkori( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
862 break;
863 case ScdParData::ALLJKBAL:
864 rval = compute_partition_alljkbal( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
865 break;
866 case ScdParData::SQIJ:
867 rval = compute_partition_sqij( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
868 break;
869 case ScdParData::SQJK:
870 rval = compute_partition_sqjk( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
871 break;
872 case ScdParData::SQIJK:
873 rval = compute_partition_sqijk( np, nr, par_data.gDims, par_data.gPeriodic, ldims, lperiodic, pdims );
874 break;
875 default:
876 rval = MB_FAILURE;
877 break;
878 }
879
880 return rval;
881 }
882
883 inline ErrorCode ScdInterface::compute_partition_alljorkori( int np,
884 int nr,
885 const int gijk[6],
886 const int* const gperiodic,
887 int* ldims,
888 int* lperiodic,
889 int* pijk )
890 {
891 // partition *the elements* over the parametric space; 1d partition for now, in the j, k, or i
892 // parameters
893 int tmp_lp[3], tmp_pijk[3];
894 if( !lperiodic ) lperiodic = tmp_lp;
895 if( !pijk ) pijk = tmp_pijk;
896
897 for( int i = 0; i < 3; i++ )
898 lperiodic[i] = gperiodic[i];
899
900 if( np == 1 )
901 {
902 if( ldims )
903 {
904 ldims[0] = gijk[0];
905 ldims[3] = gijk[3];
906 ldims[1] = gijk[1];
907 ldims[4] = gijk[4];
908 ldims[2] = gijk[2];
909 ldims[5] = gijk[5];
910 }
911 pijk[0] = pijk[1] = pijk[2] = 1;
912 }
913 else
914 {
915 if( gijk[4] - gijk[1] > np )
916 {
917 // partition j over procs
918 int dj = ( gijk[4] - gijk[1] ) / np;
919 int extra = ( gijk[4] - gijk[1] ) % np;
920 ldims[1] = gijk[1] + nr * dj + std::min( nr, extra );
921 ldims[4] = ldims[1] + dj + ( nr < extra ? 1 : 0 );
922
923 if( gperiodic[1] && np > 1 )
924 {
925 lperiodic[1] = 0;
926 ldims[4]++;
927 }
928
929 ldims[2] = gijk[2];
930 ldims[5] = gijk[5];
931 ldims[0] = gijk[0];
932 ldims[3] = gijk[3];
933 pijk[0] = pijk[2] = 1;
934 pijk[1] = np;
935 }
936 else if( gijk[5] - gijk[2] > np )
937 {
938 // partition k over procs
939 int dk = ( gijk[5] - gijk[2] ) / np;
940 int extra = ( gijk[5] - gijk[2] ) % np;
941 ldims[2] = gijk[2] + nr * dk + std::min( nr, extra );
942 ldims[5] = ldims[2] + dk + ( nr < extra ? 1 : 0 );
943
944 ldims[1] = gijk[1];
945 ldims[4] = gijk[4];
946 ldims[0] = gijk[0];
947 ldims[3] = gijk[3];
948 pijk[0] = pijk[1] = 1;
949 pijk[2] = np;
950 }
951 else if( gijk[3] - gijk[0] > np )
952 {
953 // partition i over procs
954 int di = ( gijk[3] - gijk[0] ) / np;
955 int extra = ( gijk[3] - gijk[0] ) % np;
956 ldims[0] = gijk[0] + nr * di + std::min( nr, extra );
957 ldims[3] = ldims[0] + di + ( nr < extra ? 1 : 0 );
958
959 if( gperiodic[0] && np > 1 )
960 {
961 lperiodic[0] = 0;
962 ldims[3]++;
963 }
964
965 ldims[2] = gijk[2];
966 ldims[5] = gijk[5];
967 ldims[1] = gijk[1];
968 ldims[4] = gijk[4];
969
970 pijk[1] = pijk[2] = 1;
971 pijk[0] = np;
972 }
973 else
974 {
975 // Couldn't find a suitable partition...
976 return MB_FAILURE;
977 }
978 }
979
980 return MB_SUCCESS;
981 }
982
983 inline ErrorCode ScdInterface::compute_partition_alljkbal( int np,
984 int nr,
985 const int gijk[6],
986 const int* const gperiodic,
987 int* ldims,
988 int* lperiodic,
989 int* pijk )
990 {
991 int tmp_lp[3], tmp_pijk[3];
992 if( !lperiodic ) lperiodic = tmp_lp;
993 if( !pijk ) pijk = tmp_pijk;
994
995 for( int i = 0; i < 3; i++ )
996 lperiodic[i] = gperiodic[i];
997
998 if( np == 1 )
999 {
1000 if( ldims )
1001 {
1002 ldims[0] = gijk[0];
1003 ldims[3] = gijk[3];
1004 ldims[1] = gijk[1];
1005 ldims[4] = gijk[4];
1006 ldims[2] = gijk[2];
1007 ldims[5] = gijk[5];
1008 }
1009 pijk[0] = pijk[1] = pijk[2] = 1;
1010 }
1011 else
1012 {
1013 // improved, possibly 2-d partition
1014 std::vector< double > kfactors;
1015 kfactors.push_back( 1 );
1016 int K = gijk[5] - gijk[2];
1017 for( int i = 2; i < K; i++ )
1018 if( !( K % i ) && !( np % i ) ) kfactors.push_back( i );
1019 kfactors.push_back( K );
1020
1021 // compute the ideal nj and nk
1022 int J = gijk[4] - gijk[1];
1023 double njideal = sqrt( ( (double)( np * J ) ) / ( (double)K ) );
1024 double nkideal = ( njideal * K ) / J;
1025
1026 int nk, nj;
1027 if( nkideal < 1.0 )
1028 {
1029 nk = 1;
1030 nj = np;
1031 }
1032 else
1033 {
1034 std::vector< double >::iterator vit = std::lower_bound( kfactors.begin(), kfactors.end(), nkideal );
1035 if( vit == kfactors.begin() )
1036 nk = 1;
1037 else
1038 nk = (int)*( --vit );
1039 nj = np / nk;
1040 }
1041
1042 int dk = K / nk;
1043 int dj = J / nj;
1044
1045 ldims[2] = gijk[2] + ( nr % nk ) * dk;
1046 ldims[5] = ldims[2] + dk;
1047
1048 int extra = J % nj;
1049
1050 ldims[1] = gijk[1] + ( nr / nk ) * dj + std::min( nr / nk, extra );
1051 ldims[4] = ldims[1] + dj + ( nr / nk < extra ? 1 : 0 );
1052
1053 ldims[0] = gijk[0];
1054 ldims[3] = gijk[3];
1055
1056 if( gperiodic[1] && np > 1 )
1057 {
1058 lperiodic[1] = 0;
1059 if( nr / nk == nj - 1 )
1060 {
1061 ldims[1]++;
1062 }
1063 }
1064
1065 pijk[0] = 1;
1066 pijk[1] = nj;
1067 pijk[2] = nk;
1068 }
1069
1070 return MB_SUCCESS;
1071 }
1072
1073 inline ErrorCode ScdInterface::compute_partition_sqij( int np,
1074 int nr,
1075 const int gijk[6],
1076 const int* const gperiodic,
1077 int* ldims,
1078 int* lperiodic,
1079 int* pijk )
1080 {
1081 int tmp_lp[3], tmp_pijk[3];
1082 if( !lperiodic ) lperiodic = tmp_lp;
1083 if( !pijk ) pijk = tmp_pijk;
1084
1085 // square IxJ partition
1086
1087 for( int i = 0; i < 3; i++ )
1088 lperiodic[i] = gperiodic[i];
1089
1090 if( np == 1 )
1091 {
1092 if( ldims )
1093 {
1094 ldims[0] = gijk[0];
1095 ldims[3] = gijk[3];
1096 ldims[1] = gijk[1];
1097 ldims[4] = gijk[4];
1098 ldims[2] = gijk[2];
1099 ldims[5] = gijk[5];
1100 }
1101 pijk[0] = pijk[1] = pijk[2] = 1;
1102 }
1103 else
1104 {
1105 std::vector< double > pfactors, ppfactors;
1106 for( int i = 2; i <= np / 2; i++ )
1107 if( !( np % i ) )
1108 {
1109 pfactors.push_back( i );
1110 ppfactors.push_back( ( (double)( i * i ) ) / np );
1111 }
1112 pfactors.push_back( np );
1113 ppfactors.push_back( (double)np );
1114
1115 // ideally, Px/Py = I/J
1116 double ijratio = ( (double)( gijk[3] - gijk[0] ) ) / ( (double)( gijk[4] - gijk[1] ) );
1117
1118 unsigned int ind = 0;
1119 std::vector< double >::iterator optimal = std::lower_bound( ppfactors.begin(), ppfactors.end(), ijratio );
1120 if( optimal == ppfactors.end() )
1121 {
1122 ind = ppfactors.size() - 1;
1123 }
1124 else
1125 {
1126 ind = optimal - ppfactors.begin();
1127 if( ind && fabs( ppfactors[ind - 1] - ijratio ) < fabs( ppfactors[ind] - ijratio ) ) ind--;
1128 }
1129
1130 // VARIABLES DESCRIBING THE MESH:
1131 // pi, pj = # procs in i and j directions
1132 // nri, nrj = my proc's position in i, j directions
1133 // I, J = # edges/elements in i, j directions
1134 // iextra, jextra = # procs having extra edge in i/j direction
1135 // top_i, top_j = if true, I'm the last proc in the i/j direction
1136 // i, j = # edges locally in i/j direction, *not* including one for iextra/jextra
1137 int pi = pfactors[ind];
1138 int pj = np / pi;
1139
1140 int I = ( gijk[3] - gijk[0] ), J = ( gijk[4] - gijk[1] );
1141 int iextra = I % pi, jextra = J % pj, i = I / pi, j = J / pj;
1142 int nri = nr % pi, nrj = nr / pi;
1143
1144 if( ldims )
1145 {
1146 ldims[0] = gijk[0] + i * nri + std::min( iextra, nri );
1147 ldims[3] = ldims[0] + i + ( nri < iextra ? 1 : 0 );
1148 ldims[1] = gijk[1] + j * nrj + std::min( jextra, nrj );
1149 ldims[4] = ldims[1] + j + ( nrj < jextra ? 1 : 0 );
1150
1151 ldims[2] = gijk[2];
1152 ldims[5] = gijk[5];
1153
1154 if( gperiodic[0] && pi > 1 )
1155 {
1156 lperiodic[0] = 0;
1157 if( nri == pi - 1 ) ldims[3]++;
1158 }
1159 if( gperiodic[1] && pj > 1 )
1160 {
1161 lperiodic[1] = 0;
1162 if( nrj == pj - 1 ) ldims[4]++;
1163 }
1164 }
1165
1166 pijk[0] = pi;
1167 pijk[1] = pj;
1168 pijk[2] = 1;
1169 }
1170
1171 return MB_SUCCESS;
1172 }
1173
1174 inline ErrorCode ScdInterface::compute_partition_sqjk( int np,
1175 int nr,
1176 const int gijk[6],
1177 const int* const gperiodic,
1178 int* ldims,
1179 int* lperiodic,
1180 int* pijk )
1181 {
1182 int tmp_lp[3], tmp_pijk[3];
1183 if( !lperiodic ) lperiodic = tmp_lp;
1184 if( !pijk ) pijk = tmp_pijk;
1185
1186 // square JxK partition
1187 for( int i = 0; i < 3; i++ )
1188 lperiodic[i] = gperiodic[i];
1189
1190 if( np == 1 )
1191 {
1192 if( ldims )
1193 {
1194 ldims[0] = gijk[0];
1195 ldims[3] = gijk[3];
1196 ldims[1] = gijk[1];
1197 ldims[4] = gijk[4];
1198 ldims[2] = gijk[2];
1199 ldims[5] = gijk[5];
1200 }
1201 pijk[0] = pijk[1] = pijk[2] = 1;
1202 }
1203 else
1204 {
1205 std::vector< double > pfactors, ppfactors;
1206 for( int p = 2; p <= np; p++ )
1207 if( !( np % p ) )
1208 {
1209 pfactors.push_back( p );
1210 ppfactors.push_back( ( (double)( p * p ) ) / np );
1211 }
1212
1213 // ideally, Pj/Pk = J/K
1214 int pj, pk;
1215 if( gijk[5] == gijk[2] )
1216 {
1217 pk = 1;
1218 pj = np;
1219 }
1220 else
1221 {
1222 double jkratio = ( (double)( gijk[4] - gijk[1] ) ) / ( (double)( gijk[5] - gijk[2] ) );
1223
1224 std::vector< double >::iterator vit = std::lower_bound( ppfactors.begin(), ppfactors.end(), jkratio );
1225 if( vit == ppfactors.end() )
1226 --vit;
1227 else if( vit != ppfactors.begin() && fabs( *( vit - 1 ) - jkratio ) < fabs( ( *vit ) - jkratio ) )
1228 --vit;
1229 int ind = vit - ppfactors.begin();
1230
1231 pj = 1;
1232 if( ind >= 0 && !pfactors.empty() ) pj = pfactors[ind];
1233 pk = np / pj;
1234 }
1235
1236 int K = ( gijk[5] - gijk[2] ), J = ( gijk[4] - gijk[1] );
1237 int jextra = J % pj, kextra = K % pk, j = J / pj, k = K / pk;
1238 int nrj = nr % pj, nrk = nr / pj;
1239 ldims[1] = gijk[1] + j * nrj + std::min( jextra, nrj );
1240 ldims[4] = ldims[1] + j + ( nrj < jextra ? 1 : 0 );
1241 ldims[2] = gijk[2] + k * nrk + std::min( kextra, nrk );
1242 ldims[5] = ldims[2] + k + ( nrk < kextra ? 1 : 0 );
1243
1244 ldims[0] = gijk[0];
1245 ldims[3] = gijk[3];
1246
1247 if( gperiodic[1] && pj > 1 )
1248 {
1249 lperiodic[1] = 0;
1250 if( nrj == pj - 1 ) ldims[4]++;
1251 }
1252
1253 pijk[0] = 1;
1254 pijk[1] = pj;
1255 pijk[2] = pk;
1256 }
1257
1258 return MB_SUCCESS;
1259 }
1260
1261 inline ErrorCode ScdInterface::compute_partition_sqijk( int np,
1262 int nr,
1263 const int* const gijk,
1264 const int* const gperiodic,
1265 int* ldims,
1266 int* lperiodic,
1267 int* pijk )
1268 {
1269 if( gperiodic[0] || gperiodic[1] || gperiodic[2] ) return MB_FAILURE;
1270
1271 int tmp_lp[3], tmp_pijk[3];
1272 if( !lperiodic ) lperiodic = tmp_lp;
1273 if( !pijk ) pijk = tmp_pijk;
1274
1275 // square IxJxK partition
1276
1277 for( int i = 0; i < 3; i++ )
1278 lperiodic[i] = gperiodic[i];
1279
1280 if( np == 1 )
1281 {
1282 if( ldims )
1283 for( int i = 0; i < 6; i++ )
1284 ldims[i] = gijk[i];
1285 pijk[0] = pijk[1] = pijk[2] = 1;
1286 return MB_SUCCESS;
1287 }
1288
1289 std::vector< int > pfactors;
1290 pfactors.push_back( 1 );
1291 for( int i = 2; i <= np / 2; i++ )
1292 if( !( np % i ) ) pfactors.push_back( i );
1293 pfactors.push_back( np );
1294
1295 // test for IJ, JK, IK
1296 int IJK[3], dIJK[3];
1297 for( int i = 0; i < 3; i++ )
1298 IJK[i] = std::max( gijk[3 + i] - gijk[i], 1 );
1299 // order IJK from lo to hi
1300 int lo = 0, hi = 0;
1301 for( int i = 1; i < 3; i++ )
1302 {
1303 if( IJK[i] < IJK[lo] ) lo = i;
1304 if( IJK[i] > IJK[hi] ) hi = i;
1305 }
1306 if( lo == hi ) hi = ( lo + 1 ) % 3;
1307 int mid = 3 - lo - hi;
1308 // search for perfect subdivision of np that balances #cells
1309 int perfa_best = -1, perfb_best = -1;
1310 double ratio = 0.0;
1311 for( int po = 0; po < (int)pfactors.size(); po++ )
1312 {
1313 for( int pi = po; pi < (int)pfactors.size() && np / ( pfactors[po] * pfactors[pi] ) >= pfactors[pi]; pi++ )
1314 {
1315 int p3 =
1316 std::find( pfactors.begin(), pfactors.end(), np / ( pfactors[po] * pfactors[pi] ) ) - pfactors.begin();
1317 if( p3 == (int)pfactors.size() || pfactors[po] * pfactors[pi] * pfactors[p3] != np )
1318 continue; // po*pi should exactly factor np
1319 assert( po <= pi && pi <= p3 );
1320 // by definition, po <= pi <= p3
1321 double minl =
1322 std::min( std::min( IJK[lo] / pfactors[po], IJK[mid] / pfactors[pi] ), IJK[hi] / pfactors[p3] ),
1323 maxl =
1324 std::max( std::max( IJK[lo] / pfactors[po], IJK[mid] / pfactors[pi] ), IJK[hi] / pfactors[p3] );
1325 if( minl / maxl > ratio )
1326 {
1327 ratio = minl / maxl;
1328 perfa_best = po;
1329 perfb_best = pi;
1330 }
1331 }
1332 }
1333 if( perfa_best == -1 || perfb_best == -1 ) return MB_FAILURE;
1334
1335 // VARIABLES DESCRIBING THE MESH:
1336 // pijk[i] = # procs in direction i
1337 // numr[i] = my proc's position in direction i
1338 // dIJK[i] = # edges/elements in direction i
1339 // extra[i]= # procs having extra edge in direction i
1340 // top[i] = if true, I'm the last proc in direction i
1341
1342 pijk[lo] = pfactors[perfa_best];
1343 pijk[mid] = pfactors[perfb_best];
1344 pijk[hi] = ( np / ( pfactors[perfa_best] * pfactors[perfb_best] ) );
1345 int extra[3] = { 0, 0, 0 }, numr[3];
1346 for( int i = 0; i < 3; i++ )
1347 {
1348 dIJK[i] = IJK[i] / pijk[i];
1349 extra[i] = IJK[i] % pijk[i];
1350 }
1351 numr[2] = nr / ( pijk[0] * pijk[1] );
1352 int rem = nr % ( pijk[0] * pijk[1] );
1353 numr[1] = rem / pijk[0];
1354 numr[0] = rem % pijk[0];
1355 for( int i = 0; i < 3; i++ )
1356 {
1357 extra[i] = IJK[i] % dIJK[i];
1358 ldims[i] = gijk[i] + numr[i] * dIJK[i] + std::min( extra[i], numr[i] );
1359 ldims[3 + i] = ldims[i] + dIJK[i] + ( numr[i] < extra[i] ? 1 : 0 );
1360 }
1361
1362 return MB_SUCCESS;
1363 }
1364
1365 inline int ScdInterface::gtol( const int* gijk, int i, int j, int k )
1366 {
1367 return ( ( k - gijk[2] ) * ( gijk[3] - gijk[0] + 1 ) * ( gijk[4] - gijk[1] + 1 ) +
1368 ( j - gijk[1] ) * ( gijk[3] - gijk[0] + 1 ) + i - gijk[0] );
1369 }
1370
1371 inline ErrorCode ScdInterface::get_indices( const int* const ldims,
1372 const int* const rdims,
1373 const int* const across_bdy,
1374 int* face_dims,
1375 std::vector< int >& shared_indices )
1376 {
1377 // check for going across periodic bdy and face_dims not in my ldims (I'll always be on top in
1378 // that case)...
1379 if( across_bdy[0] > 0 && face_dims[0] != ldims[3] )
1380 face_dims[0] = face_dims[3] = ldims[3];
1381 else if( across_bdy[0] < 0 && face_dims[0] != ldims[0] )
1382 face_dims[0] = face_dims[3] = ldims[0];
1383 if( across_bdy[1] > 0 && face_dims[1] != ldims[4] )
1384 face_dims[1] = face_dims[4] = ldims[4];
1385 else if( across_bdy[1] < 0 && face_dims[1] != ldims[1] )
1386 face_dims[0] = face_dims[3] = ldims[1];
1387
1388 for( int k = face_dims[2]; k <= face_dims[5]; k++ )
1389 for( int j = face_dims[1]; j <= face_dims[4]; j++ )
1390 for( int i = face_dims[0]; i <= face_dims[3]; i++ )
1391 shared_indices.push_back( gtol( ldims, i, j, k ) );
1392
1393 if( across_bdy[0] > 0 && face_dims[0] != rdims[0] )
1394 face_dims[0] = face_dims[3] = rdims[0];
1395 else if( across_bdy[0] < 0 && face_dims[0] != rdims[3] )
1396 face_dims[0] = face_dims[3] = rdims[3];
1397 if( across_bdy[1] > 0 && face_dims[1] != rdims[1] )
1398 face_dims[1] = face_dims[4] = rdims[1];
1399 else if( across_bdy[1] < 0 && face_dims[1] != rdims[4] )
1400 face_dims[0] = face_dims[3] = rdims[4];
1401
1402 for( int k = face_dims[2]; k <= face_dims[5]; k++ )
1403 for( int j = face_dims[1]; j <= face_dims[4]; j++ )
1404 for( int i = face_dims[0]; i <= face_dims[3]; i++ )
1405 shared_indices.push_back( gtol( rdims, i, j, k ) );
1406
1407 return MB_SUCCESS;
1408 }
1409
1410 inline ErrorCode ScdInterface::get_neighbor( int np,
1411 int pfrom,
1412 const ScdParData& spd,
1413 const int* const dijk,
1414 int& pto,
1415 int* rdims,
1416 int* facedims,
1417 int* across_bdy )
1418 {
1419 if( !dijk[0] && !dijk[1] && !dijk[2] )
1420 {
1421 // not going anywhere, return
1422 pto = -1;
1423 return MB_SUCCESS;
1424 }
1425
1426 switch( spd.partMethod )
1427 {
1428 case ScdParData::ALLJORKORI:
1429 case -1:
1430 return get_neighbor_alljorkori( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims,
1431 across_bdy );
1432 case ScdParData::ALLJKBAL:
1433 return get_neighbor_alljkbal( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
1434 case ScdParData::SQIJ:
1435 return get_neighbor_sqij( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
1436 case ScdParData::SQJK:
1437 return get_neighbor_sqjk( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
1438 case ScdParData::SQIJK:
1439 return get_neighbor_sqijk( np, pfrom, spd.gDims, spd.gPeriodic, dijk, pto, rdims, facedims, across_bdy );
1440 default:
1441 break;
1442 }
1443
1444 return MB_FAILURE;
1445 }
1446
1447 inline ErrorCode ScdInterface::tag_shared_vertices( ParallelComm* pcomm, EntityHandle seth )
1448 {
1449 ScdBox* box = get_scd_box( seth );
1450 if( !box )
1451 {
1452 // look for contained boxes
1453 Range tmp_range;
1454 ErrorCode rval = mbImpl->get_entities_by_type( seth, MBENTITYSET, tmp_range );
1455 if( MB_SUCCESS != rval ) return rval;
1456 for( Range::iterator rit = tmp_range.begin(); rit != tmp_range.end(); ++rit )
1457 {
1458 box = get_scd_box( *rit );
1459 if( box ) break;
1460 }
1461 }
1462
1463 if( !box ) return MB_FAILURE;
1464
1465 return tag_shared_vertices( pcomm, box );
1466 }
1467
1468 inline ScdInterface* ScdBox::sc_impl() const
1469 {
1470 return scImpl;
1471 }
1472
1473 inline EntityHandle ScdBox::start_vertex() const
1474 {
1475 return startVertex;
1476 }
1477
1478 inline void ScdBox::start_vertex( EntityHandle startv )
1479 {
1480 startVertex = startv;
1481 }
1482
1483 inline EntityHandle ScdBox::start_element() const
1484 {
1485 return startElem;
1486 }
1487
1488 inline void ScdBox::start_element( EntityHandle starte )
1489 {
1490 startElem = starte;
1491 }
1492
1493 inline int ScdBox::num_elements() const
1494 {
1495 if( !startElem ) return 0; // not initialized yet
1496
1497 /* for a structured mesh, total number of elements is obtained by multiplying
1498 number of elements in each direction
1499 number of elements in each direction is given by number of vertices in that direction minus 1
1500 if periodic in that direction, the last vertex is the same as first one, count one more
1501 element
1502 */
1503 int num_e_i = ( -1 == boxSize[0] || 1 == boxSize[0] ) ? 1 : boxSize[0] - 1;
1504 if( locallyPeriodic[0] ) ++num_e_i;
1505
1506 int num_e_j = ( -1 == boxSize[1] || 1 == boxSize[1] ) ? 1 : boxSize[1] - 1;
1507 if( locallyPeriodic[1] ) ++num_e_j;
1508
1509 int num_e_k = ( -1 == boxSize[2] || 1 == boxSize[2] ) ? 1 : boxSize[2] - 1;
1510 if( locallyPeriodic[2] ) ++num_e_k;
1511
1512 return num_e_i * num_e_j * num_e_k;
1513 }
1514
1515 inline int ScdBox::num_vertices() const
1516 {
1517 return boxSize[0] * ( !boxSize[1] ? 1 : boxSize[1] ) * ( !boxSize[2] ? 1 : boxSize[2] );
1518 }
1519
1520 inline const int* ScdBox::box_dims() const
1521 {
1522 return boxDims;
1523 }
1524
1525 inline HomCoord ScdBox::box_min() const
1526 {
1527 return HomCoord( boxDims, 3 );
1528 }
1529
1530 inline HomCoord ScdBox::box_max() const
1531 {
1532 return HomCoord( boxDims + 3, 3 );
1533 }
1534
1535 inline HomCoord ScdBox::box_size() const
1536 {
1537 return boxSize;
1538 }
1539
1540 inline void ScdBox::box_size( int* ijk ) const
1541 {
1542 ijk[0] = boxSize[0];
1543 ijk[1] = boxSize[1];
1544 ijk[2] = boxSize[2];
1545 }
1546
1547 inline void ScdBox::box_size( int& i, int& j, int& k ) const
1548 {
1549 i = boxSize[0];
1550 j = boxSize[1];
1551 k = boxSize[2];
1552 }
1553
1554 inline EntityHandle ScdBox::get_element( int i, int j, int k ) const
1555 {
1556 return ( !startElem
1557 ? 0
1558 : startElem + ( k - boxDims[2] ) * boxSizeIJM1 + ( j - boxDims[1] ) * boxSizeIM1 + i - boxDims[0] );
1559 }
1560
1561 inline EntityHandle ScdBox::get_element( const HomCoord& ijk ) const
1562 {
1563 return get_element( ijk[0], ijk[1], ijk[2] );
1564 }
1565
1566 inline EntityHandle ScdBox::get_vertex( int i, int j, int k ) const
1567 {
1568 return ( vertDat
1569 ? startVertex + ( boxDims[2] == -1 && boxDims[5] == -1 ? 0 : ( k - boxDims[2] ) ) * boxSizeIJ +
1570 ( boxDims[1] == -1 && boxDims[4] == -1 ? 0 : ( j - boxDims[1] ) ) * boxSize[0] + i - boxDims[0]
1571 : get_vertex_from_seq( i, j, k ) );
1572 }
1573
1574 inline EntityHandle ScdBox::get_vertex( const HomCoord& ijk ) const
1575 {
1576 return get_vertex( ijk[0], ijk[1], ijk[2] );
1577 }
1578
1579 inline bool ScdBox::contains( const HomCoord& ijk ) const
1580 {
1581 return ( ijk >= HomCoord( boxDims, 3 ) && ijk <= HomCoord( boxDims + 3, 3 ) );
1582 }
1583
1584 inline bool ScdBox::contains( int i, int j, int k ) const
1585 {
1586 return contains( HomCoord( i, j, k ) );
1587 }
1588
1589 inline void ScdBox::box_set( EntityHandle this_set )
1590 {
1591 boxSet = this_set;
1592 }
1593
1594 inline EntityHandle ScdBox::box_set()
1595 {
1596 return boxSet;
1597 }
1598
1599 inline ScdVertexData* ScdBox::vert_dat() const
1600 {
1601 return vertDat;
1602 }
1603
1604 inline StructuredElementSeq* ScdBox::elem_seq() const
1605 {
1606 return elemSeq;
1607 }
1608
1609 inline ErrorCode ScdBox::get_params( EntityHandle ent, int& i, int& j, int& k, int& dir ) const
1610 {
1611 HomCoord hc;
1612 ErrorCode rval = get_params( ent, hc );
1613 if( MB_SUCCESS == rval )
1614 {
1615 i = hc[0];
1616 j = hc[1];
1617 k = hc[2];
1618 dir = hc[3];
1619 }
1620
1621 return rval;
1622 }
1623
1624 inline ErrorCode ScdBox::get_params( EntityHandle ent, int& i, int& j, int& k ) const
1625 {
1626 HomCoord hc;
1627 ErrorCode rval = get_params( ent, hc );
1628 if( MB_SUCCESS == rval )
1629 {
1630 i = hc[0];
1631 j = hc[1];
1632 k = hc[2];
1633 }
1634
1635 return rval;
1636 }
1637
1638 inline bool ScdBox::locally_periodic_i() const
1639 {
1640 return locallyPeriodic[0];
1641 }
1642
1643 inline bool ScdBox::locally_periodic_j() const
1644 {
1645 return locallyPeriodic[1];
1646 }
1647
1648 inline bool ScdBox::locally_periodic_k() const
1649 {
1650 return locallyPeriodic[2];
1651 }
1652
1653 inline void ScdBox::locally_periodic( bool lperiodic[3] )
1654 {
1655 for( int i = 0; i < 3; i++ )
1656 locallyPeriodic[i] = lperiodic[i];
1657 }
1658
1659 inline const int* ScdBox::locally_periodic() const
1660 {
1661 return locallyPeriodic;
1662 }
1663
1664 std::ostream& operator<<( std::ostream& str, const ScdParData& pd );
1665
1666 } // namespace moab
1667 #endif