forked from lijiext/lammps
586 lines
19 KiB
C++
586 lines
19 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 H. Carter Edwards (hcedwar@sandia.gov)
|
|
//
|
|
// ************************************************************************
|
|
//@HEADER
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <cstdlib>
|
|
#include <cmath>
|
|
|
|
namespace HybridFEM {
|
|
namespace Implicit {
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
template< typename Scalar , unsigned Dim , unsigned N >
|
|
struct TensorIntegration ;
|
|
|
|
template<typename Scalar >
|
|
struct TensorIntegration<Scalar,1,1> {
|
|
Scalar pts[1] ;
|
|
Scalar wts[1] ;
|
|
|
|
TensorIntegration() { pts[0] = 0 ; wts[0] = 2 ; }
|
|
};
|
|
|
|
template<typename Scalar >
|
|
struct TensorIntegration<Scalar,1,2>
|
|
{
|
|
Scalar pts[2] ;
|
|
Scalar wts[2] ;
|
|
|
|
TensorIntegration()
|
|
{
|
|
const Scalar x2 = 0.577350269 ;
|
|
pts[0] = -x2; wts[0] = 1.0;
|
|
pts[1] = x2; wts[1] = 1.0;
|
|
}
|
|
};
|
|
|
|
template<typename Scalar >
|
|
struct TensorIntegration<Scalar,1,3>
|
|
{
|
|
Scalar pts[3] ;
|
|
Scalar wts[3] ;
|
|
|
|
TensorIntegration()
|
|
{
|
|
const Scalar x3 = 0.774596669 ;
|
|
const Scalar w1 = 0.555555556 ;
|
|
const Scalar w2 = 0.888888889 ;
|
|
pts[0] = -x3 ; wts[0] = w1 ;
|
|
pts[1] = 0 ; wts[1] = w2 ;
|
|
pts[2] = x3 ; wts[2] = w1 ;
|
|
}
|
|
};
|
|
|
|
template< typename Scalar , unsigned Order >
|
|
struct TensorIntegration<Scalar,3,Order>
|
|
{
|
|
static const unsigned N = Order * Order * Order ;
|
|
|
|
Scalar pts[N][3] ;
|
|
Scalar wts[N];
|
|
|
|
TensorIntegration()
|
|
{
|
|
TensorIntegration<Scalar,1,Order> oneD ;
|
|
|
|
unsigned n = 0 ;
|
|
for ( unsigned k = 0 ; k < Order ; ++k ) {
|
|
for ( unsigned j = 0 ; j < Order ; ++j ) {
|
|
for ( unsigned i = 0 ; i < Order ; ++i , ++n ) {
|
|
pts[n][0] = oneD.pts[i] ;
|
|
pts[n][1] = oneD.pts[j] ;
|
|
pts[n][2] = oneD.pts[k] ;
|
|
wts[n] = oneD.wts[i] * oneD.wts[j] * oneD.wts[k] ;
|
|
}}}
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
template< typename Scalar >
|
|
struct ShapeFunctionEvaluation {
|
|
|
|
static const unsigned FunctionCount = 8 ;
|
|
static const unsigned SpatialDimension = 3 ;
|
|
static const unsigned IntegrationOrder = 2 ;
|
|
|
|
typedef TensorIntegration< Scalar , SpatialDimension , IntegrationOrder >
|
|
TensorIntegrationType ;
|
|
|
|
static const unsigned PointCount = TensorIntegrationType::N ;
|
|
|
|
Scalar value [ PointCount ][ FunctionCount ] ;
|
|
Scalar gradient[ PointCount ][ FunctionCount * SpatialDimension ];
|
|
Scalar weight [ PointCount ];
|
|
|
|
ShapeFunctionEvaluation()
|
|
{
|
|
const TensorIntegration< Scalar , SpatialDimension , IntegrationOrder >
|
|
integration ;
|
|
|
|
const Scalar ONE8TH = 0.125 ;
|
|
|
|
for ( unsigned i = 0 ; i < PointCount ; ++i ) {
|
|
|
|
const Scalar u = 1.0 - integration.pts[i][0];
|
|
const Scalar v = 1.0 - integration.pts[i][1];
|
|
const Scalar w = 1.0 - integration.pts[i][2];
|
|
|
|
const Scalar up1 = 1.0 + integration.pts[i][0];
|
|
const Scalar vp1 = 1.0 + integration.pts[i][1];
|
|
const Scalar wp1 = 1.0 + integration.pts[i][2];
|
|
|
|
weight[i] = integration.wts[i] ;
|
|
|
|
// Vaues:
|
|
value[i][0] = ONE8TH * u * v * w ;
|
|
value[i][1] = ONE8TH * up1 * v * w ;
|
|
value[i][2] = ONE8TH * up1 * vp1 * w ;
|
|
value[i][3] = ONE8TH * u * vp1 * w ;
|
|
|
|
value[i][4] = ONE8TH * u * v * wp1 ;
|
|
value[i][5] = ONE8TH * up1 * v * wp1 ;
|
|
value[i][6] = ONE8TH * up1 * vp1 * wp1 ;
|
|
value[i][7] = ONE8TH * u * vp1 * wp1 ;
|
|
|
|
//fn 0 = u * v * w
|
|
gradient[i][ 0] = ONE8TH * -1 * v * w ;
|
|
gradient[i][ 1] = ONE8TH * u * -1 * w ;
|
|
gradient[i][ 2] = ONE8TH * u * v * -1 ;
|
|
|
|
//fn 1 = up1 * v * w
|
|
gradient[i][ 3] = ONE8TH * 1 * v * w ;
|
|
gradient[i][ 4] = ONE8TH * up1 * -1 * w ;
|
|
gradient[i][ 5] = ONE8TH * up1 * v * -1 ;
|
|
|
|
//fn 2 = up1 * vp1 * w
|
|
gradient[i][ 6] = ONE8TH * 1 * vp1 * w ;
|
|
gradient[i][ 7] = ONE8TH * up1 * 1 * w ;
|
|
gradient[i][ 8] = ONE8TH * up1 * vp1 * -1 ;
|
|
|
|
//fn 3 = u * vp1 * w
|
|
gradient[i][ 9] = ONE8TH * -1 * vp1 * w ;
|
|
gradient[i][10] = ONE8TH * u * 1 * w ;
|
|
gradient[i][11] = ONE8TH * u * vp1 * -1 ;
|
|
|
|
//fn 4 = u * v * wp1
|
|
gradient[i][12] = ONE8TH * -1 * v * wp1 ;
|
|
gradient[i][13] = ONE8TH * u * -1 * wp1 ;
|
|
gradient[i][14] = ONE8TH * u * v * 1 ;
|
|
|
|
//fn 5 = up1 * v * wp1
|
|
gradient[i][15] = ONE8TH * 1 * v * wp1 ;
|
|
gradient[i][16] = ONE8TH * up1 * -1 * wp1 ;
|
|
gradient[i][17] = ONE8TH * up1 * v * 1 ;
|
|
|
|
//fn 6 = up1 * vp1 * wp1
|
|
gradient[i][18] = ONE8TH * 1 * vp1 * wp1 ;
|
|
gradient[i][19] = ONE8TH * up1 * 1 * wp1 ;
|
|
gradient[i][20] = ONE8TH * up1 * vp1 * 1 ;
|
|
|
|
//fn 7 = u * vp1 * wp1
|
|
gradient[i][21] = ONE8TH * -1 * vp1 * wp1 ;
|
|
gradient[i][22] = ONE8TH * u * 1 * wp1 ;
|
|
gradient[i][23] = ONE8TH * u * vp1 * 1 ;
|
|
}
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
template< typename ScalarType , typename ScalarCoordType , class DeviceType >
|
|
struct ElementComputation
|
|
{
|
|
typedef DeviceType execution_space;
|
|
typedef ScalarType scalar_type ;
|
|
typedef typename execution_space::size_type size_type ;
|
|
|
|
static const size_type ElementNodeCount = 8 ;
|
|
|
|
typedef FEMesh< ScalarCoordType , ElementNodeCount , execution_space > mesh_type ;
|
|
typedef Kokkos::View< scalar_type[][ElementNodeCount][ElementNodeCount] , execution_space > elem_matrices_type ;
|
|
typedef Kokkos::View< scalar_type[][ElementNodeCount] , execution_space > elem_vectors_type ;
|
|
|
|
typedef ShapeFunctionEvaluation< scalar_type > shape_function_data ;
|
|
|
|
static const unsigned SpatialDim = shape_function_data::SpatialDimension ;
|
|
static const unsigned FunctionCount = shape_function_data::FunctionCount ;
|
|
|
|
private:
|
|
|
|
const shape_function_data shape_eval ;
|
|
typename mesh_type::elem_node_ids_type elem_node_ids ;
|
|
typename mesh_type::node_coords_type node_coords ;
|
|
elem_matrices_type element_matrices ;
|
|
elem_vectors_type element_vectors ;
|
|
scalar_type coeff_K ;
|
|
scalar_type coeff_Q ;
|
|
|
|
ElementComputation( const mesh_type & arg_mesh ,
|
|
const elem_matrices_type & arg_element_matrices ,
|
|
const elem_vectors_type & arg_element_vectors ,
|
|
const scalar_type arg_coeff_K ,
|
|
const scalar_type arg_coeff_Q )
|
|
: shape_eval()
|
|
, elem_node_ids( arg_mesh.elem_node_ids )
|
|
, node_coords( arg_mesh.node_coords )
|
|
, element_matrices( arg_element_matrices )
|
|
, element_vectors( arg_element_vectors )
|
|
, coeff_K( arg_coeff_K )
|
|
, coeff_Q( arg_coeff_Q )
|
|
{}
|
|
|
|
public:
|
|
|
|
static void apply( const mesh_type & mesh ,
|
|
const elem_matrices_type & elem_matrices ,
|
|
const elem_vectors_type & elem_vectors ,
|
|
const scalar_type elem_coeff_K ,
|
|
const scalar_type elem_coeff_Q )
|
|
{
|
|
ElementComputation comp( mesh , elem_matrices , elem_vectors , elem_coeff_K , elem_coeff_Q );
|
|
const size_t elem_count = mesh.elem_node_ids.dimension_0();
|
|
|
|
parallel_for( elem_count , comp );
|
|
}
|
|
|
|
//------------------------------------
|
|
|
|
static const unsigned FLOPS_jacobian =
|
|
FunctionCount * SpatialDim * SpatialDim * 2 ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void jacobian( const ScalarCoordType * x,
|
|
const ScalarCoordType * y,
|
|
const ScalarCoordType * z,
|
|
const scalar_type * grad_vals,
|
|
scalar_type * J) const
|
|
{
|
|
int i_grad = 0 ;
|
|
|
|
for( unsigned i = 0; i < ElementNodeCount ; ++i , i_grad += SpatialDim ) {
|
|
const scalar_type g0 = grad_vals[ i_grad ];
|
|
const scalar_type g1 = grad_vals[ i_grad + 1 ];
|
|
const scalar_type g2 = grad_vals[ i_grad + 2 ];
|
|
const scalar_type x0 = x[i] ;
|
|
const scalar_type x1 = y[i] ;
|
|
const scalar_type x2 = z[i] ;
|
|
|
|
J[0] += g0 * x0 ;
|
|
J[1] += g0 * x1 ;
|
|
J[2] += g0 * x2 ;
|
|
|
|
J[3] += g1 * x0 ;
|
|
J[4] += g1 * x1 ;
|
|
J[5] += g1 * x2 ;
|
|
|
|
J[6] += g2 * x0 ;
|
|
J[7] += g2 * x1 ;
|
|
J[8] += g2 * x2 ;
|
|
}
|
|
}
|
|
|
|
//------------------------------------
|
|
|
|
static const unsigned FLOPS_inverse_and_det = 46 ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
scalar_type inverse_and_determinant3x3( scalar_type * const J ) const
|
|
{
|
|
const scalar_type J00 = J[0];
|
|
const scalar_type J01 = J[1];
|
|
const scalar_type J02 = J[2];
|
|
|
|
const scalar_type J10 = J[3];
|
|
const scalar_type J11 = J[4];
|
|
const scalar_type J12 = J[5];
|
|
|
|
const scalar_type J20 = J[6];
|
|
const scalar_type J21 = J[7];
|
|
const scalar_type J22 = J[8];
|
|
|
|
const scalar_type term0 = J22*J11 - J21*J12;
|
|
const scalar_type term1 = J22*J01 - J21*J02;
|
|
const scalar_type term2 = J12*J01 - J11*J02;
|
|
|
|
const scalar_type detJ = J00*term0 - J10*term1 + J20*term2;
|
|
const scalar_type inv_detJ = 1.0/detJ;
|
|
|
|
J[0] = term0*inv_detJ;
|
|
J[1] = -term1*inv_detJ;
|
|
J[2] = term2*inv_detJ;
|
|
|
|
J[3] = -(J22*J10 - J20*J12)*inv_detJ;
|
|
J[4] = (J22*J00 - J20*J02)*inv_detJ;
|
|
J[5] = -(J12*J00 - J10*J02)*inv_detJ;
|
|
|
|
J[6] = (J21*J10 - J20*J11)*inv_detJ;
|
|
J[7] = -(J21*J00 - J20*J01)*inv_detJ;
|
|
J[8] = (J11*J00 - J10*J01)*inv_detJ;
|
|
|
|
return detJ ;
|
|
}
|
|
|
|
//------------------------------------
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void matTransMat3x3_X_3xn( const scalar_type * A, int n,
|
|
const scalar_type * B,
|
|
scalar_type * C ) const
|
|
{
|
|
//A is 3x3, B is 3xn. So C is also 3xn.
|
|
//A,B,C are all assumed to be ordered such that columns are contiguous.
|
|
|
|
scalar_type * Cj = C;
|
|
const scalar_type * Bj = B;
|
|
|
|
for(int j=0; j<n; ++j) {
|
|
Cj[0] = A[0]*Bj[0] + A[1]*Bj[1] + A[2]*Bj[2];
|
|
Cj[1] = A[3]*Bj[0] + A[4]*Bj[1] + A[5]*Bj[2];
|
|
Cj[2] = A[6]*Bj[0] + A[7]*Bj[1] + A[8]*Bj[2];
|
|
Bj += 3;
|
|
Cj += 3;
|
|
}
|
|
|
|
}
|
|
//------------------------------------
|
|
|
|
static const unsigned FLOPS_contributeDiffusionMatrix = FunctionCount * ( 3 * 5 + FunctionCount * 7 ) ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void contributeDiffusionMatrix(
|
|
const scalar_type weight ,
|
|
const scalar_type grad_vals[] ,
|
|
const scalar_type invJ[] ,
|
|
scalar_type elem_mat[][8] ) const
|
|
{
|
|
scalar_type dpsidx[8], dpsidy[8], dpsidz[8];
|
|
|
|
int i_grad = 0 ;
|
|
for( unsigned i = 0; i < FunctionCount ; ++i , i_grad += 3 ) {
|
|
const scalar_type g0 = grad_vals[i_grad+0];
|
|
const scalar_type g1 = grad_vals[i_grad+1];
|
|
const scalar_type g2 = grad_vals[i_grad+2];
|
|
|
|
dpsidx[i] = g0 * invJ[0] + g1 * invJ[1] + g2 * invJ[2];
|
|
dpsidy[i] = g0 * invJ[3] + g1 * invJ[4] + g2 * invJ[5];
|
|
dpsidz[i] = g0 * invJ[6] + g1 * invJ[7] + g2 * invJ[8];
|
|
}
|
|
|
|
for( unsigned m = 0; m < FunctionCount; m++) {
|
|
for( unsigned n = 0; n < FunctionCount; n++) {
|
|
|
|
elem_mat[m][n] += weight *
|
|
((dpsidx[m] * dpsidx[n]) +
|
|
(dpsidy[m] * dpsidy[n]) +
|
|
(dpsidz[m] * dpsidz[n]));
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------
|
|
|
|
static const unsigned FLOPS_contributeSourceVector = FunctionCount * 2 ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void contributeSourceVector( const scalar_type term ,
|
|
const scalar_type psi[] ,
|
|
scalar_type elem_vec[] ) const
|
|
{
|
|
for( unsigned i=0; i< FunctionCount ; ++i) {
|
|
elem_vec[i] += psi[i] * term ;
|
|
}
|
|
}
|
|
|
|
|
|
static const unsigned FLOPS_operator =
|
|
shape_function_data::PointCount * ( 3
|
|
+ FLOPS_jacobian
|
|
+ FLOPS_inverse_and_det
|
|
+ FLOPS_contributeDiffusionMatrix
|
|
+ FLOPS_contributeSourceVector ) ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( int ielem )const {
|
|
|
|
scalar_type elem_vec[8] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
|
|
scalar_type elem_mat[8][8] =
|
|
{ { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
|
|
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } };
|
|
|
|
ScalarCoordType x[8], y[8], z[8];
|
|
|
|
for ( int i = 0 ; i < 8 ; ++i ) {
|
|
const int node_index = elem_node_ids( ielem , i );
|
|
x[i] = node_coords( node_index , 0 );
|
|
y[i] = node_coords( node_index , 1 );
|
|
z[i] = node_coords( node_index , 2 );
|
|
}
|
|
|
|
// This loop could be parallelized; however,
|
|
// it would require additional per-thread temporaries
|
|
// of 'elem_vec' and 'elem_mat' which would
|
|
// consume more local memory and have to be reduced.
|
|
|
|
for ( unsigned i = 0 ; i < shape_function_data::PointCount ; ++i ) {
|
|
|
|
scalar_type J[SpatialDim*SpatialDim] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
jacobian( x, y, z, shape_eval.gradient[i] , J );
|
|
|
|
// Overwrite J with its inverse to save scratch memory space.
|
|
const scalar_type detJ_w = shape_eval.weight[i] * inverse_and_determinant3x3(J);
|
|
const scalar_type k_detJ_w = coeff_K * detJ_w ;
|
|
const scalar_type Q_detJ_w = coeff_Q * detJ_w ;
|
|
|
|
contributeDiffusionMatrix( k_detJ_w , shape_eval.gradient[i] , J , elem_mat );
|
|
|
|
contributeSourceVector( Q_detJ_w , shape_eval.value[i] , elem_vec );
|
|
}
|
|
|
|
for( size_type i=0; i< ElementNodeCount ; ++i) {
|
|
element_vectors(ielem, i) = elem_vec[i] ;
|
|
}
|
|
|
|
for( size_type i = 0; i < ElementNodeCount ; i++){
|
|
for( size_type j = 0; j < ElementNodeCount ; j++){
|
|
element_matrices(ielem, i, j) = elem_mat[i][j] ;
|
|
}
|
|
}
|
|
}
|
|
}; /* ElementComputation */
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
template< typename ScalarType , typename ScalarCoordType , class DeviceType >
|
|
struct DirichletBoundary
|
|
{
|
|
typedef DeviceType execution_space;
|
|
typedef typename execution_space::size_type size_type ;
|
|
|
|
static const size_type ElementNodeCount = 8 ;
|
|
|
|
typedef Kokkos::CrsMatrix< ScalarType , execution_space > matrix_type ;
|
|
typedef Kokkos::View< ScalarType[] , execution_space > vector_type ;
|
|
|
|
typedef FEMesh< ScalarCoordType , ElementNodeCount , execution_space > mesh_type ;
|
|
|
|
typename mesh_type::node_coords_type node_coords ;
|
|
matrix_type matrix ;
|
|
vector_type rhs ;
|
|
ScalarCoordType bc_lower_z ;
|
|
ScalarCoordType bc_upper_z ;
|
|
ScalarType bc_lower_value ;
|
|
ScalarType bc_upper_value ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( size_type inode ) const
|
|
{
|
|
// Apply a dirichlet boundary condition to 'irow'
|
|
// to maintain the symmetry of the original
|
|
// global stiffness matrix, zero out the columns
|
|
// that correspond to boundary conditions, and
|
|
// adjust the load vector accordingly
|
|
|
|
const size_type iBeg = matrix.graph.row_map[inode];
|
|
const size_type iEnd = matrix.graph.row_map[inode+1];
|
|
|
|
const ScalarCoordType z = node_coords(inode,2);
|
|
const bool bc_lower = z <= bc_lower_z ;
|
|
const bool bc_upper = bc_upper_z <= z ;
|
|
|
|
if ( bc_lower || bc_upper ) {
|
|
const ScalarType bc_value = bc_lower ? bc_lower_value
|
|
: bc_upper_value ;
|
|
|
|
rhs(inode) = bc_value ; // set the rhs vector
|
|
|
|
// zero each value on the row, and leave a one
|
|
// on the diagonal
|
|
|
|
for( size_type i = iBeg ; i < iEnd ; i++) {
|
|
matrix.coefficients(i) =
|
|
(int) inode == matrix.graph.entries(i) ? 1 : 0 ;
|
|
}
|
|
}
|
|
else {
|
|
// Find any columns that are boundary conditions.
|
|
// Clear them and adjust the load vector
|
|
|
|
for( size_type i = iBeg ; i < iEnd ; i++ ) {
|
|
const size_type cnode = matrix.graph.entries(i) ;
|
|
|
|
const ScalarCoordType zc = node_coords(cnode,2);
|
|
const bool c_bc_lower = zc <= bc_lower_z ;
|
|
const bool c_bc_upper = bc_upper_z <= zc ;
|
|
|
|
if ( c_bc_lower || c_bc_upper ) {
|
|
|
|
const ScalarType c_bc_value = c_bc_lower ? bc_lower_value
|
|
: bc_upper_value ;
|
|
|
|
rhs( inode ) -= c_bc_value * matrix.coefficients(i);
|
|
|
|
matrix.coefficients(i) = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void apply( const matrix_type & linsys_matrix ,
|
|
const vector_type & linsys_rhs ,
|
|
const mesh_type & mesh ,
|
|
const ScalarCoordType bc_lower_z ,
|
|
const ScalarCoordType bc_upper_z ,
|
|
const ScalarType bc_lower_value ,
|
|
const ScalarType bc_upper_value )
|
|
{
|
|
const size_t row_count = linsys_matrix.graph.row_map.dimension_0() - 1 ;
|
|
DirichletBoundary op ;
|
|
op.node_coords = mesh.node_coords ;
|
|
op.matrix = linsys_matrix ;
|
|
op.rhs = linsys_rhs ;
|
|
op.bc_lower_z = bc_lower_z ;
|
|
op.bc_upper_z = bc_upper_z ;
|
|
op.bc_lower_value = bc_lower_value ;
|
|
op.bc_upper_value = bc_upper_value ;
|
|
parallel_for( row_count , op );
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
} /* namespace Implicit */
|
|
} /* namespace HybridFEM */
|
|
|