Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/v0.1.0/v0.9.0/cpp
DOLFINx  0.1.0
DOLFINx C++ interface
discreteoperators.h
1 // Copyright (C) 2015 Garth N. Wells
2 //
3 // This file is part of DOLFINx (https://www.fenicsproject.org)
4 //
5 // SPDX-License-Identifier: LGPL-3.0-or-later
6 
7 #pragma once
8 
9 #include <array>
10 #include <dolfinx/common/IndexMap.h>
11 #include <dolfinx/fem/DofMap.h>
12 #include <dolfinx/fem/FunctionSpace.h>
13 #include <dolfinx/la/SparsityPattern.h>
14 #include <dolfinx/mesh/Mesh.h>
15 #include <memory>
16 #include <vector>
17 #include <xtl/xspan.hpp>
18 
19 namespace dolfinx::fem
20 {
21 
40  const fem::FunctionSpace& V1);
41 
61 template <typename T>
63  const std::function<int(std::int32_t, const std::int32_t*, std::int32_t,
64  const std::int32_t*, const T*)>& mat_set,
65  const fem::FunctionSpace& V0, const fem::FunctionSpace& V1);
66 } // namespace dolfinx::fem
67 
68 using namespace dolfinx;
69 template <typename T>
71  const std::function<int(std::int32_t, const std::int32_t*, std::int32_t,
72  const std::int32_t*, const T*)>& mat_set,
73  const fem::FunctionSpace& V0, const fem::FunctionSpace& V1)
74 {
75  // Get mesh
76  std::shared_ptr<const mesh::Mesh> mesh = V0.mesh();
77  assert(mesh);
78 
79  // Check that mesh is the same for both function spaces
80  assert(V1.mesh());
81  if (mesh != V1.mesh())
82  {
83  throw std::runtime_error("Compute discrete gradient operator. Function "
84  "spaces do not share the same mesh");
85  }
86 
87  // Check that V0 is a (lowest-order) edge basis
88  mesh->topology_mutable().create_entities(1);
89  std::int64_t num_edges_global = mesh->topology().index_map(1)->size_global();
90  const std::int64_t V0dim
91  = V0.dofmap()->index_map->size_global() * V0.dofmap()->index_map_bs();
92  if (V0dim != num_edges_global)
93  {
94  throw std::runtime_error(
95  "Cannot compute discrete gradient operator. Function "
96  "spaces is not a lowest-order edge space");
97  }
98 
99  // Check that V1 is a linear nodal basis
100  const std::int64_t num_vertices_global
101  = mesh->topology().index_map(0)->size_global();
102  const std::int64_t V1dim
103  = V1.dofmap()->index_map->size_global() * V1.dofmap()->index_map_bs();
104  if (V1dim != num_vertices_global)
105  {
106  throw std::runtime_error(
107  "Cannot compute discrete gradient operator. Function "
108  "space is not a linear nodal function space");
109  }
110 
111  // Build maps from entities to local dof indices
112  std::shared_ptr<const dolfinx::fem::ElementDofLayout> layout0
113  = V0.dofmap()->element_dof_layout;
114  std::shared_ptr<const dolfinx::fem::ElementDofLayout> layout1
115  = V1.dofmap()->element_dof_layout;
116 
117  // Copy index maps from dofmaps
118  std::array<std::shared_ptr<const common::IndexMap>, 2> index_maps
119  = {{V0.dofmap()->index_map, V1.dofmap()->index_map}};
120  std::array<int, 2> block_sizes
121  = {V0.dofmap()->index_map_bs(), V1.dofmap()->index_map_bs()};
122  std::vector<std::array<std::int64_t, 2>> local_range
123  = {index_maps[0]->local_range(), index_maps[1]->local_range()};
124  assert(block_sizes[0] == block_sizes[1]);
125 
126  // Initialize required connectivities
127  const int tdim = mesh->topology().dim();
128  mesh->topology_mutable().create_connectivity(1, 0);
129  auto e_to_v = mesh->topology().connectivity(1, 0);
130  mesh->topology_mutable().create_connectivity(tdim, 1);
131  auto c_to_e = mesh->topology().connectivity(tdim, 1);
132  mesh->topology_mutable().create_connectivity(1, tdim);
133  auto e_to_c = mesh->topology().connectivity(1, tdim);
134  mesh->topology_mutable().create_connectivity(tdim, 0);
135  auto c_to_v = mesh->topology().connectivity(tdim, 0);
136 
137  // Build sparsity pattern
138  const std::int32_t num_edges = mesh->topology().index_map(1)->size_local()
139  + mesh->topology().index_map(1)->num_ghosts();
140  const std::shared_ptr<const fem::DofMap> dofmap0 = V0.dofmap();
141  assert(dofmap0);
142  // Create local lookup table for local edge to cell dofs
143  const int num_edges_per_cell
144  = mesh::cell_num_entities(mesh->topology().cell_type(), 1);
145  std::map<std::int32_t, std::vector<std::int32_t>> local_edge_dofs;
146  for (std::int32_t i = 0; i < num_edges_per_cell; ++i)
147  local_edge_dofs[i] = layout0->entity_dofs(1, i);
148  // Create local lookup table for local vertex to cell dofs
149  const int num_vertices_per_cell
150  = mesh::cell_num_entities(mesh->topology().cell_type(), 0);
151  std::map<std::int32_t, std::vector<std::int32_t>> local_vertex_dofs;
152  for (std::int32_t i = 0; i < num_vertices_per_cell; ++i)
153  local_vertex_dofs[i] = layout1->entity_dofs(0, i);
154 
155  // Build discrete gradient operator/matrix
156  const std::shared_ptr<const fem::DofMap> dofmap1 = V1.dofmap();
157  assert(dofmap1);
158  const std::vector<std::int64_t>& global_indices
159  = mesh->topology().index_map(0)->global_indices();
160  std::array<T, 2> Ae;
161  for (std::int32_t e = 0; e < num_edges; ++e)
162  {
163  // Find local index of edge in one of the cells it is part of
164  xtl::span<const std::int32_t> cells = e_to_c->links(e);
165  assert(cells.size() > 0);
166  const std::int32_t cell = cells[0];
167  xtl::span<const std::int32_t> edges = c_to_e->links(cell);
168  const auto it = std::find(edges.begin(), edges.end(), e);
169  assert(it != edges.end());
170  const int local_edge = std::distance(edges.begin(), it);
171 
172  // Find the dofs located on the edge
173  xtl::span<const std::int32_t> dofs0 = dofmap0->cell_dofs(cell);
174  std::vector<std::int32_t>& local_dofs = local_edge_dofs[local_edge];
175  assert(local_dofs.size() == 1);
176  const std::int32_t row = dofs0[local_dofs[0]];
177 
178  xtl::span<const std::int32_t> vertices = e_to_v->links(e);
179  assert(vertices.size() == 2);
180  xtl::span<const std::int32_t> cell_vertices = c_to_v->links(cell);
181 
182  // Find local index of each of the vertices and map to local dof
183  std::array<std::int32_t, 2> cols;
184  xtl::span<const std::int32_t> dofs1 = dofmap1->cell_dofs(cell);
185  for (std::int32_t i = 0; i < 2; ++i)
186  {
187  const auto it
188  = std::find(cell_vertices.begin(), cell_vertices.end(), vertices[i]);
189  assert(it != cell_vertices.end());
190  const int local_vertex = std::distance(cell_vertices.begin(), it);
191 
192  std::vector<std::int32_t>& local_v_dofs = local_vertex_dofs[local_vertex];
193  assert(local_v_dofs.size() == 1);
194  cols[i] = dofs1[local_v_dofs[0]];
195  }
196 
197  if (global_indices[vertices[1]] < global_indices[vertices[0]])
198  Ae = {1, -1};
199  else
200  Ae = {-1, 1};
201 
202  mat_set(1, &row, 2, cols.data(), Ae.data());
203  }
204 }
205 //-----------------------------------------------------------------------------
dolfinx::mesh::cell_num_entities
int cell_num_entities(mesh::CellType type, int dim)
Number of entities of dimension dim.
Definition: cell_types.cpp:183
dolfinx::fem::FunctionSpace
This class represents a finite element function space defined by a mesh, a finite element,...
Definition: FunctionSpace.h:33
dolfinx::la::SparsityPattern
This class provides a sparsity pattern data structure that can be used to initialize sparse matrices.
Definition: SparsityPattern.h:35
dolfinx::fem::FunctionSpace::mesh
std::shared_ptr< const mesh::Mesh > mesh() const
The mesh.
Definition: FunctionSpace.cpp:211
dolfinx::fem::FunctionSpace::dofmap
std::shared_ptr< const fem::DofMap > dofmap() const
The dofmap.
Definition: FunctionSpace.cpp:218
dolfinx::fem::create_sparsity_discrete_gradient
la::SparsityPattern create_sparsity_discrete_gradient(const fem::FunctionSpace &V0, const fem::FunctionSpace &V1)
Definition: discreteoperators.cpp:13
dolfinx::fem
Finite element method functionality.
Definition: assemble_matrix_impl.h:22
dolfinx::fem::assemble_discrete_gradient
void assemble_discrete_gradient(const std::function< int(std::int32_t, const std::int32_t *, std::int32_t, const std::int32_t *, const T *)> &mat_set, const fem::FunctionSpace &V0, const fem::FunctionSpace &V1)
Definition: discreteoperators.h:70