#ifndef _SparseMatrix_functions_hpp_ #define _SparseMatrix_functions_hpp_ //@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 #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MINIFE_HAVE_TBB #include #endif #ifdef HAVE_MPI #include #endif namespace miniFE { template void init_matrix(MatrixType& M, const std::vector& rows, const std::vector& row_offsets, const std::vector& row_coords, int global_nodes_x, int global_nodes_y, int global_nodes_z, typename MatrixType::GlobalOrdinalType global_nrows, const simple_mesh_description& mesh) { MatrixInitOp mat_init(rows, row_offsets, row_coords, global_nodes_x, global_nodes_y, global_nodes_z, global_nrows, mesh, M); for(int i=0; i void sort_with_companions(ptrdiff_t len, T* array, U* companions) { ptrdiff_t i, j, index; U companion; for (i=1; i < len; i++) { index = array[i]; companion = companions[i]; j = i; while ((j > 0) && (array[j-1] > index)) { array[j] = array[j-1]; companions[j] = companions[j-1]; j = j - 1; } array[j] = index; companions[j] = companion; } } template void write_matrix(const std::string& filename, MatrixType& mat) { typedef typename MatrixType::LocalOrdinalType LocalOrdinalType; typedef typename MatrixType::GlobalOrdinalType GlobalOrdinalType; typedef typename MatrixType::ScalarType ScalarType; int numprocs = 1, myproc = 0; #ifdef HAVE_MPI MPI_Comm_size(MPI_COMM_WORLD, &numprocs); MPI_Comm_rank(MPI_COMM_WORLD, &myproc); #endif std::ostringstream osstr; osstr << filename << "." << numprocs << "." << myproc; std::string full_name = osstr.str(); std::ofstream ofs(full_name.c_str()); size_t nrows = mat.rows.size(); size_t nnz = mat.num_nonzeros(); for(int p=0; p void sum_into_row(int row_len, GlobalOrdinal* row_indices, Scalar* row_coefs, int num_inputs, const GlobalOrdinal* input_indices, const Scalar* input_coefs) { for(size_t i=0; i void sum_into_row(typename MatrixType::GlobalOrdinalType row, size_t num_indices, const typename MatrixType::GlobalOrdinalType* col_inds, const typename MatrixType::ScalarType* coefs, MatrixType& mat) { typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; typedef typename MatrixType::ScalarType Scalar; size_t row_len = 0; GlobalOrdinal* mat_row_cols = NULL; Scalar* mat_row_coefs = NULL; mat.get_row_pointers(row, row_len, mat_row_cols, mat_row_coefs); if (row_len == 0) return; sum_into_row(row_len, mat_row_cols, mat_row_coefs, num_indices, col_inds, coefs); } template void sum_in_symm_elem_matrix(size_t num, const typename MatrixType::GlobalOrdinalType* indices, const typename MatrixType::ScalarType* coefs, MatrixType& mat) { typedef typename MatrixType::ScalarType Scalar; typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; //indices is length num (which should be nodes-per-elem) //coefs is the upper triangle of the element diffusion matrix //which should be length num*(num+1)/2 //std::cout< void sum_in_elem_matrix(size_t num, const typename MatrixType::GlobalOrdinalType* indices, const typename MatrixType::ScalarType* coefs, MatrixType& mat) { size_t offset = 0; for(size_t i=0; i void sum_into_global_linear_system(ElemData& elem_data, MatrixType& A, VectorType& b) { sum_in_symm_elem_matrix(elem_data.nodes_per_elem, elem_data.elem_node_ids, elem_data.elem_diffusion_matrix, A); sum_into_vector(elem_data.nodes_per_elem, elem_data.elem_node_ids, elem_data.elem_source_vector, b); } #ifdef MINIFE_HAVE_TBB template void sum_in_elem_matrix(size_t num, const typename MatrixType::GlobalOrdinalType* indices, const typename MatrixType::ScalarType* coefs, LockingMatrix& mat) { size_t offset = 0; for(size_t i=0; i void sum_into_global_linear_system(ElemData& elem_data, LockingMatrix& A, LockingVector& b) { sum_in_elem_matrix(elem_data.nodes_per_elem, elem_data.elem_node_ids, elem_data.elem_diffusion_matrix, A); sum_into_vector(elem_data.nodes_per_elem, elem_data.elem_node_ids, elem_data.elem_source_vector, b); } #endif template void add_to_diagonal(typename MatrixType::ScalarType value, MatrixType& mat) { for(size_t i=0; i double parallel_memory_overhead_MB(const MatrixType& A) { typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; typedef typename MatrixType::LocalOrdinalType LocalOrdinal; double mem_MB = 0; #ifdef HAVE_MPI double invMB = 1.0/(1024*1024); mem_MB = invMB*A.external_index.size()*sizeof(GlobalOrdinal); mem_MB += invMB*A.external_local_index.size()*sizeof(GlobalOrdinal); mem_MB += invMB*A.elements_to_send.size()*sizeof(GlobalOrdinal); mem_MB += invMB*A.neighbors.size()*sizeof(int); mem_MB += invMB*A.recv_length.size()*sizeof(LocalOrdinal); mem_MB += invMB*A.send_length.size()*sizeof(LocalOrdinal); double tmp = mem_MB; MPI_Allreduce(&tmp, &mem_MB, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #endif return mem_MB; } template void rearrange_matrix_local_external(MatrixType& A) { //This function will rearrange A so that local entries are contiguous at the front //of A's memory, and external entries are contiguous at the back of A's memory. // //A.row_offsets will describe where the local entries occur, and //A.row_offsets_external will describe where the external entries occur. typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; typedef typename MatrixType::LocalOrdinalType LocalOrdinal; typedef typename MatrixType::ScalarType Scalar; size_t nrows = A.rows.size(); std::vector tmp_row_offsets(nrows*2); std::vector tmp_row_offsets_external(nrows*2); LocalOrdinal num_local_nz = 0; LocalOrdinal num_extern_nz = 0; //First sort within each row of A, so that local entries come //before external entries within each row. //tmp_row_offsets describe the locations of the local entries, and //tmp_row_offsets_external describe the locations of the external entries. // for(size_t i=0; i ext_cols(num_extern_nz); std::vector ext_coefs(num_extern_nz); std::vector ext_offsets(nrows+1); LocalOrdinal offset = 0; for(size_t i=0; i void zero_row_and_put_1_on_diagonal(MatrixType& A, typename MatrixType::GlobalOrdinalType row) { typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; typedef typename MatrixType::LocalOrdinalType LocalOrdinal; typedef typename MatrixType::ScalarType Scalar; size_t row_len = 0; GlobalOrdinal* cols = NULL; Scalar* coefs = NULL; A.get_row_pointers(row, row_len, cols, coefs); for(size_t i=0; i void impose_dirichlet(typename MatrixType::ScalarType prescribed_value, MatrixType& A, VectorType& b, int global_nx, int global_ny, int global_nz, const std::set& bc_rows) { typedef typename MatrixType::GlobalOrdinalType GlobalOrdinal; typedef typename MatrixType::LocalOrdinalType LocalOrdinal; typedef typename MatrixType::ScalarType Scalar; GlobalOrdinal first_local_row = A.rows.size()>0 ? A.rows[0] : 0; GlobalOrdinal last_local_row = A.rows.size()>0 ? A.rows[A.rows.size()-1] : -1; typename std::set::const_iterator bc_iter = bc_rows.begin(), bc_end = bc_rows.end(); for(; bc_iter!=bc_end; ++bc_iter) { GlobalOrdinal row = *bc_iter; if (row >= first_local_row && row <= last_local_row) { size_t local_row = row - first_local_row; b.coefs[local_row] = prescribed_value; zero_row_and_put_1_on_diagonal(A, row); } } for(size_t i=0; i typename TypeTraits::magnitude_type matvec_and_dot(MatrixType& A, VectorType& x, VectorType& y) { timer_type t0 = mytimer(); exchange_externals(A, x); exchtime += mytimer()-t0; typedef typename TypeTraits::magnitude_type magnitude; typedef typename MatrixType::ScalarType ScalarType; typedef typename MatrixType::GlobalOrdinalType GlobalOrdinalType; typedef typename MatrixType::LocalOrdinalType LocalOrdinalType; int n = A.rows.size(); const LocalOrdinalType* Arowoffsets = &A.row_offsets[0]; const GlobalOrdinalType* Acols = &A.packed_cols[0]; const ScalarType* Acoefs = &A.packed_coefs[0]; const ScalarType* xcoefs = &x.coefs[0]; ScalarType* ycoefs = &y.coefs[0]; ScalarType beta = 0; magnitude result = 0; for(int row=0; row::mpi_type(); MPI_Allreduce(&local_dot, &global_dot, 1, mpi_dtype, MPI_SUM, MPI_COMM_WORLD); return global_dot; #else return result; #endif } //------------------------------------------------------------------------ //Compute matrix vector product y = A*x where: // // A - input matrix // x - input vector // y - result vector // #if defined(MINIFE_CSR_MATRIX) template struct matvec_std { void operator()(MatrixType& A, VectorType& x, VectorType& y) { exchange_externals(A, x); typedef typename MatrixType::ScalarType ScalarType; typedef typename MatrixType::GlobalOrdinalType GlobalOrdinalType; typedef typename MatrixType::LocalOrdinalType LocalOrdinalType; int n = A.rows.size(); const LocalOrdinalType* Arowoffsets = &A.row_offsets[0]; const GlobalOrdinalType* Acols = &A.packed_cols[0]; const ScalarType* Acoefs = &A.packed_coefs[0]; const ScalarType* xcoefs = &x.coefs[0]; ScalarType* ycoefs = &y.coefs[0]; ScalarType beta = 0; for(int row=0; row