//----------------------------------------------------------------------------- Graph GraphBuilder::local_graph(const Mesh& mesh, const GenericDofMap& dofmap0, const GenericDofMap& dofmap1) { Timer timer("Build local sparsity graph from dofmaps"); // Create empty graph const std::size_t n = dofmap0.global_dimension(); Graph graph(n); // Build graph for (CellIterator cell(mesh); !cell.end(); ++cell) { const ArrayView<const dolfin::la_index> dofs0 = dofmap0.cell_dofs(cell->index()); const ArrayView<const dolfin::la_index> dofs1 = dofmap1.cell_dofs(cell->index()); //std::vector<dolfin::la_index>::const_iterator node0, node1; for (auto node0 = dofs0.begin(); node0 != dofs0.end(); ++node0) for (auto node1 = dofs1.begin(); node1 != dofs1.end(); ++node1) if (*node0 != *node1) graph[*node0].insert(*node1); } return graph; }
//---------------------------------------------------------------------------- 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"); }