DOLFINx 0.11.0.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
ADIOS2Writers.h
Go to the documentation of this file.
1// Copyright (C) 2021-2023 Jørgen S. Dokken and 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#ifdef HAS_ADIOS2
10
11#include "vtk_utils.h"
12#include <adios2.h>
13#include <algorithm>
14#include <basix/mdspan.hpp>
15#include <cassert>
16#include <complex>
17#include <concepts>
18#include <dolfinx/common/IndexMap.h>
19#include <dolfinx/fem/DofMap.h>
20#include <dolfinx/fem/FiniteElement.h>
21#include <dolfinx/fem/Function.h>
22#include <dolfinx/mesh/Geometry.h>
23#include <dolfinx/mesh/Mesh.h>
24#include <filesystem>
25#include <memory>
26#include <mpi.h>
27#include <stdexcept>
28#include <string>
29#include <type_traits>
30#include <variant>
31#include <vector>
32
35
36namespace dolfinx::fem
37{
38template <dolfinx::scalar T, std::floating_point U>
39class Function;
40}
41
42namespace dolfinx::io
43{
44namespace adios2_writer
45{
47template <std::floating_point T>
48using U = std::vector<std::variant<
49 std::shared_ptr<const fem::Function<float, T>>,
50 std::shared_ptr<const fem::Function<double, T>>,
51 std::shared_ptr<const fem::Function<std::complex<float>, T>>,
52 std::shared_ptr<const fem::Function<std::complex<double>, T>>>>;
53} // namespace adios2_writer
54
56class ADIOS2Writer
57{
58protected:
65 ADIOS2Writer(MPI_Comm comm, const std::filesystem::path& filename,
66 std::string tag, std::string engine);
67
69 ADIOS2Writer(ADIOS2Writer&& writer) = default;
70
72 ADIOS2Writer(const ADIOS2Writer&) = delete;
73
75 ~ADIOS2Writer();
76
78 ADIOS2Writer& operator=(ADIOS2Writer&& writer) = default;
79
80 // Copy assignment
81 ADIOS2Writer& operator=(const ADIOS2Writer&) = delete;
82
83public:
85 void close();
86
87protected:
88 std::unique_ptr<adios2::ADIOS> _adios;
89 std::unique_ptr<adios2::IO> _io;
90 std::unique_ptr<adios2::Engine> _engine;
91};
92
94namespace impl_adios2
95{
98constexpr std::array field_ext = {"_real", "_imag"};
99
102template <class T>
103adios2::Attribute<T> define_attribute(adios2::IO& io, std::string name,
104 const T& value, std::string var_name = "",
105 std::string separator = "/")
106{
107 if (adios2::Attribute<T> attr = io.InquireAttribute<T>(name); attr)
108 return attr;
109 else
110 return io.DefineAttribute<T>(name, value, var_name, separator);
111}
112
115template <class T>
116adios2::Variable<T> define_variable(adios2::IO& io, std::string name,
117 const adios2::Dims& shape = adios2::Dims(),
118 const adios2::Dims& start = adios2::Dims(),
119 const adios2::Dims& count = adios2::Dims())
120{
121 if (adios2::Variable v = io.InquireVariable<T>(name); v)
122 {
123 if (v.Count() != count and v.ShapeID() == adios2::ShapeID::LocalArray)
124 v.SetSelection({start, count});
125 return v;
126 }
127 else
128 return io.DefineVariable<T>(name, shape, start, count);
129}
130
132template <std::floating_point T>
133std::shared_ptr<const mesh::Mesh<T>>
134extract_common_mesh(const typename adios2_writer::U<T>& u)
135{
136 // Extract mesh from first function
137 assert(!u.empty());
138 auto mesh = std::visit([](auto&& u) { return u->function_space()->mesh(); },
139 u.front());
140 assert(mesh);
141
142 // Check that all functions share the same mesh
143 for (auto& v : u)
144 {
145 std::visit(
146 [&mesh](auto&& u)
147 {
148 if (mesh != u->function_space()->mesh())
149 {
150 throw std::runtime_error(
151 "ADIOS2Writer only supports functions sharing the same mesh");
152 }
153 },
154 v);
155 }
156
157 return mesh;
158}
159
160} // namespace impl_adios2
161
163namespace impl_vtx
164{
167std::stringstream create_vtk_schema(const std::vector<std::string>& point_data,
168 const std::vector<std::string>& cell_data);
169
171template <std::floating_point T>
172std::tuple<std::vector<std::string>, std::vector<std::string>>
173extract_function_names(const typename adios2_writer::U<T>& u)
174{
175 std::vector<std::string> names, dg0_names;
176 std::ranges::for_each(
177 u,
178 [&names, &dg0_names](auto&& v)
179 {
180 std::visit(
181 [&names, &dg0_names](auto&& v)
182 {
183 using U = std::decay_t<decltype(v)>;
184 using X = typename U::element_type;
185
186 if (impl::is_cellwise(*(v->function_space()->element())))
187 names = dg0_names;
188
189 if constexpr (std::is_floating_point_v<typename X::value_type>)
190 names.push_back(v->name);
191 else
192 {
193 names.push_back(v->name + impl_adios2::field_ext[0]);
194 names.push_back(v->name + impl_adios2::field_ext[1]);
195 }
196 },
197 v);
198 });
199
200 {
201 // Check names are unique
202 auto sorted = names;
203 std::ranges::sort(sorted);
204 if (std::ranges::unique(sorted).begin() != sorted.end())
205 {
206 throw std::runtime_error(
207 "Function names in VTX output need to be unique.");
208 }
209 }
210
211 return {names, dg0_names};
212}
213
223template <typename T, std::floating_point X>
224void vtx_write_data(adios2::IO& io, adios2::Engine& engine,
225 const fem::Function<T, X>& u)
226{
227 // Get function data array and information about layout
228 assert(u.x());
229 std::span<const T> u_vector = u.x()->array();
230
231 // Pad to 3D if vector/tensor is product of dimensions is smaller than
232 // 3**rank to ensure that we can visualize them correctly in Paraview
233 std::span<const std::size_t> value_shape
234 = u.function_space()->element()->value_shape();
235 std::size_t rank = value_shape.size();
236 std::size_t num_comp = std::reduce(value_shape.begin(), value_shape.end(), 1,
237 std::multiplies{});
238 if (num_comp < std::pow(3, rank))
239 num_comp = std::pow(3, rank);
240
241 std::shared_ptr<const fem::DofMap> dofmap = u.function_space()->dofmap();
242 assert(dofmap);
243 std::shared_ptr<const common::IndexMap> index_map = dofmap->index_map;
244 assert(index_map);
245 int index_map_bs = dofmap->index_map_bs();
246 int dofmap_bs = dofmap->bs();
247 std::uint32_t num_dofs = index_map_bs
248 * (index_map->size_local() + index_map->num_ghosts())
249 / dofmap_bs;
250 if constexpr (std::is_scalar_v<T>)
251 {
252 // ---- Real
253 std::vector<T> data(num_dofs * num_comp, 0);
254 for (std::size_t i = 0; i < num_dofs; ++i)
255 for (int j = 0; j < index_map_bs; ++j)
256 data[i * num_comp + j] = u_vector[i * index_map_bs + j];
257
258 adios2::Variable output = impl_adios2::define_variable<T>(
259 io, u.name, {}, {}, {num_dofs, num_comp});
260 spdlog::debug("Output data size={}", data.size());
261 engine.Put(output, data.data(), adios2::Mode::Sync);
262 }
263 else
264 {
265 // ---- Complex
266 using U = typename T::value_type;
267
268 std::vector<U> data(num_dofs * num_comp, 0);
269 for (std::size_t i = 0; i < num_dofs; ++i)
270 for (int j = 0; j < index_map_bs; ++j)
271 data[i * num_comp + j] = std::real(u_vector[i * index_map_bs + j]);
272
273 adios2::Variable output_real = impl_adios2::define_variable<U>(
274 io, u.name + impl_adios2::field_ext[0], {}, {}, {num_dofs, num_comp});
275 engine.Put(output_real, data.data(), adios2::Mode::Sync);
276
277 std::ranges::fill(data, 0);
278 for (std::size_t i = 0; i < num_dofs; ++i)
279 for (int j = 0; j < index_map_bs; ++j)
280 data[i * num_comp + j] = std::imag(u_vector[i * index_map_bs + j]);
281 adios2::Variable output_imag = impl_adios2::define_variable<U>(
282 io, u.name + impl_adios2::field_ext[1], {}, {}, {num_dofs, num_comp});
283 engine.Put(output_imag, data.data(), adios2::Mode::Sync);
284 }
285}
286
291template <std::floating_point T>
292void vtx_write_mesh(adios2::IO& io, adios2::Engine& engine,
293 const mesh::Mesh<T>& mesh)
294{
295 const mesh::Geometry<T>& geometry = mesh.geometry();
296 auto topology = mesh.topology();
297 assert(topology);
298
299 // "Put" geometry
300 std::shared_ptr<const common::IndexMap> x_map = geometry.index_map();
301 std::uint32_t num_vertices = x_map->size_local() + x_map->num_ghosts();
302 adios2::Variable local_geometry = impl_adios2::define_variable<T>(
303 io, "geometry", {}, {}, {num_vertices, 3});
304 spdlog::debug("Put local_geometry: {}x3", num_vertices);
305 engine.Put(local_geometry, geometry.x().data());
306
307 // Put number of nodes. The mesh data is written with local indices,
308 // therefore we need the ghost vertices.
309 adios2::Variable vertices = impl_adios2::define_variable<std::uint32_t>(
310 io, "NumberOfNodes", {adios2::LocalValueDim});
311 engine.Put<std::uint32_t>(vertices, num_vertices);
312
313 auto [vtkcells, shape]
314 = io::extract_vtk_connectivity(geometry.dofmap(), topology->cell_type());
315
316 // Add cell metadata
317 int tdim = topology->dim();
318 adios2::Variable cell_var = impl_adios2::define_variable<std::uint32_t>(
319 io, "NumberOfCells", {adios2::LocalValueDim});
320 engine.Put<std::uint32_t>(cell_var, shape[0]);
321 spdlog::debug("Put local_cells: {}", shape[0]);
322
323 adios2::Variable celltype_var
325 engine.Put<std::uint32_t>(
326 celltype_var, cells::get_vtk_cell_type(topology->cell_type(), tdim));
327
328 // Pack mesh 'nodes'. Output is written as [N0, v0_0,...., v0_N0, N1,
329 // v1_0,...., v1_N1,....], where N is the number of cell nodes and v0,
330 // etc, is the node index
331 std::vector<std::int64_t> cells(shape[0] * (shape[1] + 1), shape[1]);
332 for (std::size_t c = 0; c < shape[0]; ++c)
333 {
334 std::span vtkcell(vtkcells.data() + c * shape[1], shape[1]);
335 std::span cell(cells.data() + c * (shape[1] + 1), shape[1] + 1);
336 std::ranges::copy(vtkcell, std::next(cell.begin()));
337 }
338
339 // Put topology (nodes)
340 adios2::Variable local_topology = impl_adios2::define_variable<std::int64_t>(
341 io, "connectivity", {}, {}, {shape[0], shape[1] + 1});
342 spdlog::debug("Put local_topology: {}x{}", shape[0], shape[1] + 1);
343
344 engine.Put(local_topology, cells.data());
345
346 // Vertex global ids and ghost markers
347 adios2::Variable orig_id = impl_adios2::define_variable<std::int64_t>(
348 io, "vtkOriginalPointIds", {}, {}, {num_vertices});
349 engine.Put(orig_id, geometry.input_global_indices().data());
350
351 std::vector<std::uint8_t> x_ghost(num_vertices, 0);
352 std::fill(std::next(x_ghost.begin(), x_map->size_local()), x_ghost.end(), 1);
353 adios2::Variable ghost = impl_adios2::define_variable<std::uint8_t>(
354 io, "vtkGhostType", {}, {}, {x_ghost.size()});
355 engine.Put(ghost, x_ghost.data());
356 engine.PerformPuts();
357}
358
366template <std::floating_point T>
367std::pair<std::vector<std::int64_t>, std::vector<std::uint8_t>>
368vtx_write_mesh_from_space(adios2::IO& io, adios2::Engine& engine,
369 const fem::FunctionSpace<T>& V)
370{
371 auto mesh = V.mesh();
372 assert(mesh);
373 auto topology = mesh->topology();
374 assert(topology);
375 int tdim = topology->dim();
376
377 // Get a VTK mesh with points at the 'nodes'
378 auto [x, xshape, x_id, x_ghost, vtk, vtkshape] = io::vtk_mesh_from_space(V);
379
380 spdlog::debug("x={}, xshape={}x{}, x_id={}, x_ghost={}", x.size(), xshape[0],
381 xshape[1], x_id.size(), x_ghost.size());
382
383 std::uint32_t num_dofs = xshape[0];
384
385 // -- Pack mesh 'nodes'. Output is written as [N0, v0_0,...., v0_N0, N1,
386 // v1_0,...., v1_N1,....], where N is the number of cell nodes and v0,
387 // etc, is the node index.
388
389 spdlog::debug("Create cells: [{}x{}]", vtkshape[0], vtkshape[1]);
390
391 // Create vector, setting all entries to nodes per cell (vtk.shape(1))
392 std::vector<std::int64_t> cells(vtkshape[0] * (vtkshape[1] + 1), vtkshape[1]);
393
394 // Set the [v0_0,...., v0_N0, v1_0,...., v1_N1,....] data
395 for (std::size_t c = 0; c < vtkshape[0]; ++c)
396 {
397 std::span vtkcell(vtk.data() + c * vtkshape[1], vtkshape[1]);
398 std::span cell(cells.data() + c * (vtkshape[1] + 1), vtkshape[1] + 1);
399 std::ranges::copy(vtkcell, std::next(cell.begin()));
400 }
401
402 // Define ADIOS2 variables for geometry, topology, celltypes and
403 // corresponding VTK data
404 adios2::Variable local_geometry
405 = impl_adios2::define_variable<T>(io, "geometry", {}, {}, {num_dofs, 3});
406 adios2::Variable local_topology = impl_adios2::define_variable<std::int64_t>(
407 io, "connectivity", {}, {}, {vtkshape[0], vtkshape[1] + 1});
408 adios2::Variable cell_type
410 adios2::Variable vertices = impl_adios2::define_variable<std::uint32_t>(
411 io, "NumberOfNodes", {adios2::LocalValueDim});
412 adios2::Variable elements = impl_adios2::define_variable<std::uint32_t>(
413 io, "NumberOfEntities", {adios2::LocalValueDim});
414
415 // Write mesh information to file
416 spdlog::debug("vertices={}, elements={}, local_geom={}, local_cells={}",
417 num_dofs, vtkshape[0], x.size(), cells.size());
418 engine.Put<std::uint32_t>(vertices, num_dofs);
419 engine.Put<std::uint32_t>(elements, vtkshape[0]);
420 engine.Put<std::uint32_t>(
421 cell_type, cells::get_vtk_cell_type(topology->cell_type(), tdim));
422 engine.Put(local_geometry, x.data());
423 engine.Put(local_topology, cells.data());
424
425 // Node global ids
426 adios2::Variable orig_id = impl_adios2::define_variable<std::int64_t>(
427 io, "vtkOriginalPointIds", {}, {}, {x_id.size(), 1});
428 engine.Put(orig_id, x_id.data());
429 adios2::Variable ghost = impl_adios2::define_variable<std::uint8_t>(
430 io, "vtkGhostType", {}, {}, {x_ghost.size(), 1});
431 engine.Put(ghost, x_ghost.data());
432
433 engine.PerformPuts();
434 return {std::move(x_id), std::move(x_ghost)};
435}
436} // namespace impl_vtx
437
439enum class VTXMeshPolicy : std::int8_t
440{
441 update,
442 reuse
444};
445
451template <std::floating_point T>
452class VTXWriter : public ADIOS2Writer
453{
454public:
466 VTXWriter(MPI_Comm comm, const std::filesystem::path& filename,
467 std::shared_ptr<const mesh::Mesh<T>> mesh,
468 std::string engine = "BPFile")
469 : ADIOS2Writer(comm, filename, "VTX mesh writer", engine), _mesh(mesh),
470 _mesh_reuse_policy(VTXMeshPolicy::update),
471 _has_piecewise_constant(false)
472 {
473 // Define VTK scheme attribute for mesh
474 std::string vtk_scheme = impl_vtx::create_vtk_schema({}, {}).str();
475 impl_adios2::define_attribute<std::string>(*_io, "vtk.xml", vtk_scheme);
476 }
477
493 VTXWriter(MPI_Comm comm, const std::filesystem::path& filename,
494 const typename adios2_writer::U<T>& u, std::string engine,
495 VTXMeshPolicy mesh_policy = VTXMeshPolicy::update)
496 : ADIOS2Writer(comm, filename, "VTX function writer", engine),
497 _mesh(impl_adios2::extract_common_mesh<T>(u)), _u(u),
498 _mesh_reuse_policy(mesh_policy), _has_piecewise_constant(false)
499 {
500 if (u.empty())
501 throw std::runtime_error("VTXWriter fem::Function list is empty.");
502
503 // Extract space from first function
504 auto V0 = std::visit([](auto& u) { return u->function_space().get(); },
505 u.front());
506 assert(V0);
507
508 // Replace first function space if it is a space for piecewise constants
509 bool has_V0_changed = false;
510 for (auto& v : u)
511 {
512 std::visit(
513 [&V0, &has_V0_changed](auto& u)
514 {
515 auto V = u->function_space().get();
516 assert(V);
517 if (!impl::is_cellwise(*V->element()))
518 {
519 V0 = V;
520 has_V0_changed = true;
521 }
522 },
523 v);
524 if (has_V0_changed)
525 break;
526 }
527 auto element0 = V0->element().get();
528 assert(element0);
529
530 // Check if function is mixed
531 if (element0->is_mixed())
532 {
533 throw std::runtime_error(
534 "Mixed functions are not supported by VTXWriter.");
535 }
536
537 // FIXME: is the below check adequate for detecting a Lagrange
538 // element?
539 // Check that element is Lagrange
540 if (!element0->interpolation_ident())
541 {
542 throw std::runtime_error(
543 "Only (discontinuous) Lagrange functions are "
544 "supported. Interpolate Functions before output.");
545 }
546
547 // Check that all functions come from same element type
548 for (auto& v : _u)
549 {
550 std::visit(
551 [V0, this](auto& u)
552 {
553 auto element = u->function_space()->element();
554 assert(element);
555 bool is_piecewise_constant = impl::is_cellwise(*element);
556 _has_piecewise_constant
557 = _has_piecewise_constant || is_piecewise_constant;
558 if (*element != *V0->element().get() and !is_piecewise_constant)
559 {
560 throw std::runtime_error("All functions in VTXWriter must have "
561 "the same element type.");
562 }
563#ifndef NDEBUG
564 auto dmap0 = V0->dofmap()->map();
565 auto dmap = u->function_space()->dofmap()->map();
566 if ((dmap0.size() != dmap.size()
567 or !std::equal(dmap0.data_handle(),
568 dmap0.data_handle() + dmap0.size(),
569 dmap.data_handle()))
570 and !is_piecewise_constant)
571 {
572 throw std::runtime_error(
573 "All functions must have the same dofmap for VTXWriter.");
574 }
575#endif
576 },
577 v);
578 }
579
580 // Define VTK scheme attribute for set of functions
581 auto [names, dg0_names] = impl_vtx::extract_function_names<T>(u);
582 std::string vtk_scheme;
583 vtk_scheme = impl_vtx::create_vtk_schema(names, dg0_names).str();
584
585 impl_adios2::define_attribute<std::string>(*_io, "vtk.xml", vtk_scheme);
586 }
587
602 VTXWriter(MPI_Comm comm, const std::filesystem::path& filename,
603 const typename adios2_writer::U<T>& u,
604 VTXMeshPolicy mesh_policy = VTXMeshPolicy::update)
605 : VTXWriter(comm, filename, u, "BPFile", mesh_policy)
606 {
607 }
608
609 // Copy constructor
610 VTXWriter(const VTXWriter&) = delete;
611
613 VTXWriter(VTXWriter&& file) = default;
614
616 ~VTXWriter() = default;
617
619 VTXWriter& operator=(VTXWriter&&) = default;
620
621 // Copy assignment
622 VTXWriter& operator=(const VTXWriter&) = delete;
623
626 void write(double t)
627 {
628 assert(_io);
629 adios2::Variable var_step
630 = impl_adios2::define_variable<double>(*_io, "step");
631
632 spdlog::debug("ADIOS2: step");
633 assert(_engine);
634 _engine->BeginStep();
635 _engine->template Put<double>(var_step, t);
636
637 // If we have no non-constant functions write the mesh to file
638 auto [names, dg0_names] = impl_vtx::extract_function_names<T>(_u);
639 if ((names.size() == 0) or _u.empty())
640 {
641 spdlog::debug("ADIOS2: write_mesh");
642 impl_vtx::vtx_write_mesh(*_io, *_engine, *_mesh);
643 }
644 else
645 {
646 if (_mesh_reuse_policy == VTXMeshPolicy::update
647 or !(_io->template InquireVariable<std::int64_t>("connectivity")))
648 {
649 // Write a single mesh for functions as they share finite
650 // element
651 std::tie(_x_id, _x_ghost) = std::visit(
652 [&](auto& u)
653 {
654 spdlog::debug("ADIOS2: write_mesh_from_space");
655 return impl_vtx::vtx_write_mesh_from_space(*_io, *_engine,
656 *u->function_space());
657 },
658 _u[0]);
659 }
660 else
661 {
662 // Node global ids
663 adios2::Variable orig_id = impl_adios2::define_variable<std::int64_t>(
664 *_io, "vtkOriginalPointIds", {}, {}, {_x_id.size()});
665 _engine->Put(orig_id, _x_id.data());
666 adios2::Variable ghost = impl_adios2::define_variable<std::uint8_t>(
667 *_io, "vtkGhostType", {}, {}, {_x_ghost.size()});
668 _engine->Put(ghost, _x_ghost.data());
669 _engine->PerformPuts();
670 }
671 }
672
673 spdlog::debug("Write function data");
674 // Write function data for each function to file
675 for (auto& v : _u)
676 {
677 std::visit([&](auto& u) { impl_vtx::vtx_write_data(*_io, *_engine, *u); },
678 v);
679 }
680
681 _engine->EndStep();
682 }
683
684private:
685 std::shared_ptr<const mesh::Mesh<T>> _mesh;
686 adios2_writer::U<T> _u;
687
688 // Control whether the mesh is written to file once or at every time
689 // step
690 VTXMeshPolicy _mesh_reuse_policy;
691 std::vector<std::int64_t> _x_id;
692 std::vector<std::uint8_t> _x_ghost;
693
694 // Special handling of piecewise constant functions
695 bool _has_piecewise_constant;
696};
697
699template <typename U, typename T>
700VTXWriter(MPI_Comm comm, U filename, T mesh)
701 -> VTXWriter<typename std::remove_cvref<
702 typename T::element_type>::type::geometry_type::value_type>;
703
704} // namespace dolfinx::io
705
706#endif
std::shared_ptr< const mesh::Mesh< T > > extract_common_mesh(const typename adios2_writer::U< T > &u)
Extract common mesh from list of Functions.
Definition ADIOS2Writers.h:134
std::pair< std::vector< std::int64_t >, std::vector< std::uint8_t > > vtx_write_mesh_from_space(adios2::IO &io, adios2::Engine &engine, const fem::FunctionSpace< T > &V)
Given a FunctionSpace, create a topology and geometry based on the function space dof coordinates....
Definition ADIOS2Writers.h:368
adios2::Variable< T > define_variable(adios2::IO &io, std::string name, const adios2::Dims &shape=adios2::Dims(), const adios2::Dims &start=adios2::Dims(), const adios2::Dims &count=adios2::Dims())
Definition ADIOS2Writers.h:116
void vtx_write_mesh(adios2::IO &io, adios2::Engine &engine, const mesh::Mesh< T > &mesh)
Definition ADIOS2Writers.h:292
adios2::Attribute< T > define_attribute(adios2::IO &io, std::string name, const T &value, std::string var_name="", std::string separator="/")
Definition ADIOS2Writers.h:103
constexpr std::array field_ext
Definition ADIOS2Writers.h:98
void vtx_write_data(adios2::IO &io, adios2::Engine &engine, const fem::Function< T, X > &u)
Definition ADIOS2Writers.h:224
std::tuple< std::vector< std::string >, std::vector< std::string > > extract_function_names(const typename adios2_writer::U< T > &u)
Extract name of functions and split into real and imaginary component.
Definition ADIOS2Writers.h:173
Degree-of-freedom map representations and tools.
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:34
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
The mesh.
Definition FunctionSpace.h:361
Definition Function.h:47
std::shared_ptr< const FunctionSpace< geometry_type > > function_space() const
Access the function space.
Definition Function.h:147
std::string name
Name.
Definition Function.h:745
std::shared_ptr< const la::Vector< value_type > > x() const
Underlying vector (const version).
Definition Function.h:153
void close()
Close the file.
Definition ADIOS2Writers.cpp:32
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:34
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Finite element method functionality.
Definition assemble_expression_impl.h:23
Geometry data structures and algorithms.
Definition BoundingBoxTree.h:22
Functions for the re-ordering of input mesh topology to the DOLFINx ordering, and transpose orderings...
Definition cells.h:119
std::int8_t get_vtk_cell_type(mesh::CellType cell, int dim)
Get VTK cell identifier.
Definition cells.cpp:709
Support for file IO.
Definition ADIOS2Writers.h:43
std::tuple< std::vector< T >, std::array< std::size_t, 2 >, std::vector< std::int64_t >, std::vector< std::uint8_t >, std::vector< std::int64_t >, std::array< std::size_t, 2 > > vtk_mesh_from_space(const fem::FunctionSpace< T > &V)
Given a FunctionSpace, create a topology and geometry based on the dof coordinates.
Definition vtk_utils.h:196
std::pair< std::vector< std::int64_t >, std::array< std::size_t, 2 > > extract_vtk_connectivity(md::mdspan< const std::int32_t, md::dextents< std::size_t, 2 > > dofmap_x, mesh::CellType cell_type)
Extract the cell topology (connectivity) in VTK ordering for all cells the mesh. The 'topology' inclu...
Definition vtk_utils.cpp:23
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32