277 lines
9.3 KiB
C++
277 lines
9.3 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
|
|
*/
|
|
|
|
#ifndef SPARSELINEARSYSTEMFILL_HPP
|
|
#define SPARSELINEARSYSTEMFILL_HPP
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <limits>
|
|
|
|
#include <FEMesh.hpp>
|
|
#include <SparseLinearSystem.hpp>
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
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<size_type>::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 */
|
|
|