178class LagrangePolynomialGrid {
180 LagrangePolynomialGrid() =
default;
181 LagrangePolynomialGrid(
const dolfinx::fem::FunctionSpace<T>& space) {
182 if (!space.mesh() || !space.element())
183 throw ValueError(
"Cannot construct mesh from space without mesh or element");
185 if (Detail::is_cellwise_constant(space))
186 throw ValueError(
"Cannot construct mesh from a space with cell-wise constant (P0) functions");
188 _cell_type = space.mesh()->topology()->cell_type();
189 _mesh = space.mesh();
190 _element = space.element();
192 auto [x, xshape, xids, _ghosts, cells, cells_shape] = dolfinx::io::vtk_mesh_from_space(space);
193 _node_coords = std::move(x);
194 _node_coords_shape = std::move(xshape);
195 _node_ids = std::move(xids);
196 _cells = std::move(cells);
197 _cells_shape = std::move(cells_shape);
201 void update(
const dolfinx::fem::FunctionSpace<T>& space) {
202 *
this = LagrangePolynomialGrid{space};
208 _node_coords.clear();
214 static LagrangePolynomialGrid from(
const dolfinx::fem::FunctionSpace<T>& space) {
218 std::integral
auto number_of_points()
const {
return _node_coords_shape[0]; }
219 std::integral
auto number_of_cells()
const {
return _cells_shape[0]; }
220 std::integral
auto number_of_cell_points()
const {
return _cells_shape[1]; }
222 std::int64_t id(
const Point& p)
const {
223 return _node_ids[p.index];
226 auto position(
const Point& p)
const {
227 assert(_node_coords_shape[1] == 3);
229 _node_coords[p.index*3],
230 _node_coords[p.index*3 + 1],
231 _node_coords[p.index*3 + 2]
235 std::ranges::range
auto points()
const {
237 return std::views::iota(std::size_t{0}, _node_coords_shape[0])
238 | std::views::transform([] (std::size_t i) {
239 return Point{
static_cast<std::int32_t
>(i)};
243 std::ranges::range
auto points(
const Cell& cell)
const {
244 return std::views::iota(std::size_t{0}, _cells_shape[1])
245 | std::views::transform([&, i=cell.index, ncorners=_cells_shape[1]] (std::size_t local_point_index) {
246 return Point{static_cast<std::int32_t>(_cells[i*ncorners + local_point_index])};
250 std::ranges::range
auto cells()
const {
252 return std::views::iota(std::size_t{0}, _cells_shape[0])
253 | std::views::transform([] (std::size_t i) {
254 return Cell{
static_cast<std::int32_t
>(i)};
258 template<
int rank = 0,
int dim = 3, Concepts::Scalar V>
259 auto evaluate(
const dolfinx::fem::Function<V, T>& f,
const Cell& c)
const {
260 assert(is_compatible(f));
261 return _evaluate<rank, dim>(f, c.index);
264 template<
int rank = 0,
int dim = 3, Concepts::Scalar V>
265 auto evaluate(
const dolfinx::fem::Function<V, T>& f,
const Point& p)
const {
266 assert(is_compatible(f));
267 return _evaluate<rank, dim>(f, p.index);
270 auto cell_type()
const {
274 template<Concepts::Scalar V>
275 bool is_compatible(
const dolfinx::fem::Function<V, T>& f)
const {
276 if (!_set)
return false;
277 if (!f.function_space()->mesh())
return false;
278 if (f.function_space()->mesh() != _mesh)
return false;
279 if (!Detail::is_cellwise_constant(f)) {
280 if (!f.function_space()->element())
return false;
281 if (*f.function_space()->element() != *_element)
return false;
287 void _check_built()
const {
289 throw InvalidState(
"Mesh has not been built");
292 template<
int rank = 0,
int dim = 3, Concepts::Scalar V>
293 auto _evaluate(
const dolfinx::fem::Function<V, T>& f,
const std::integral
auto i)
const {
294 const auto f_components = f.function_space()->element()->block_size();
295 const auto& values = f.x()->array();
296 assert(f.function_space()->element()->value_shape().size() == rank);
297 assert(values.size() >=
static_cast<std::size_t
>(i*f_components + f_components));
299 if constexpr (rank == 0)
300 return values[i*f_components];
301 else if constexpr (rank == 1) {
302 auto result = Ranges::filled_array<dim>(V{0});
304 values.data() + i*f_components,
305 std::min(dim, f_components),
310 throw NotImplemented(
"Tensor evaluation");
311 return std::array<std::array<V, dim>, dim>{};
315 dolfinx::mesh::CellType _cell_type;
316 std::shared_ptr<const dolfinx::mesh::Mesh<T>> _mesh{
nullptr};
317 std::shared_ptr<const dolfinx::fem::FiniteElement<T>> _element{
nullptr};
319 std::vector<T> _node_coords;
320 std::array<std::size_t, 2> _node_coords_shape;
321 std::vector<std::int64_t> _node_ids;
322 std::vector<std::int64_t> _cells;
323 std::array<std::size_t, 2> _cells_shape;