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