blob: 3197a2e698319b3b4a6bfe303e09749fabdde6db [file] [log] [blame]
//@HEADER
// ************************************************************************
//
// MiniFE: Simple Finite Element Assembly and Solve
// Copyright (2006-2013) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
// ************************************************************************
//@HEADER
#ifndef _MatrixInitOp_hpp_
#define _MatrixInitOp_hpp_
#include <simple_mesh_description.hpp>
#include <box_utils.hpp>
#include <CSRMatrix.hpp>
#include <ELLMatrix.hpp>
#include <algorithm>
template<typename GlobalOrdinal>
void sort_if_needed(GlobalOrdinal* list,
GlobalOrdinal list_len)
{
bool need_to_sort = false;
for(GlobalOrdinal i=list_len-1; i>=1; --i) {
if (list[i] < list[i-1]) {
need_to_sort = true;
break;
}
}
if (need_to_sort) {
std::sort(list,list+list_len);
}
}
template<typename MatrixType>
struct MatrixInitOp {
};
template<>
struct MatrixInitOp<miniFE::CSRMatrix<MINIFE_SCALAR,MINIFE_LOCAL_ORDINAL,MINIFE_GLOBAL_ORDINAL> > {
MatrixInitOp(const std::vector<MINIFE_GLOBAL_ORDINAL>& rows_vec,
const std::vector<MINIFE_LOCAL_ORDINAL>& row_offsets_vec,
const std::vector<int>& row_coords_vec,
int global_nx, int global_ny, int global_nz,
MINIFE_GLOBAL_ORDINAL global_n_rows,
const miniFE::simple_mesh_description<MINIFE_GLOBAL_ORDINAL>& input_mesh,
miniFE::CSRMatrix<MINIFE_SCALAR,MINIFE_LOCAL_ORDINAL,MINIFE_GLOBAL_ORDINAL>& matrix)
: rows(&rows_vec[0]),
row_offsets(&row_offsets_vec[0]),
row_coords(&row_coords_vec[0]),
global_nodes_x(global_nx),
global_nodes_y(global_ny),
global_nodes_z(global_nz),
global_nrows(global_n_rows),
mesh(&input_mesh),
dest_rows(&matrix.rows[0]),
dest_rowoffsets(&matrix.row_offsets[0]),
dest_cols(&matrix.packed_cols[0]),
dest_coefs(&matrix.packed_coefs[0]),
n(matrix.rows.size())
{
if (matrix.packed_cols.capacity() != matrix.packed_coefs.capacity()) {
std::cout<<"Warning, packed_cols.capacity ("<<matrix.packed_cols.capacity()<<") != "
<< "packed_coefs.capacity ("<<matrix.packed_coefs.capacity()<<")"<<std::endl;
}
size_t nnz = row_offsets_vec[n];
if (matrix.packed_cols.capacity() < nnz) {
std::cout<<"Warning, packed_cols.capacity ("<<matrix.packed_cols.capacity()<<") < "
" nnz ("<<nnz<<")"<<std::endl;
}
matrix.packed_cols.resize(nnz);
matrix.packed_coefs.resize(nnz);
dest_rowoffsets[n] = nnz;
#ifdef HAVE_MPI
MPI_Comm_rank(MPI_COMM_WORLD, &proc);
#else
proc = 0;
#endif
}
typedef MINIFE_GLOBAL_ORDINAL GlobalOrdinalType;
typedef MINIFE_LOCAL_ORDINAL LocalOrdinalType;
typedef MINIFE_SCALAR ScalarType;
const GlobalOrdinalType* rows;
const LocalOrdinalType* row_offsets;
const int* row_coords;
int global_nodes_x;
int global_nodes_y;
int global_nodes_z;
GlobalOrdinalType global_nrows;
GlobalOrdinalType* dest_rows;
LocalOrdinalType* dest_rowoffsets;
GlobalOrdinalType* dest_cols;
ScalarType* dest_coefs;
int n;
int proc;
const miniFE::simple_mesh_description<GlobalOrdinalType>* mesh;
inline void operator()(int i)
{
dest_rows[i] = rows[i];
int offset = row_offsets[i];
dest_rowoffsets[i] = offset;
int ix = row_coords[i*3];
int iy = row_coords[i*3+1];
int iz = row_coords[i*3+2];
GlobalOrdinalType nnz = 0;
for(int sz=-1; sz<=1; ++sz) {
for(int sy=-1; sy<=1; ++sy) {
for(int sx=-1; sx<=1; ++sx) {
GlobalOrdinalType col_id =
miniFE::get_id<GlobalOrdinalType>(global_nodes_x, global_nodes_y, global_nodes_z,
ix+sx, iy+sy, iz+sz);
if (col_id >= 0 && col_id < global_nrows) {
GlobalOrdinalType col = mesh->map_id_to_row(col_id);
if (col >= global_nrows) {
std::cout << "mesh->map_id_to_row produced col="<<col<<" from col_id="<<col_id<<", but global_nrows="<<global_nrows<<", max_row_in_map="<<mesh->max_row_in_map()<<", proc="<<proc<<std::endl;
}
dest_cols[offset+nnz] = col;
dest_coefs[offset+nnz] = 0;
++nnz;
}
}
}
}
sort_if_needed(&dest_cols[offset], nnz);
}
};
template<>
struct MatrixInitOp<miniFE::ELLMatrix<MINIFE_SCALAR,MINIFE_LOCAL_ORDINAL,MINIFE_GLOBAL_ORDINAL> > {
MatrixInitOp(const std::vector<MINIFE_GLOBAL_ORDINAL>& rows_vec,
const std::vector<MINIFE_LOCAL_ORDINAL>& /*row_offsets_vec*/,
const std::vector<int>& row_coords_vec,
int global_nx, int global_ny, int global_nz,
MINIFE_GLOBAL_ORDINAL global_n_rows,
const miniFE::simple_mesh_description<MINIFE_GLOBAL_ORDINAL>& input_mesh,
miniFE::ELLMatrix<MINIFE_SCALAR,MINIFE_LOCAL_ORDINAL,MINIFE_GLOBAL_ORDINAL>& matrix)
: rows(&rows_vec[0]),
row_coords(&row_coords_vec[0]),
global_nodes_x(global_nx),
global_nodes_y(global_ny),
global_nodes_z(global_nz),
global_nrows(global_n_rows),
mesh(&input_mesh),
dest_rows(&matrix.rows[0]),
dest_cols(&matrix.cols[0]),
dest_coefs(&matrix.coefs[0]),
n(matrix.rows.size()),
ncols_per_row(matrix.num_cols_per_row)
{
}
typedef MINIFE_GLOBAL_ORDINAL GlobalOrdinalType;
typedef MINIFE_LOCAL_ORDINAL LocalOrdinalType;
typedef MINIFE_SCALAR ScalarType;
const GlobalOrdinalType* rows;
const int* row_coords;
int global_nodes_x;
int global_nodes_y;
int global_nodes_z;
GlobalOrdinalType global_nrows;
GlobalOrdinalType* dest_rows;
GlobalOrdinalType* dest_cols;
ScalarType* dest_coefs;
int n;
int ncols_per_row;
const miniFE::simple_mesh_description<GlobalOrdinalType>* mesh;
inline void operator()(int i)
{
dest_rows[i] = rows[i];
int offset = i*ncols_per_row;
int ix = row_coords[i*3];
int iy = row_coords[i*3+1];
int iz = row_coords[i*3+2];
GlobalOrdinalType nnz = 0;
for(int sz=-1; sz<=1; ++sz)
for(int sy=-1; sy<=1; ++sy)
for(int sx=-1; sx<=1; ++sx) {
GlobalOrdinalType col_id =
miniFE::get_id<GlobalOrdinalType>(global_nodes_x, global_nodes_y, global_nodes_z,
ix+sx, iy+sy, iz+sz);
if (col_id >= 0 && col_id < global_nrows) {
GlobalOrdinalType col = mesh->map_id_to_row(col_id);
dest_cols[offset+nnz] = col;
dest_coefs[offset+nnz] = 0;
++nnz;
}
}
sort_if_needed(&dest_cols[offset], nnz);
}
};
#endif