//----------------------------------------------------------------------------- void DofMap::set(GenericVector& x, double value) const { dolfin_assert(_dofmap.size() % _cell_dimension == 0); const std::size_t num_cells = _dofmap.size() / _cell_dimension; std::vector<double> _value(_cell_dimension, value); for (std::size_t i = 0; i < num_cells; ++i) { const ArrayView<const la_index> dofs = cell_dofs(i); x.set_local(_value.data(), dofs.size(), dofs.data()); } x.apply("insert"); }
//----------------------------------------------------------------------------- std::size_t MUMPSLUSolver::solve(GenericVector& x, const GenericVector& b) { dolfin_assert(_matA); DMUMPS_STRUC_C data; data.comm_fortran = -987654; // Initialise data.job = -1; // Host participates in solve data.par = 1; // Output related parameters //data.ICNTL(1) = 6; // error messages //data.ICNTL(2) = 0; //data.ICNTL(3) = 6; // Global information //data.ICNTL(3) = 6; // Global information if (parameters["verbose"]) data.ICNTL(4) = 2; else data.ICNTL(4) = 1; // Matrix symmetry (0=non-symmetric, 2=symmetric positive defn, 2=symmetric) data.sym = 0; if (parameters["symmetric"]) data.sym = 2; // Initialise MUMPS dmumps_c(&data); // Related to use of ScaLAPACK (+/-. Negative is faster?) //data.ICNTL(13) = -1; // Solve transpose (1: A x = b, otherwise A^T x = b) data.ICNTL(9) = 1; // FIXME (20=default) data.ICNTL(14) = 20; // Reordering (7=automatic) data.ICNTL(7) = 7; // Control solution vector (0=solution on root, 1=solution distributed) data.ICNTL(21) = 1; // Distributed matrix data.ICNTL(18) = 3; // Parallel/serial analysis (0=auto, 1=serial, 2=parallel) if (MPI::size(_matA->mpi_comm()) > 1) data.ICNTL(28) = 2; else data.ICNTL(28) = 0; // Parallel graph partitioning library (0=auto, 1=pt-scotch, 2=parmetis) data.ICNTL(29) = 0; // Global size dolfin_assert(_matA->size(0) == _matA->size(1)); data.n = _matA->size(0); if (!_matA->base_one()) dolfin_error("MUMPSLUSolver.cpp", "initialize solver", "MUMPS requires a CoordinateMatrix with Fortran-style " "base 1 indexing"); // Get matrix coordinate and value data const std::vector<std::size_t>& rows = _matA->rows(); const std::vector<std::size_t>& cols = _matA->columns(); const std::vector<double>& vals = _matA->values(); // Number of non-zero entries on this process data.nz_loc = rows.size(); // Pass matrix data to MUMPS. Trust MUMPS not to change it data.irn_loc = const_cast<int*>(reinterpret_cast<const int*>(rows.data())); data.jcn_loc = const_cast<int*>(reinterpret_cast<const int*>(cols.data())); data.a_loc = const_cast<double*>(vals.data()); // Analyse and factorize data.job = 4; dmumps_c(&data); if (data.INFOG(1) < 0) dolfin_error("MUMPSLUSolver.cpp", "compute matrix factors", "MUMPS reported an error during the analysis and " "factorisation"); cout << "Factorisation finished" << endl; // Gather RHS on root process and attach std::vector<double> _b; b.gather_on_zero(_b); data.rhs = _b.data(); // Scaling strategy (77 is default) data.ICNTL(8) = 77; // Get size of local solution vector x and create objects to hold solution const std::size_t local_x_size = data.INFO(23); std::vector<int> x_local_indices(local_x_size); std::vector<double> x_local_vals(local_x_size); // Attach solution data to MUMPS object data.lsol_loc = local_x_size; data.sol_loc = x_local_vals.data(); data.isol_loc = x_local_indices.data(); // Solve problem data.job = 3; dmumps_c(&data); if (data.INFOG(1) < 0) dolfin_error("MUMPSLUSolver.cpp", "compute matrix factors", "MUMPS reported an error during the solve"); // Shift indices by -1 for (std::size_t i = 0; i < local_x_size ; ++i) x_local_indices[i]--; // Set x values #if defined(PETSC_USE_64BIT_INDICES) // Cast indices to 64 bit std::vector<dolfin::la_index> _x_local_indices(x_local_indices.begin(), x_local_indices.end()); x.set_local(x_local_vals.data(), x_local_indices.size(), _x_local_indices.data()); #else x.set_local(x_local_vals.data(), x_local_indices.size(), x_local_indices.data()); #endif x.apply("insert"); // Clean up data.job = -2; dmumps_c(&data); return 1; }
//----------------------------------------------------------------------------- void FunctionSpace::interpolate(GenericVector& expansion_coefficients, const GenericFunction& v) const { dolfin_assert(_mesh); dolfin_assert(_element); dolfin_assert(_dofmap); // Check that function ranks match if (_element->value_rank() != v.value_rank()) { dolfin_error("FunctionSpace.cpp", "interpolate function into function space", "Rank of function (%d) does not match rank of function space (%d)", v.value_rank(), element()->value_rank()); } // Check that function dims match for (std::size_t i = 0; i < _element->value_rank(); ++i) { if (_element->value_dimension(i) != v.value_dimension(i)) { dolfin_error("FunctionSpace.cpp", "interpolate function into function space", "Dimension %d of function (%d) does not match dimension %d of function space (%d)", i, v.value_dimension(i), i, element()->value_dimension(i)); } } // Initialize vector of expansion coefficients if (expansion_coefficients.size() != _dofmap->global_dimension()) { dolfin_error("FunctionSpace.cpp", "interpolate function into function space", "Wrong size of vector"); } expansion_coefficients.zero(); // Initialize local arrays std::vector<double> cell_coefficients(_dofmap->max_element_dofs()); // Iterate over mesh and interpolate on each cell ufc::cell ufc_cell; std::vector<double> vertex_coordinates; for (CellIterator cell(*_mesh); !cell.end(); ++cell) { // Update to current cell cell->get_vertex_coordinates(vertex_coordinates); cell->get_cell_data(ufc_cell); // Restrict function to cell v.restrict(cell_coefficients.data(), *_element, *cell, vertex_coordinates.data(), ufc_cell); // Tabulate dofs const ArrayView<const dolfin::la_index> cell_dofs = _dofmap->cell_dofs(cell->index()); // Copy dofs to vector expansion_coefficients.set_local(cell_coefficients.data(), _dofmap->num_element_dofs(cell->index()), cell_dofs.data()); } // Finalise changes expansion_coefficients.apply("insert"); }
//---------------------------------------------------------------------------- void LocalSolver::solve_local(GenericVector& x, const GenericVector& b, const GenericDofMap& dofmap_b) const { dolfin_assert(_a); dolfin_assert(_a->rank() == 2); // Extract mesh dolfin_assert(_a->function_space(0)->mesh()); const Mesh& mesh = *_a->function_space(0)->mesh(); // Check whether to use cache for factorizations const bool use_cache = _cholesky_cache.empty() and _lu_cache.empty() ? false : true; // Create UFC object UFC ufc_a(*_a); // Get cell integral std::shared_ptr<ufc::cell_integral> integral_a = ufc_a.default_cell_integral; dolfin_assert(integral_a); // Get dofmaps std::array<std::shared_ptr<const GenericDofMap>, 2> dofmaps_a = {{_a->function_space(0)->dofmap(), _a->function_space(1)->dofmap()}}; dolfin_assert(dofmaps_a[0] and dofmaps_a[1]); // Check dimensions dolfin_assert(dofmaps_a[0]->global_dimension() == dofmaps_a[1]->global_dimension()); dolfin_assert(dofmaps_a[0]->global_dimension() == dofmap_b.global_dimension()); // Eigen data structures for local tensors Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A_e; Eigen::VectorXd b_e, x_e; // Eigen factorizations Eigen::PartialPivLU<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> lu; Eigen::LLT<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> cholesky; // Assemble LHS over cells and solve Progress p("Performing local (cell-wise) solve", mesh.num_cells()); ufc::cell ufc_cell; std::vector<double> vertex_coordinates; for (CellIterator cell(mesh); !cell.end(); ++cell) { // Get cell dofmaps const ArrayView<const dolfin::la_index> dofs_L = dofmap_b.cell_dofs(cell->index()); const ArrayView<const dolfin::la_index> dofs_a0 = dofmaps_a[0]->cell_dofs(cell->index()); // Check dimensions dolfin_assert(dofs_L.size() == dofs_a0.size()); // Copy global RHS data into local RHS b_e.resize(dofs_L.size()); b.get_local(b_e.data(), dofs_L.size(), dofs_L.data()); // Solve local problem if (!use_cache) { // Update to current cell cell->get_vertex_coordinates(vertex_coordinates); cell->get_cell_data(ufc_cell); // Update LHS UFC object ufc_a.update(*cell, vertex_coordinates, ufc_cell, integral_a->enabled_coefficients()); // Resize A_e and tabulate on for cell const std::size_t dim = dofmaps_a[0]->num_element_dofs(cell->index()); dolfin_assert(dim == dofmaps_a[1]->num_element_dofs(cell->index())); A_e.resize(dim, dim); integral_a->tabulate_tensor(A_e.data(), ufc_a.w(), vertex_coordinates.data(), ufc_cell.orientation); // Solve local problem if (_solver_type == SolverType::Cholesky) { cholesky.compute(A_e); x_e = cholesky.solve(b_e); } else { lu.compute(A_e); x_e = lu.solve(b_e); } } else { if (_solver_type == SolverType::Cholesky) x_e = _cholesky_cache[cell->index()].solve(b_e); else x_e = _lu_cache[cell->index()].solve(b_e); } // Set solution in global vector x.set_local(x_e.data(), dofs_a0.size(), dofs_a0.data()); p++; } // Finalise vector x.apply("insert"); }