//------------------------------------------------------------------------------ void LocalAssembler::assemble_interior_facet(Eigen::MatrixXd& A, UFC& ufc, const std::vector<double>& vertex_coordinates, const ufc::cell& ufc_cell, const Cell& cell, const Facet& facet, const std::size_t local_facet, const MeshFunction<std::size_t>* domains) { // Skip if there are no interior facet integrals if (!ufc.form.has_interior_facet_integrals()) return; // Extract default interior facet integral ufc::interior_facet_integral* integral = ufc.default_interior_facet_integral.get(); // Get integral for sub domain (if any) if (domains && !domains->empty()) integral = ufc.get_interior_facet_integral((*domains)[facet]); // Skip integral if zero if (!integral) return; // Update to current pair of cells and facets ufc.update(cell, vertex_coordinates, ufc_cell, cell, vertex_coordinates, ufc_cell, integral->enabled_coefficients()); // Tabulate interior facet tensor on macro element integral->tabulate_tensor(ufc.macro_A.data(), ufc.macro_w(), vertex_coordinates.data(), vertex_coordinates.data(), local_facet, local_facet, ufc_cell.orientation, ufc_cell.orientation); // Stuff upper left quadrant (corresponding to this cell) into A const std::size_t M = A.rows(); const std::size_t N = A.cols(); if (N == 1) { for (std::size_t i = 0; i < M; i++) A(i, 0) = ufc.macro_A[i]; } else { for (std::size_t i = 0; i < M; i++) for (std::size_t j = 0; j < N; j++) A(i, j) += ufc.macro_A[2*N*i + j]; } }
//----------------------------------------------------------------------------- void Assembler::assemble_interior_facets( GenericTensor& A, const Form& a, UFC& ufc, std::shared_ptr<const MeshFunction<std::size_t>> domains, std::shared_ptr<const MeshFunction<std::size_t>> cell_domains, std::vector<double>* values) { // Skip assembly if there are no interior facet integrals if (!ufc.form.has_interior_facet_integrals()) return; // Set timer Timer timer("Assemble interior facets"); // Extract mesh and coefficients const Mesh& mesh = a.mesh(); // MPI rank const int my_mpi_rank = MPI::rank(mesh.mpi_comm()); // Form rank const std::size_t form_rank = ufc.form.rank(); // Collect pointers to dof maps std::vector<const GenericDofMap*> dofmaps; for (std::size_t i = 0; i < form_rank; ++i) dofmaps.push_back(a.function_space(i)->dofmap().get()); // Vector to hold dofs for cells, and a vector holding pointers to same std::vector<std::vector<dolfin::la_index>> macro_dofs(form_rank); std::vector<ArrayView<const dolfin::la_index>> macro_dof_ptrs(form_rank); // Interior facet integral const ufc::interior_facet_integral* integral = ufc.default_interior_facet_integral.get(); // Check whether integral is domain-dependent bool use_domains = domains && !domains->empty(); bool use_cell_domains = cell_domains && !cell_domains->empty(); // Compute facets and facet - cell connectivity if not already computed const std::size_t D = mesh.topology().dim(); mesh.init(D - 1); mesh.init(D - 1, D); dolfin_assert(mesh.ordered()); // Assemble over interior facets (the facets of the mesh) ufc::cell ufc_cell[2]; std::vector<double> coordinate_dofs[2]; Progress p(AssemblerBase::progress_message(A.rank(), "interior facets"), mesh.num_facets()); for (FacetIterator facet(mesh); !facet.end(); ++facet) { if (facet->num_entities(D) == 1) continue; // Check that facet is not a ghost dolfin_assert(!facet->is_ghost()); // Get integral for sub domain (if any) if (use_domains) integral = ufc.get_interior_facet_integral((*domains)[*facet]); // Skip integral if zero if (!integral) continue; // Get cells incident with facet (which is 0 and 1 here is arbitrary) dolfin_assert(facet->num_entities(D) == 2); std::size_t cell_index_plus = facet->entities(D)[0]; std::size_t cell_index_minus = facet->entities(D)[1]; if (use_cell_domains && (*cell_domains)[cell_index_plus] < (*cell_domains)[cell_index_minus]) { std::swap(cell_index_plus, cell_index_minus); } // The convention '+' = 0, '-' = 1 is from ffc const Cell cell0(mesh, cell_index_plus); const Cell cell1(mesh, cell_index_minus); // Get local index of facet with respect to each cell std::size_t local_facet0 = cell0.index(*facet); std::size_t local_facet1 = cell1.index(*facet); // Update to current pair of cells cell0.get_cell_data(ufc_cell[0], local_facet0); cell0.get_coordinate_dofs(coordinate_dofs[0]); cell1.get_cell_data(ufc_cell[1], local_facet1); cell1.get_coordinate_dofs(coordinate_dofs[1]); ufc.update(cell0, coordinate_dofs[0], ufc_cell[0], cell1, coordinate_dofs[1], ufc_cell[1], integral->enabled_coefficients()); // Tabulate dofs for each dimension on macro element for (std::size_t i = 0; i < form_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.data(), cell_dofs0.data() + cell_dofs0.size(), macro_dofs[i].begin()); std::copy(cell_dofs1.data(), cell_dofs1.data() + cell_dofs1.size(), macro_dofs[i].begin() + cell_dofs0.size()); macro_dof_ptrs[i].set(macro_dofs[i]); } // Tabulate interior facet tensor on macro element integral->tabulate_tensor(ufc.macro_A.data(), ufc.macro_w(), coordinate_dofs[0].data(), coordinate_dofs[1].data(), local_facet0, local_facet1, ufc_cell[0].orientation, ufc_cell[1].orientation); if (cell0.is_ghost() != cell1.is_ghost()) { int ghost_rank = -1; if (cell0.is_ghost()) ghost_rank = cell0.owner(); else ghost_rank = cell1.owner(); dolfin_assert(my_mpi_rank != ghost_rank); dolfin_assert(ghost_rank != -1); if (ghost_rank < my_mpi_rank) continue; } // Add entries to global tensor A.add_local(ufc.macro_A.data(), macro_dof_ptrs); p++; } }