/* //@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 */ #ifndef SPARSELINEARSYSTEMFILL_HPP #define SPARSELINEARSYSTEMFILL_HPP #include #include #include #include #include //---------------------------------------------------------------------------- namespace HybridFEM { template< class MatrixType , class MeshType , class elem_matrices_type , class elem_vectors_type > struct GatherFill ; template< typename ScalarType , class DeviceType , unsigned ElemNode , typename CoordScalarType , class elem_matrices_type , class elem_vectors_type > struct GatherFill< Kokkos::CrsMatrix< ScalarType , DeviceType > , FEMesh< CoordScalarType , ElemNode , DeviceType > , elem_matrices_type , elem_vectors_type > { typedef DeviceType execution_space ; typedef typename execution_space::size_type size_type ; static const size_type ElemNodeCount = ElemNode ; typedef Kokkos::CrsMatrix< ScalarType , execution_space > matrix_type ; typedef typename matrix_type::coefficients_type coefficients_type ; typedef Kokkos::View< ScalarType[] , execution_space > vector_type ; typedef Kokkos::View< size_type[][ElemNodeCount][ElemNodeCount] , execution_space > elem_graph_type ; typedef FEMesh< CoordScalarType , ElemNodeCount , execution_space > mesh_type ; typedef typename mesh_type::node_elem_ids_type node_elem_ids_type ; private: node_elem_ids_type node_elem_ids ; elem_graph_type elem_graph ; elem_matrices_type elem_matrices ; elem_vectors_type elem_vectors ; coefficients_type system_coeff ; vector_type system_rhs ; public: KOKKOS_INLINE_FUNCTION void operator()( size_type irow ) const { const size_type node_elem_begin = node_elem_ids.row_map[irow]; const size_type node_elem_end = node_elem_ids.row_map[irow+1]; // for each element that a node belongs to for ( size_type i = node_elem_begin ; i < node_elem_end ; i++ ) { const size_type elem_id = node_elem_ids.entries( i, 0); const size_type row_index = node_elem_ids.entries( i, 1); system_rhs(irow) += elem_vectors(elem_id, row_index); // for each node in a particular related element // gather the contents of the element stiffness // matrix that belong in irow for ( size_type j = 0 ; j < ElemNodeCount ; ++j ){ const size_type A_index = elem_graph( elem_id , row_index , j ); system_coeff( A_index ) += elem_matrices( elem_id, row_index, j ); } } } static void apply( const matrix_type & matrix , const vector_type & rhs , const mesh_type & mesh , const elem_graph_type & elem_graph , const elem_matrices_type & elem_matrices , const elem_vectors_type & elem_vectors ) { const size_t row_count = matrix.graph.row_map.dimension_0() - 1 ; GatherFill op ; op.node_elem_ids = mesh.node_elem_ids ; op.elem_graph = elem_graph ; op.elem_matrices = elem_matrices ; op.elem_vectors = elem_vectors ; op.system_coeff = matrix.coefficients ; op.system_rhs = rhs ; parallel_for( row_count , op ); } }; } /* namespace HybridFEM */ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace HybridFEM { template< class GraphType , class MeshType > struct GraphFactory { typedef GraphType graph_type ; typedef MeshType mesh_type ; typedef typename graph_type::execution_space execution_space ; typedef typename execution_space::size_type size_type ; static const unsigned ElemNodeCount = mesh_type::element_node_count ; typedef Kokkos::View< size_type[][ElemNodeCount][ElemNodeCount] , execution_space > element_map_type ; static void create( const mesh_type & mesh , graph_type & graph , element_map_type & elem_map ) { typename mesh_type::node_elem_ids_type::HostMirror node_elem_ids = create_mirror( mesh.node_elem_ids ); typename mesh_type::elem_node_ids_type::HostMirror elem_node_ids = create_mirror( mesh.elem_node_ids ); typedef typename element_map_type::HostMirror element_map_host_type ; deep_copy( elem_node_ids , mesh.elem_node_ids ); deep_copy( node_elem_ids.entries , mesh.node_elem_ids.entries ); const size_t owned_node = mesh.parallel_data_map.count_owned ; const size_t total_elem = mesh.elem_node_ids.dimension_0(); if ( total_elem ) { elem_map = element_map_type( std::string("element_map"), total_elem ); } element_map_host_type elem_map_host = create_mirror( elem_map ); //------------------------------------ // Node->node mapping for the CrsMatrix graph std::vector< std::vector< unsigned > > node_node_ids( owned_node ); std::vector< unsigned > node_node_begin( owned_node ); size_t offset = 0 ; for ( size_t i = 0 ; i < owned_node ; ++i ) { const size_t j_end = node_elem_ids.row_map[i+1]; size_t j = node_elem_ids.row_map[i]; node_node_begin[i] = offset ; std::vector< unsigned > & work = node_node_ids[i] ; for ( ; j < j_end ; ++j ) { const size_t elem_id = node_elem_ids.entries(j,0); for ( size_t k = 0 ; k < ElemNodeCount ; ++k ) { work.push_back( elem_node_ids( elem_id , k ) ); } } std::sort( work.begin() , work.end() ); work.erase( std::unique( work.begin() , work.end() ) , work.end() ); offset += work.size(); } graph = Kokkos::create_staticcrsgraph< graph_type >( "node_node_ids" , node_node_ids ); //------------------------------------ // ( element , node_row , node_column ) -> matrix_crs_column for ( size_t elem_id = 0 ; elem_id < total_elem ; ++elem_id ) { for ( size_t i = 0 ; i < ElemNodeCount ; ++i ) { const size_t node_row = elem_node_ids( elem_id , i ); const size_t node_row_begin = node_node_begin[ node_row ]; const std::vector< unsigned > & column = node_node_ids[ node_row ] ; if ( owned_node <= node_row ) { for ( unsigned j = 0 ; j < ElemNodeCount ; ++j ) { elem_map_host( elem_id , i , j ) = std::numeric_limits::max(); } } else { for ( unsigned j = 0 ; j < ElemNodeCount ; ++j ) { const size_type node_col = elem_node_ids( elem_id , j ); int col_search = 0 ; for ( int len = column.size() ; 0 < len ; ) { const int half = len >> 1; const int middle = col_search + half ; if ( column[middle] < node_col ){ col_search = middle + 1 ; len -= half + 1 ; } else { len = half ; } } if ( node_col != column[col_search] ) { throw std::runtime_error(std::string("Failed")); } elem_map_host( elem_id , i , j ) = col_search + node_row_begin ; } } } } deep_copy( elem_map , elem_map_host ); } }; } // namespace HybridFEM //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #ifndef SPARSELINEARSYSTEMFILL_HPP */