382 lines
13 KiB
C++
382 lines
13 KiB
C++
/*
|
|
//@HEADER
|
|
// ************************************************************************
|
|
//
|
|
// Kokkos v. 2.0
|
|
// Copyright (2014) Sandia Corporation
|
|
//
|
|
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
// the U.S. Government retains certain rights in this software.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the Corporation nor the names of the
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
|
|
//
|
|
// ************************************************************************
|
|
//@HEADER
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <limits>
|
|
#include <BoxMeshPartition.hpp>
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
namespace {
|
|
|
|
void box_partition( size_t ip , size_t up ,
|
|
const BoxType & box ,
|
|
BoxType * const p_box )
|
|
{
|
|
const size_t np = up - ip ;
|
|
|
|
if ( 1 == np ) {
|
|
p_box[ip] = box ;
|
|
}
|
|
else {
|
|
// Choose axis with largest count:
|
|
|
|
const size_t n0 = box[0][1] - box[0][0] ;
|
|
const size_t n1 = box[1][1] - box[1][0] ;
|
|
const size_t n2 = box[2][1] - box[2][0] ;
|
|
|
|
const size_t axis = n2 > n1 ? ( n2 > n0 ? 2 : ( n1 > n0 ? 1 : 0 ) ) :
|
|
( n1 > n0 ? 1 : 0 );
|
|
|
|
const size_t n = box[ axis ][1] - box[ axis ][0] ;
|
|
|
|
if ( 0 == np % 3 ) {
|
|
const size_t np_part = np / 3 ; // exact
|
|
|
|
const size_t nbox_low = (size_t)(( (double) n ) * ( 1.0 / 3.0 ));
|
|
const size_t nbox_mid = (size_t)(( (double) n ) * ( 2.0 / 3.0 ));
|
|
|
|
BoxType dbox_low = box ; // P = [ip,ip+np/3)
|
|
BoxType dbox_mid = box ; // P = [ip+np/3,ip+2*np/3)
|
|
BoxType dbox_upp = box ; // P = [ip+2*np/3,ip+np)
|
|
|
|
dbox_low[ axis ][1] = box[ axis ][0] + nbox_low ;
|
|
dbox_mid[ axis ][1] = box[ axis ][0] + nbox_mid ;
|
|
|
|
dbox_mid[ axis ][0] = dbox_low[ axis ][1];
|
|
dbox_upp[ axis ][0] = dbox_mid[ axis ][1];
|
|
|
|
box_partition( ip, ip + np_part, dbox_low , p_box );
|
|
box_partition( ip+ np_part, ip + 2*np_part, dbox_mid , p_box );
|
|
box_partition( ip+2*np_part, up, dbox_upp , p_box );
|
|
}
|
|
else {
|
|
const size_t np_low = np / 2 ; /* Rounded down */
|
|
const size_t nbox_low = (size_t)
|
|
(((double)n) * ( ((double) np_low ) / ((double) np ) ));
|
|
|
|
BoxType dbox_low = box ;
|
|
BoxType dbox_upp = box ;
|
|
|
|
dbox_low[ axis ][1] = dbox_low[ axis ][0] + nbox_low ;
|
|
dbox_upp[ axis ][0] = dbox_low[ axis ][1];
|
|
|
|
box_partition( ip, ip + np_low, dbox_low , p_box );
|
|
box_partition( ip + np_low, up, dbox_upp , p_box );
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t box_map_offset( const BoxType & local_use ,
|
|
const size_t global_i ,
|
|
const size_t global_j ,
|
|
const size_t global_k )
|
|
|
|
{
|
|
const size_t max = std::numeric_limits<size_t>::max();
|
|
|
|
const size_t n[3] =
|
|
{ local_use[0][1] - local_use[0][0] ,
|
|
local_use[1][1] - local_use[1][0] ,
|
|
local_use[2][1] - local_use[2][0] };
|
|
|
|
const size_t use[3] = {
|
|
( global_i >= local_use[0][0] ? global_i - local_use[0][0] : max ) ,
|
|
( global_j >= local_use[1][0] ? global_j - local_use[1][0] : max ) ,
|
|
( global_k >= local_use[2][0] ? global_k - local_use[2][0] : max ) };
|
|
|
|
const size_t offset =
|
|
( use[0] < n[0] && use[1] < n[1] && use[2] < n[2] ) ?
|
|
( use[0] + n[0] * ( use[1] + n[1] * use[2] ) ) : max ;
|
|
|
|
if ( offset == max ) {
|
|
std::ostringstream msg ;
|
|
msg << "box_map_offset ERROR: "
|
|
<< " use " << local_use
|
|
<< " ( " << global_i
|
|
<< " , " << global_j
|
|
<< " , " << global_k
|
|
<< " )" ;
|
|
throw std::runtime_error( msg.str() );
|
|
}
|
|
|
|
return offset ;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void BoxBoundsLinear::apply( const BoxType & box_global ,
|
|
const BoxType & box_part ,
|
|
BoxType & box_interior ,
|
|
BoxType & box_use ) const
|
|
{
|
|
const unsigned ghost = 1 ;
|
|
|
|
if ( 0 == count( box_part ) ) {
|
|
box_interior = box_part ;
|
|
box_use = box_part ;
|
|
}
|
|
else {
|
|
for ( size_t i = 0 ; i < 3 ; ++i ) {
|
|
|
|
box_interior[i][0] =
|
|
( box_part[i][0] == box_global[i][0] ) ? box_part[i][0] : (
|
|
( box_part[i][0] + ghost < box_part[i][1] ) ? box_part[i][0] + ghost :
|
|
box_part[i][1] );
|
|
|
|
box_interior[i][1] =
|
|
( box_part[i][1] == box_global[i][1] ) ? box_part[i][1] : (
|
|
( box_part[i][0] + ghost < box_part[i][1] ) ? box_part[i][1] - ghost :
|
|
box_part[i][0] );
|
|
|
|
box_use[i][0] =
|
|
( box_part[i][0] > ghost + box_global[i][0] ) ? box_part[i][0] - ghost :
|
|
box_global[i][0] ;
|
|
box_use[i][1] =
|
|
( box_part[i][1] + ghost < box_global[i][1] ) ? box_part[i][1] + ghost :
|
|
box_global[i][1] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxBoundsQuadratic::apply( const BoxType & box_global ,
|
|
const BoxType & box_part ,
|
|
BoxType & box_interior ,
|
|
BoxType & box_use ) const
|
|
{
|
|
if ( 0 == count( box_part ) ) {
|
|
box_interior = box_part ;
|
|
box_use = box_part ;
|
|
}
|
|
else {
|
|
for ( size_t i = 0 ; i < 3 ; ++i ) {
|
|
const bool odd = ( box_part[i][0] - box_global[i][0] ) & 01 ;
|
|
|
|
const unsigned ghost = odd ? 1 : 2 ;
|
|
|
|
box_interior[i][0] =
|
|
( box_part[i][0] == box_global[i][0] ) ? box_part[i][0] : (
|
|
( box_part[i][0] + ghost < box_part[i][1] ) ? box_part[i][0] + ghost :
|
|
box_part[i][1] );
|
|
|
|
box_interior[i][1] =
|
|
( box_part[i][1] == box_global[i][1] ) ? box_part[i][1] : (
|
|
( box_part[i][0] + ghost < box_part[i][1] ) ? box_part[i][1] - ghost :
|
|
box_part[i][0] );
|
|
|
|
box_use[i][0] =
|
|
( box_part[i][0] > ghost + box_global[i][0] ) ? box_part[i][0] - ghost :
|
|
box_global[i][0] ;
|
|
box_use[i][1] =
|
|
( box_part[i][1] + ghost < box_global[i][1] ) ? box_part[i][1] + ghost :
|
|
box_global[i][1] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void box_partition_rcb( const BoxType & root_box ,
|
|
std::vector<BoxType> & part_boxes )
|
|
{
|
|
const BoxBoundsLinear use_boxes ;
|
|
|
|
const size_t part_count = part_boxes.size();
|
|
|
|
box_partition( 0 , part_count , root_box , & part_boxes[0] );
|
|
|
|
// Verify partitioning
|
|
|
|
size_t total_cell = 0 ;
|
|
|
|
for ( size_t i = 0 ; i < part_count ; ++i ) {
|
|
|
|
total_cell += count( part_boxes[i] );
|
|
|
|
BoxType box_interior , box_use ;
|
|
|
|
use_boxes.apply( root_box , part_boxes[i] , box_interior , box_use );
|
|
|
|
if ( count( box_use ) < count( part_boxes[i] ) ||
|
|
count( part_boxes[i] ) < count( box_interior ) ||
|
|
part_boxes[i] != intersect( part_boxes[i] , box_use ) ||
|
|
box_interior != intersect( part_boxes[i] , box_interior )) {
|
|
|
|
std::ostringstream msg ;
|
|
|
|
msg << "box_partition_rcb ERROR : "
|
|
<< "part_boxes[" << i << "] = "
|
|
<< part_boxes[i]
|
|
<< " use " << box_use
|
|
<< " interior " << box_interior
|
|
<< std::endl
|
|
<< " part ^ use " << intersect( part_boxes[i] , box_use )
|
|
<< " part ^ interior " << intersect( part_boxes[i] , box_interior );
|
|
|
|
throw std::runtime_error( msg.str() );
|
|
}
|
|
|
|
for ( size_t j = i + 1 ; j < part_count ; ++j ) {
|
|
const BoxType tmp = intersect( part_boxes[i] , part_boxes[j] );
|
|
|
|
if ( count( tmp ) ) {
|
|
throw std::runtime_error( std::string("box partition intersection") );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( total_cell != count( root_box ) ) {
|
|
throw std::runtime_error( std::string("box partition count") );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
size_t box_map_id( const BoxType & local_use ,
|
|
const std::vector<size_t> & local_use_id_map ,
|
|
const size_t global_i ,
|
|
const size_t global_j ,
|
|
const size_t global_k )
|
|
|
|
{
|
|
const size_t offset =
|
|
box_map_offset( local_use , global_i , global_j , global_k );
|
|
return local_use_id_map[ offset ];
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void box_partition_maps( const BoxType & root_box ,
|
|
const std::vector<BoxType> & part_boxes ,
|
|
const BoxBounds & use_boxes ,
|
|
const size_t my_part ,
|
|
BoxType & my_use_box ,
|
|
std::vector<size_t> & my_use_id_map ,
|
|
size_t & my_count_interior ,
|
|
size_t & my_count_owned ,
|
|
size_t & my_count_uses ,
|
|
std::vector<size_t> & my_part_counts ,
|
|
std::vector<std::vector<size_t> > & my_send_map )
|
|
{
|
|
const size_t np = part_boxes.size();
|
|
|
|
if ( np <= my_part ) {
|
|
std::ostringstream msg ;
|
|
msg << "box_partition_maps ERROR : "
|
|
<< " np(" << np << ") <= my_part(" << my_part << ")" ;
|
|
throw std::runtime_error( msg.str() );
|
|
}
|
|
|
|
const BoxType my_owned_box = part_boxes[my_part];
|
|
BoxType my_interior_box ;
|
|
|
|
|
|
use_boxes.apply( root_box, my_owned_box, my_interior_box, my_use_box );
|
|
|
|
my_count_interior = count( my_interior_box );
|
|
my_count_owned = count( my_owned_box );
|
|
my_count_uses = count( my_use_box );
|
|
|
|
my_use_id_map.assign( my_count_uses , std::numeric_limits<size_t>::max() );
|
|
|
|
// Order ids as { owned-interior , owned-parallel , received_{(p+i)%np} }
|
|
|
|
size_t offset_interior = 0 ;
|
|
size_t offset_parallel = my_count_interior ;
|
|
|
|
for ( size_t iz = my_owned_box[2][0] ; iz < my_owned_box[2][1] ; ++iz ) {
|
|
for ( size_t iy = my_owned_box[1][0] ; iy < my_owned_box[1][1] ; ++iy ) {
|
|
for ( size_t ix = my_owned_box[0][0] ; ix < my_owned_box[0][1] ; ++ix ) {
|
|
const size_t offset = box_map_offset( my_use_box , ix , iy , iz );
|
|
if ( contain( my_interior_box , ix , iy , iz ) ) {
|
|
my_use_id_map[ offset ] = offset_interior++ ;
|
|
}
|
|
else {
|
|
my_use_id_map[ offset ] = offset_parallel++ ;
|
|
}
|
|
}}}
|
|
|
|
|
|
my_part_counts.assign( np , (size_t) 0 );
|
|
my_send_map.assign( np , std::vector<size_t>() );
|
|
|
|
my_part_counts[0] = my_count_owned ;
|
|
|
|
for ( size_t i = 1 ; i < np ; ++i ) {
|
|
|
|
const size_t ip = ( my_part + i ) % np ;
|
|
|
|
const BoxType p_owned_box = part_boxes[ip];
|
|
BoxType p_use_box , p_interior_box ;
|
|
use_boxes.apply( root_box, p_owned_box, p_interior_box, p_use_box );
|
|
|
|
const BoxType recv_box = intersect( my_use_box , p_owned_box );
|
|
const BoxType send_box = intersect( my_owned_box , p_use_box );
|
|
|
|
if ( 0 != ( my_part_counts[i] = count( recv_box ) ) ) {
|
|
for ( size_t iz = recv_box[2][0] ; iz < recv_box[2][1] ; ++iz ) {
|
|
for ( size_t iy = recv_box[1][0] ; iy < recv_box[1][1] ; ++iy ) {
|
|
for ( size_t ix = recv_box[0][0] ; ix < recv_box[0][1] ; ++ix ) {
|
|
const size_t offset = box_map_offset( my_use_box , ix , iy , iz );
|
|
my_use_id_map[ offset ] = offset_parallel++ ;
|
|
}}}
|
|
}
|
|
|
|
if ( 0 != count( send_box ) ) {
|
|
for ( size_t iz = send_box[2][0] ; iz < send_box[2][1] ; ++iz ) {
|
|
for ( size_t iy = send_box[1][0] ; iy < send_box[1][1] ; ++iy ) {
|
|
for ( size_t ix = send_box[0][0] ; ix < send_box[0][1] ; ++ix ) {
|
|
const size_t offset = box_map_offset( my_use_box , ix , iy , iz );
|
|
|
|
my_send_map[ i ].push_back( my_use_id_map[ offset ] );
|
|
}}}
|
|
}
|
|
}
|
|
}
|
|
|
|
|