//----------------------------------------------------------------------------- void SparsityPatternBuilder::build_multimesh_sparsity_pattern( GenericSparsityPattern& sparsity_pattern, const MultiMeshForm& form) { // Get global dimensions and local range const std::size_t rank = form.rank(); std::vector<std::size_t> global_dimensions(rank); std::vector<std::pair<std::size_t, std::size_t>> local_range(rank); std::vector<ArrayView<const std::size_t>> local_to_global(rank); std::vector<ArrayView<const int>> off_process_owner(rank); for (std::size_t i = 0; i < rank; ++i) { global_dimensions[i] = form.function_space(i)->dofmap()->global_dimension(); local_range[i] = form.function_space(i)->dofmap()->ownership_range(); off_process_owner[i].set(form.function_space(i)->dofmap()->off_process_owner()); } // Initialize sparsity pattern const std::vector<std::size_t> block_sizes(rank, 1); sparsity_pattern.init(form.function_space(0)->part(0)->mesh()->mpi_comm(), global_dimensions, local_range, local_to_global, off_process_owner, block_sizes); // Iterate over each part for (std::size_t part = 0; part < form.num_parts(); part++) { // Get mesh on current part (assume it's the same for all arguments) const Mesh& mesh = *form.function_space(0)->part(part)->mesh(); // Build list of dofmaps std::vector<const GenericDofMap*> dofmaps; for (std::size_t i = 0; i < form.rank(); i++) dofmaps.push_back(&*form.function_space(i)->dofmap()->part(part)); log(PROGRESS, "Building intra-mesh sparsity pattern on part %d.", part); // Build sparsity pattern for part by calling the regular dofmap // builder. This builds the sparsity pattern for all interacting // dofs on the current part. build(sparsity_pattern, mesh, dofmaps, true, false, false, true, false, false); log(PROGRESS, "Building inter-mesh sparsity pattern on part %d.", part); // Build sparsity pattern for interface. This builds the sparsity // pattern for all dofs that may interact across the interface // between cutting meshes. _build_multimesh_sparsity_pattern_interface(sparsity_pattern, form, part); } log(PROGRESS, "Applying changes to sparsity pattern."); // Finalize sparsity pattern sparsity_pattern.apply(); }
//----------------------------------------------------------------------------- void SparsityPatternBuilder::build(GenericSparsityPattern& sparsity_pattern, const Mesh& mesh, const std::vector<const GenericDofMap*> dofmaps, bool cells, bool interior_facets, bool exterior_facets, bool diagonal, bool init, bool finalize) { const std::size_t rank = dofmaps.size(); // Get global dimensions and local range std::vector<std::size_t> global_dimensions(rank); std::vector<std::pair<std::size_t, std::size_t> > local_range(rank); std::vector<const boost::unordered_map<std::size_t, unsigned int>* > off_process_owner(rank); for (std::size_t i = 0; i < rank; ++i) { global_dimensions[i] = dofmaps[i]->global_dimension(); local_range[i] = dofmaps[i]->ownership_range(); off_process_owner[i] = &(dofmaps[i]->off_process_owner()); } // Initialise sparsity pattern if (init) { sparsity_pattern.init(mesh.mpi_comm(), global_dimensions, local_range, off_process_owner); } // Only build for rank >= 2 (matrices and higher order tensors) that // require sparsity details if (rank < 2) return; // Vector to store macro-dofs, if required (for interior facets) std::vector<std::vector<dolfin::la_index> > macro_dofs(rank); // Create vector to point to dofs std::vector<const std::vector<dolfin::la_index>* > dofs(rank); // FIXME: We iterate over the entire mesh even if the function space // is restricted. This works out fine since the local dofmap // returned on each cell will be an empty vector, but we might think // about optimizing this further. // Build sparsity pattern for cell integrals if (cells) { Progress p("Building sparsity pattern over cells", mesh.num_cells()); for (CellIterator cell(mesh); !cell.end(); ++cell) { // Tabulate dofs for each dimension and get local dimensions for (std::size_t i = 0; i < rank; ++i) dofs[i] = &dofmaps[i]->cell_dofs(cell->index()); // Insert non-zeroes in sparsity pattern sparsity_pattern.insert(dofs); p++; } } // Note: no need to iterate over exterior facets since those dofs // are included when tabulating dofs on all cells // Build sparsity pattern for interior/exterior facet integrals const std::size_t D = mesh.topology().dim(); if (interior_facets || exterior_facets) { // Compute facets and facet - cell connectivity if not already computed mesh.init(D - 1); mesh.init(D - 1, D); if (!mesh.ordered()) { dolfin_error("SparsityPatternBuilder.cpp", "compute sparsity pattern", "Mesh is not ordered according to the UFC numbering convention. " "Consider calling mesh.order()"); } Progress p("Building sparsity pattern over interior facets", mesh.num_facets()); for (FacetIterator facet(mesh); !facet.end(); ++facet) { bool exterior_facet = false; if (facet->num_global_entities(D) == 1) exterior_facet = true; // Check facet type if (exterior_facets && exterior_facet && !cells) { // Get cells incident with facet dolfin_assert(facet->num_entities(D) == 1); Cell cell(mesh, facet->entities(D)[0]); // Tabulate dofs for each dimension and get local dimensions for (std::size_t i = 0; i < rank; ++i) dofs[i] = &dofmaps[i]->cell_dofs(cell.index()); // Insert dofs sparsity_pattern.insert(dofs); } else if (interior_facets && !exterior_facet) { // Get cells incident with facet Cell cell0(mesh, facet->entities(D)[0]); Cell cell1(mesh, facet->entities(D)[1]); // Tabulate dofs for each dimension on macro element for (std::size_t i = 0; i < rank; i++) { // Get dofs for each cell const std::vector<dolfin::la_index>& cell_dofs0 = dofmaps[i]->cell_dofs(cell0.index()); const std::vector<dolfin::la_index>& cell_dofs1 = dofmaps[i]->cell_dofs(cell1.index()); // Create space in macro dof vector macro_dofs[i].resize(cell_dofs0.size() + cell_dofs1.size()); // Copy cell dofs into macro dof vector std::copy(cell_dofs0.begin(), cell_dofs0.end(), macro_dofs[i].begin()); std::copy(cell_dofs1.begin(), cell_dofs1.end(), macro_dofs[i].begin() + cell_dofs0.size()); // Store pointer to macro dofs dofs[i] = ¯o_dofs[i]; } // Insert dofs sparsity_pattern.insert(dofs); } p++; } } if (diagonal) { Progress p("Building sparsity pattern over diagonal", local_range[0].second-local_range[0].first); std::vector<dolfin::la_index> diagonal_dof(1, 0); for (std::size_t i = 0; i < rank; ++i) dofs[i] = &diagonal_dof; for (std::size_t j = local_range[0].first; j < local_range[0].second; j++) { diagonal_dof[0] = j; // Insert diagonal non-zeroes in sparsity pattern sparsity_pattern.insert(dofs); p++; } } // Finalize sparsity pattern (communicate off-process terms) if (finalize) sparsity_pattern.apply(); }
//----------------------------------------------------------------------------- void SparsityPatternBuilder::build(GenericSparsityPattern& sparsity_pattern, const Mesh& mesh, const std::vector<const GenericDofMap*> dofmaps, bool cells, bool interior_facets, bool exterior_facets, bool vertices, bool diagonal, bool init, bool finalize) { // Get global dimensions and local range const std::size_t rank = dofmaps.size(); std::vector<std::size_t> global_dimensions(rank); std::vector<std::pair<std::size_t, std::size_t>> local_range(rank); std::vector<ArrayView<const std::size_t>> local_to_global(rank); std::vector<ArrayView<const int>> off_process_owner(rank); for (std::size_t i = 0; i < rank; ++i) { global_dimensions[i] = dofmaps[i]->global_dimension(); local_range[i] = dofmaps[i]->ownership_range(); local_to_global[i].set(dofmaps[i]->local_to_global_unowned()); off_process_owner[i].set(dofmaps[i]->off_process_owner()); } dolfin_assert(!dofmaps.empty()); dolfin_assert(dofmaps[0]); std::vector<std::size_t> block_sizes(rank); for (std::size_t i = 0; i < rank; ++i) block_sizes[i] = dofmaps[i]->block_size; // Initialise sparsity pattern if (init) { sparsity_pattern.init(mesh.mpi_comm(), global_dimensions, local_range, local_to_global, off_process_owner, block_sizes); } // Only build for rank >= 2 (matrices and higher order tensors) that // require sparsity details if (rank < 2) return; // Vector to store macro-dofs, if required (for interior facets) std::vector<std::vector<dolfin::la_index>> macro_dofs(rank); // Create vector to point to dofs std::vector<ArrayView<const dolfin::la_index>> dofs(rank); // FIXME: We iterate over the entire mesh even if the function space // is restricted. This works out fine since the local dofmap // returned on each cell will be an empty vector, but we might think // about optimizing this further. // Build sparsity pattern for cell integrals if (cells) { Progress p("Building sparsity pattern over cells", mesh.num_cells()); for (CellIterator cell(mesh); !cell.end(); ++cell) { // Tabulate dofs for each dimension and get local dimensions for (std::size_t i = 0; i < rank; ++i) dofs[i] = dofmaps[i]->cell_dofs(cell->index()); // Insert non-zeroes in sparsity pattern sparsity_pattern.insert_local(dofs); p++; } } // Build sparsity pattern for vertex/point integrals const std::size_t D = mesh.topology().dim(); if (vertices) { mesh.init(0); mesh.init(0, D); std::vector<std::vector<dolfin::la_index>> global_dofs(rank); //std::vector<const std::vector<dolfin::la_index>* > global_dofs_p(rank); std::vector<std::vector<std::size_t>> local_to_local_dofs(rank); // Resize local dof map vector for (std::size_t i = 0; i < rank; ++i) { global_dofs[i].resize(dofmaps[i]->num_entity_dofs(0)); local_to_local_dofs[i].resize(dofmaps[i]->num_entity_dofs(0)); } Progress p("Building sparsity pattern over vertices", mesh.num_vertices()); for (VertexIterator vert(mesh); !vert.end(); ++vert) { // Get mesh cell to which mesh vertex belongs (pick first) Cell mesh_cell(mesh, vert->entities(D)[0]); // Check that cell is not a ghost dolfin_assert(!mesh_cell.is_ghost()); // Get local index of vertex with respect to the cell const std::size_t local_vertex = mesh_cell.index(*vert); for (std::size_t i = 0; i < rank; ++i) { dofs[i] = dofmaps[i]->cell_dofs(mesh_cell.index()); dofmaps[i]->tabulate_entity_dofs(local_to_local_dofs[i], 0, local_vertex); // Copy cell dofs to local dofs and tabulated values to for (std::size_t j = 0; j < local_to_local_dofs[i].size(); ++j) global_dofs[i][j] = dofs[i][local_to_local_dofs[i][j]]; } // Insert non-zeroes in sparsity pattern std::vector<ArrayView<const dolfin::la_index>> global_dofs_p(rank); for (std::size_t i = 0; i < rank; ++i) global_dofs_p[i].set(global_dofs[i]); sparsity_pattern.insert_local(global_dofs_p); p++; } } // Note: no need to iterate over exterior facets since those dofs // are included when tabulating dofs on all cells // Build sparsity pattern for interior/exterior facet integrals if (interior_facets || exterior_facets) { // Compute facets and facet - cell connectivity if not already // computed mesh.init(D - 1); mesh.init(D - 1, D); if (!mesh.ordered()) { dolfin_error("SparsityPatternBuilder.cpp", "compute sparsity pattern", "Mesh is not ordered according to the UFC numbering convention. " "Consider calling mesh.order()"); } Progress p("Building sparsity pattern over interior facets", mesh.num_facets()); for (FacetIterator facet(mesh); !facet.end(); ++facet) { bool this_exterior_facet = false; if (facet->num_global_entities(D) == 1) this_exterior_facet = true; // Check facet type if (exterior_facets && this_exterior_facet && !cells) { // Get cells incident with facet dolfin_assert(facet->num_entities(D) == 1); Cell cell(mesh, facet->entities(D)[0]); // Tabulate dofs for each dimension and get local dimensions for (std::size_t i = 0; i < rank; ++i) dofs[i] = dofmaps[i]->cell_dofs(cell.index()); // Insert dofs sparsity_pattern.insert_local(dofs); } else if (interior_facets && !this_exterior_facet) { if (facet->num_entities(D) == 1) { dolfin_assert(facet->is_ghost()); continue; } // Get cells incident with facet dolfin_assert(facet->num_entities(D) == 2); Cell cell0(mesh, facet->entities(D)[0]); Cell cell1(mesh, facet->entities(D)[1]); // Tabulate dofs for each dimension on macro element for (std::size_t i = 0; i < rank; i++) { // Get dofs for each cell const ArrayView<const dolfin::la_index> cell_dofs0 = dofmaps[i]->cell_dofs(cell0.index()); const ArrayView<const dolfin::la_index> cell_dofs1 = dofmaps[i]->cell_dofs(cell1.index()); // Create space in macro dof vector macro_dofs[i].resize(cell_dofs0.size() + cell_dofs1.size()); // Copy cell dofs into macro dof vector std::copy(cell_dofs0.begin(), cell_dofs0.end(), macro_dofs[i].begin()); std::copy(cell_dofs1.begin(), cell_dofs1.end(), macro_dofs[i].begin() + cell_dofs0.size()); // Store pointer to macro dofs dofs[i].set(macro_dofs[i]); } // Insert dofs sparsity_pattern.insert_local(dofs); } p++; } } if (diagonal) { const std::size_t local_size0 = local_range[0].second-local_range[0].first; const std::size_t local_size1 = local_range[1].second-local_range[1].first; const std::size_t local_size = std::min(local_size0, local_size1); Progress p("Building sparsity pattern over diagonal", local_size); std::vector<dolfin::la_index> diagonal_dof(1, 0); for (std::size_t i = 0; i < rank; ++i) dofs[i].set(diagonal_dof); for (std::size_t j = 0; j < local_size; j++) { // Insert diagonal non-zeroes in sparsity pattern diagonal_dof[0] = j; sparsity_pattern.insert_local(dofs); p++; } } // Finalize sparsity pattern (communicate off-process terms) if (finalize) sparsity_pattern.apply(); }