/* //@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 #include #include #include #include //---------------------------------------------------------------------------- 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::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 & 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 & 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 & part_boxes , const BoxBounds & use_boxes , const size_t my_part , BoxType & my_use_box , std::vector & my_use_id_map , size_t & my_count_interior , size_t & my_count_owned , size_t & my_count_uses , std::vector & my_part_counts , std::vector > & 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::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() ); 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 ] ); }}} } } }