//----------------------------------------------------------------------------- CoordinateMatrix::CoordinateMatrix(const GenericMatrix& A, bool symmetric, bool base_one) : _symmetric(symmetric), _base_one(base_one) { _size[0] = A.size(0); _size[1] = A.size(1); // Iterate over local rows const std::pair<std::size_t, std::size_t> local_row_range = A.local_range(0); if (!_symmetric) { for (std::size_t i = local_row_range.first; i < local_row_range.second; ++i) { // Get column and value data for row std::vector<std::size_t> columns; std::vector<double> values; A.getrow(i, columns, values); // Insert data at end _rows.insert(_rows.end(), columns.size(), i); _cols.insert(_cols.end(), columns.begin(), columns.end()); _vals.insert(_vals.end(), values.begin(), values.end()); } assert(_rows.size() == _cols.size()); } else { assert(_size[0] == _size[1]); for (std::size_t i = local_row_range.first; i < local_row_range.second; ++i) { // Get column and value data for row std::vector<std::size_t> columns; std::vector<double> values; A.getrow(i, columns, values); for (std::size_t j = 0; j < columns.size(); ++j) { if (columns[j] >= i) { _rows.push_back(i); _cols.push_back(columns[j]); _vals.push_back(values[j]); } } } assert(_rows.size() == _cols.size()); } // Add 1 for Fortran-style indices if (base_one) { for (std::size_t i = 0; i < _cols.size(); ++i) { _rows[i]++; _cols[i]++; } } }
void compute_DG0_to_CG_weight_matrix(GenericMatrix& A, Function& DG) { compute_weight(DG); std::vector<std::size_t> columns; std::vector<double> values; std::vector<std::vector<std::size_t> > allcolumns; std::vector<std::vector<double> > allvalues; const std::pair<std::size_t, std::size_t> row_range = A.local_range(0); const std::size_t m = row_range.second - row_range.first; GenericVector& weight = *DG.vector(); const std::pair<std::size_t, std::size_t> weight_range = weight.local_range(); std::vector<std::size_t> weight_range_vec(2); weight_range_vec[0] = weight_range.first; weight_range_vec[1] = weight_range.second; int dm = weight_range.second-weight_range.first; const MPI_Comm mpi_comm = DG.function_space()->mesh()->mpi_comm(); // Communicate local_ranges of weights std::vector<std::vector<std::size_t> > all_ranges; MPI::all_gather(mpi_comm, weight_range_vec, all_ranges); // Number of MPI processes std::size_t num_processes = MPI::size(mpi_comm); // Some weights live on other processes and need to be communicated // Create list of off-process weights std::vector<std::vector<std::size_t> > dofs_needed(num_processes); for (std::size_t row = 0; row < m; row++) { // Get global row number const std::size_t global_row = row + row_range.first; A.getrow(global_row, columns, values); for (std::size_t i = 0; i < columns.size(); i++) { std::size_t dof = columns[i]; if (dof < weight_range.first || dof >= weight_range.second) { std::size_t owner = dof_owner(all_ranges, dof); dofs_needed[owner].push_back(dof); } } } // Communicate to all which weights are needed by the process std::vector<std::vector<std::size_t> > dofs_needed_recv; MPI::all_to_all(mpi_comm, dofs_needed, dofs_needed_recv); // Fetch the weights that must be communicated std::vector<std::vector<double> > weights_to_send(num_processes); for (std::size_t p = 0; p < num_processes; p++) { if (p == MPI::rank(mpi_comm)) continue; std::vector<std::size_t> dofs = dofs_needed_recv[p]; std::map<std::size_t, double> send_weights; for (std::size_t k = 0; k < dofs.size(); k++) { weights_to_send[p].push_back(weight[dofs[k]-weight_range.first]); } } std::vector<std::vector<double> > weights_to_send_recv; MPI::all_to_all(mpi_comm, weights_to_send, weights_to_send_recv); // Create a map for looking up received weights std::map<std::size_t, double> received_weights; for (std::size_t p = 0; p < num_processes; p++) { if (p == MPI::rank(mpi_comm)) continue; for (std::size_t k = 0; k < dofs_needed[p].size(); k++) { received_weights[dofs_needed[p][k]] = weights_to_send_recv[p][k]; } } for (std::size_t row = 0; row < m; row++) { // Get global row number const std::size_t global_row = row + row_range.first; A.getrow(global_row, columns, values); for (std::size_t i = 0; i < values.size(); i++) { std::size_t dof = columns[i]; if (dof < weight_range.first || dof >= weight_range.second) { values[i] = received_weights[dof]; } else { values[i] = weight[columns[i]-weight_range.first]; } // values[i] = 1./values[i]; } double s = std::accumulate(values.begin(), values.end(), 0.0); std::transform(values.begin(), values.end(), values.begin(), std::bind2nd(std::multiplies<double>(), 1./s)); for (std::size_t i=0; i<values.size(); i++) { double w; std::size_t dof = columns[i]; if (dof < weight_range.first || dof >= weight_range.second) { w = received_weights[dof]; } else { w = weight[dof-weight_range.first]; } values[i] = values[i]*w; // values[i] = values[i]*values[i]; } allvalues.push_back(values); allcolumns.push_back(columns); } for (std::size_t row = 0; row < m; row++) { // Get global row number const std::size_t global_row = row + row_range.first; A.setrow(global_row, allcolumns[row], allvalues[row]); } A.apply("insert"); }
//----------------------------------------------------------------------------- void DirichletBC::zero_columns(GenericMatrix& A, GenericVector& b, double diag_val) const { // Check arguments check_arguments(&A, &b, NULL, 1); // A map to hold the mapping from boundary dofs to boundary values Map bv_map; get_boundary_values(bv_map); // Create lookup table of dofs //const std::size_t nrows = A.size(0); // should be equal to b.size() const std::size_t ncols = A.size(1); // should be equal to max possible dof+1 std::pair<std::size_t, std::size_t> rows = A.local_range(0); std::vector<char> is_bc_dof(ncols); std::vector<double> bc_dof_val(ncols); for (Map::const_iterator bv = bv_map.begin(); bv != bv_map.end(); ++bv) { is_bc_dof[bv->first] = 1; bc_dof_val[bv->first] = bv->second; } // Scan through all columns of all rows, setting to zero if // is_bc_dof[column]. At the same time, we collect corrections to // the RHS std::vector<std::size_t> cols; std::vector<double> vals; std::vector<double> b_vals; std::vector<dolfin::la_index> b_rows; for (std::size_t row = rows.first; row < rows.second; row++) { // If diag_val is nonzero, the matrix is a diagonal block // (nrows==ncols), and we can set the whole BC row if (diag_val != 0.0 && is_bc_dof[row]) { A.getrow(row, cols, vals); for (std::size_t j = 0; j < cols.size(); j++) vals[j] = (cols[j] == row)*diag_val; A.setrow(row, cols, vals); A.apply("insert"); b.setitem(row, bc_dof_val[row]*diag_val); } else // Otherwise, we scan the row for BC columns { A.getrow(row, cols, vals); bool row_changed = false; for (std::size_t j = 0; j < cols.size(); j++) { const std::size_t col = cols[j]; // Skip columns that aren't BC, and entries that are zero if (!is_bc_dof[col] || vals[j] == 0.0) continue; // We're going to change the row, so make room for it if (!row_changed) { row_changed = true; b_rows.push_back(row); b_vals.push_back(0.0); } b_vals.back() -= bc_dof_val[col]*vals[j]; vals[j] = 0.0; } if (row_changed) { A.setrow(row, cols, vals); A.apply("insert"); } } } b.add_local(&b_vals.front(), b_rows.size(), &b_rows.front()); b.apply("add"); }