OGS
NetCDFRasterReader.cpp
Go to the documentation of this file.
1
11
12#include <spdlog/fmt/bundled/ranges.h>
13
14#include <filesystem>
15#include <numeric>
16#ifdef OGS_USE_NETCDF
17#include <netcdf>
18#endif
19
20#include "BaseLib/ConfigTree.h"
21#include "BaseLib/StringTools.h"
22#include "GeoLib/AABB.h"
24
25namespace
26{
27#ifdef OGS_USE_NETCDF
28
30 std::multimap<std::string, netCDF::NcVar> const& variables)
31{
33
34 // remark: netcdf raster starts in the left upper corner
35 double cell_size_y = 0;
36 // first read:
37 // - origin, cell_size from GeoTransform attribute
38 // - header.no_data from _FillValue attribute
39 for (auto [variable_name, variable] : variables)
40 {
41 if (variable.isNull())
42 {
43 OGS_FATAL("Variable '{}' not found in file.", variable_name);
44 }
45 auto const& attributes = variable.getAtts();
46 for (auto [name, attribute] : attributes)
47 {
48 if (name == "GeoTransform")
49 {
50 std::vector<char> attribute_values;
51 attribute_values.resize(attribute.getAttLength());
52 attribute.getValues(attribute_values.data());
53 std::string const str_attribute_values(attribute_values.begin(),
54 attribute_values.end());
55 auto const strings = BaseLib::splitString(str_attribute_values);
56 header.origin[0] = std::stod(strings[0]); // origin x
57 header.cell_size = std::stod(strings[1]); // cell size x
58 header.origin[1] = std::stod(strings[3]); // origin y
59 cell_size_y = std::stod(strings[5]); // cell size y
60 DBUG(
61 "GeoTransform attribute values: origin_x: {}, origin_y: "
62 "{}, cell_size_x: {}, cell_size_y: {}",
63 header.origin[0], header.origin[1], header.cell_size,
64 cell_size_y);
65 }
66 if (name == "_FillValue")
67 {
68 attribute.getValues(&header.no_data);
69 }
70 }
71 }
72
73 return header;
74}
75
76std::vector<double> readDataFromNetCDF(
77 std::multimap<std::string, netCDF::NcVar> const& variables,
78 std::string_view const var_name, std::size_t const dimension_number,
79 GeoLib::MinMaxPoints const& min_max_points, GeoLib::RasterHeader& header)
80{
81 // second read raster header values
82 std::vector<double> raster_data;
83 for (auto [variable_name, variable] : variables)
84 {
85 // uncomment for debugging
86 // DBUG("checking variable '{}'", variable_name);
87 if (variable_name == var_name)
88 {
89 auto const n_dims = variable.getDimCount();
90 if (n_dims == 0)
91 {
92 continue;
93 }
94 // DBUG("variable '{}' has {} dimensions", variable_name, n_dims);
95
96 std::vector<std::size_t> counts(n_dims, 1);
97 for (int i = 0; i < n_dims; ++i)
98 {
99 counts[i] = variable.getDim(i).getSize();
100 }
101 // DBUG("counts {}", fmt::join(counts, ", "));
102 std::vector<std::size_t> start(n_dims, 0);
103 if (dimension_number > counts[0])
104 {
105 OGS_FATAL(
106 "variable '{}' has {} dimensions, requested dimension "
107 "number is {}",
108 variable_name, counts[0], dimension_number);
109 }
110 // time dimension
111 start[0] = dimension_number; // number of time step
112 counts[0] = 1; // read one time step
113
114 // y dimension - netcdf dimension number 1
115 // With the counts[1] and cell_size the 'usual' lower y-coordinate
116 // of the origin is computed.
117 // DBUG("reset header.origin[1]: original y0: {}, new y0: {} ",
118 // header.origin[1],
119 // header.origin[1] - counts[1] * header.cell_size);
120 header.origin[1] -= counts[1] * header.cell_size;
121
122 counts[2] = static_cast<int>(
123 std::ceil((min_max_points.max[0] - min_max_points.min[0]) /
124 header.cell_size) +
125 1);
126 counts[1] = static_cast<int>(
127 std::ceil((min_max_points.max[1] - min_max_points.min[1]) /
128 header.cell_size) +
129 1);
130 // x dimension - netcdf dimension number 2
131 start[2] = static_cast<int>(std::floor(
132 (min_max_points.min[0] - header.origin[0]) / header.cell_size));
133 // y dimension - netcdf dimension number 1
134 start[1] = static_cast<int>(std::floor(
135 (min_max_points.min[1] - header.origin[1]) / header.cell_size));
136
137 // DBUG("cut-out raster: pixel in x dimension: {} ", counts[2]);
138 // DBUG("cut-out raster: pixel in y dimension: {} ", counts[1]);
139 // DBUG("cut-out raster: start index x dimension: {}", start[2]);
140 // DBUG("cut-out raster: start index y dimension: {}", start[1]);
141
142 header.n_cols = counts[2];
143 header.n_rows = counts[1];
144 header.origin[0] += start[2] * header.cell_size;
145 // reset header y origin for cut out raster
146 header.origin[1] += start[1] * header.cell_size;
147 std::size_t const total_length =
148 std::accumulate(counts.cbegin(), counts.cend(), 1,
149 std::multiplies<std::size_t>());
150 raster_data.resize(total_length);
151 variable.getVar(start, counts, raster_data.data());
152
153 std::replace(raster_data.begin(), raster_data.end(), header.no_data,
154 0.0);
155 }
156 }
157 return raster_data;
158}
159
160std::unique_ptr<GeoLib::Raster> readNetCDF(
161 std::filesystem::path const& filepath,
162 std::string_view const var_name,
163 std::size_t const dimension_number,
164 GeoLib::MinMaxPoints const& min_max_points)
165{
166 netCDF::NcFile dataset(filepath.string(), netCDF::NcFile::read);
167 if (dataset.isNull())
168 {
169 OGS_FATAL("Error opening file '{}'.", filepath.string());
170 }
171
172 auto const& variables = dataset.getVars();
173 GeoLib::RasterHeader header = readHeaderFromNetCDF(variables);
174 std::vector<double> raster_data = readDataFromNetCDF(
175 variables, var_name, dimension_number, min_max_points, header);
176
177 return std::make_unique<GeoLib::Raster>(header, raster_data.begin(),
178 raster_data.end());
179}
180#endif
181
183 std::filesystem::path const& path,
184 std::filesystem::path filename,
185 std::string const& var_name,
186 std::size_t const dimension_number,
187 [[maybe_unused]] GeoLib::MinMaxPoints const& min_max_points)
188{
189 INFO("readRasterFromFile: '{}/{}'", path.string(), filename.string());
190
191 if (filename.extension() == ".nc")
192 {
193#ifdef OGS_USE_NETCDF
194 auto raster = readNetCDF(path / filename, var_name, dimension_number,
195 min_max_points);
196
197 return GeoLib::NamedRaster{filename.replace_extension().string() + "_" +
198 var_name + "_" +
199 std::to_string(dimension_number),
200 std::move(raster)};
201#else
202 OGS_FATAL("OGS was not build with NetCDF support. Can not read {}",
203 (path / filename).string());
204#endif
205 }
206 auto raster = std::unique_ptr<GeoLib::Raster>(
207 FileIO::AsciiRasterInterface::readRaster((path / filename).string()));
208 if (raster == nullptr)
209 {
210 OGS_FATAL("Could not read raster from file '{}'.",
211 (path / filename).string());
212 }
213 return GeoLib::NamedRaster{filename.replace_extension().string() + "_" +
214 var_name + "_" +
215 std::to_string(dimension_number),
216 std::move(raster)};
217}
218} // anonymous namespace
219
220namespace GeoLib::IO
221{
223 std::string const& raster_directory,
224 GeoLib::MinMaxPoints const& min_max_points)
225{
226 auto const file_name =
228 raster_config.getConfigParameter<std::string>("file");
229 auto const variable_name =
231 raster_config.getConfigParameter<std::string>("variable");
232 auto const dimension =
234 raster_config.getConfigParameter<std::size_t>("dimension", 1);
235 return readRasterFromFile(raster_directory, file_name, variable_name,
236 dimension, min_max_points);
237}
238} // namespace GeoLib::IO
Definition of the AABB class.
Definition of the AsciiRasterInterface class.
#define OGS_FATAL(...)
Definition Error.h:26
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
Definition of string helper functions.
T getConfigParameter(std::string const &param) const
static GeoLib::Raster * readRaster(std::string const &fname)
std::vector< std::string > splitString(std::string const &str)
GeoLib::NamedRaster readRaster(BaseLib::ConfigTree const &raster_config, std::string const &raster_directory, GeoLib::MinMaxPoints const &min_max_points)
std::vector< double > readDataFromNetCDF(std::multimap< std::string, netCDF::NcVar > const &variables, std::string_view const var_name, std::size_t const dimension_number, GeoLib::MinMaxPoints const &min_max_points, GeoLib::RasterHeader &header)
GeoLib::NamedRaster readRasterFromFile(std::filesystem::path const &path, std::filesystem::path filename, std::string const &var_name, std::size_t const dimension_number, GeoLib::MinMaxPoints const &min_max_points)
std::unique_ptr< GeoLib::Raster > readNetCDF(std::filesystem::path const &filepath, std::string_view const var_name, std::size_t const dimension_number, GeoLib::MinMaxPoints const &min_max_points)
GeoLib::RasterHeader readHeaderFromNetCDF(std::multimap< std::string, netCDF::NcVar > const &variables)
Eigen::Vector3d max
Definition AABB.h:37
Eigen::Vector3d min
Definition AABB.h:36
Contains the relevant information when storing a geoscientific raster data.
Definition Raster.h:28
MathLib::Point3d origin
Definition Raster.h:32
std::size_t n_cols
Definition Raster.h:29
std::size_t n_rows
Definition Raster.h:30