Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/v0.6.0/v0.9.0/cpp
DOLFINx 0.6.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
xdmf_read.h
1// Copyright (C) 2012-2018 Chris N. Richardson 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#include "xdmf_utils.h"
10#include <boost/algorithm/string.hpp>
11#include <boost/lexical_cast.hpp>
12#include <dolfinx/common/IndexMap.h>
13#include <dolfinx/mesh/Geometry.h>
14#include <dolfinx/mesh/Mesh.h>
15#include <dolfinx/mesh/Topology.h>
16#include <pugixml.hpp>
17
20{
21
23template <typename T>
24std::vector<T> get_dataset(MPI_Comm comm, const pugi::xml_node& dataset_node,
25 const hid_t h5_id,
26 std::array<std::int64_t, 2> range = {{0, 0}})
27{
28 // FIXME: Need to sort out datasset dimensions - can't depend on HDF5
29 // shape, and a Topology data item is not required to have a
30 // 'Dimensions' attribute since the dimensions can be determined from
31 // the number of cells and the cell type (for topology, one must
32 // supply cell type + (number of cells or dimensions).
33 //
34 // A geometry data item must have 'Dimensions' attribute.
35
36 assert(dataset_node);
37 pugi::xml_attribute format_attr = dataset_node.attribute("Format");
38 assert(format_attr);
39
40 // Get data set shape from 'Dimensions' attribute (empty if not
41 // available)
42 const std::vector shape_xml = xdmf_utils::get_dataset_shape(dataset_node);
43
44 const std::string format = format_attr.as_string();
45 std::vector<T> data_vector;
46 // Only read ASCII on process 0
47 const int mpi_rank = dolfinx::MPI::rank(comm);
48 if (format == "XML")
49 {
50 if (mpi_rank == 0)
51 {
52 // Read data and trim any leading/trailing whitespace
53 pugi::xml_node data_node = dataset_node.first_child();
54 assert(data_node);
55 std::string data_str = data_node.value();
56
57 // Split data based on spaces and line breaks
58 std::vector<boost::iterator_range<std::string::iterator>> data_vector_str;
59 boost::split(data_vector_str, data_str, boost::is_any_of(" \n"));
60
61 // Add data to numerical vector
62 data_vector.reserve(data_vector_str.size());
63 for (auto& v : data_vector_str)
64 {
65 if (v.begin() != v.end())
66 data_vector.push_back(
67 boost::lexical_cast<T>(boost::copy_range<std::string>(v)));
68 }
69 }
70 }
71 else if (format == "HDF")
72 {
73 // Get file and data path
74 auto paths = xdmf_utils::get_hdf5_paths(dataset_node);
75
76 // Get data shape from HDF5 file
77 const std::vector shape_hdf5
78 = HDF5Interface::get_dataset_shape(h5_id, paths[1]);
79
80 // FIXME: should we support empty data sets?
81 // Check that data set is not empty
82 assert(!shape_hdf5.empty());
83 assert(shape_hdf5[0] != 0);
84
85 // Determine range of data to read from HDF5 file. This is
86 // complicated by the XML Dimension attribute and the HDF5 storage
87 // possibly having different shapes, e.g. the HDF5 storage may be a
88 // flat array.
89
90 // If range = {0, 0} then no range is supplied and we must determine
91 // the range
92 if (range[0] == 0 and range[1] == 0)
93 {
94 if (shape_xml == shape_hdf5)
95 {
96 range = dolfinx::MPI::local_range(mpi_rank, shape_hdf5[0],
97 dolfinx::MPI::size(comm));
98 }
99 else if (!shape_xml.empty() and shape_hdf5.size() == 1)
100 {
101 // Size of dims > 0
102 std::int64_t d = std::reduce(shape_xml.begin(), shape_xml.end(),
103 std::int64_t(1), std::multiplies{});
104
105 // Check for data size consistency
106 if (d * shape_xml[0] != shape_hdf5[0])
107 {
108 throw std::runtime_error("Data size in XDMF/XML and size of HDF5 "
109 "dataset are inconsistent");
110 }
111
112 // Compute data range to read
113 range = dolfinx::MPI::local_range(mpi_rank, shape_xml[0],
114 dolfinx::MPI::rank(comm));
115 range[0] *= d;
116 range[1] *= d;
117 }
118 else
119 {
120 throw std::runtime_error(
121 "This combination of array shapes in XDMF and HDF5 "
122 "is not supported");
123 }
124 }
125
126 // Retrieve data
127 data_vector = HDF5Interface::read_dataset<T>(h5_id, paths[1], range);
128 }
129 else
130 throw std::runtime_error("Storage format \"" + format + "\" is unknown");
131
132 // Get dimensions for consistency (if available in DataItem node)
133 if (shape_xml.empty())
134 {
135 std::int64_t size = 1;
136 for (auto dim : shape_xml)
137 size *= dim;
138
139 std::int64_t size_global = 0;
140 const std::int64_t size_local = data_vector.size();
141 MPI_Allreduce(&size_local, &size_global, 1, MPI_INT64_T, MPI_SUM, comm);
142 if (size != size_global)
143 {
144 throw std::runtime_error(
145 "Data sizes in attribute and size of data read are inconsistent");
146 }
147 }
148
149 return data_vector;
150}
151//----------------------------------------------------------------------------
152
153} // namespace dolfinx::io::xdmf_read
static std::vector< std::int64_t > get_dataset_shape(const hid_t handle, const std::string &dataset_path)
Get dataset shape (size of each dimension)
Definition: HDF5Interface.cpp:203
int size(MPI_Comm comm)
Return size of the group (number of processes) associated with the communicator.
Definition: MPI.cpp:71
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition: MPI.cpp:63
constexpr std::array< std::int64_t, 2 > local_range(int rank, std::int64_t N, int size)
Return local range for the calling process, partitioning the global [0, N - 1] range across all ranks...
Definition: MPI.h:90
Low-level methods for reading XDMF files.
Definition: xdmf_read.h:20
std::vector< T > get_dataset(MPI_Comm comm, const pugi::xml_node &dataset_node, const hid_t h5_id, std::array< std::int64_t, 2 > range={{0, 0}})
Return data associated with a data set node.
Definition: xdmf_read.h:24