OGS
NetCdfConverter.cpp File Reference
#include <tclap/CmdLine.h>
#include <cctype>
#include <iostream>
#include <limits>
#include <memory>
#include <netcdf>
#include <numeric>
#include <sstream>
#include <string>
#include <utility>
#include "BaseLib/FileTools.h"
#include "BaseLib/Logging.h"
#include "BaseLib/MPI.h"
#include "BaseLib/TCLAPArguments.h"
#include "GeoLib/IO/AsciiRasterInterface.h"
#include "GeoLib/Raster.h"
#include "InfoLib/GitInfo.h"
#include "MeshLib/IO/writeMeshToFile.h"
#include "MeshLib/Mesh.h"
#include "MeshLib/Utils/addPropertyToMesh.h"
#include "MeshToolsLib/MeshGenerators/RasterToMesh.h"
Include dependency graph for NetCdfConverter.cpp:

Go to the source code of this file.

Enumerations

enum class  OutputType { INVALID , IMAGES , SINGLEMESH , MULTIMESH }

Functions

static void checkExit (std::string const &str)
static void showErrorMessage (std::size_t const error_id, std::size_t const max=0)
static std::size_t parseInput (std::string const &request_str, std::size_t const max_val, bool const has_info=false)
static NcVar getDimVar (NcFile const &dataset, NcVar const &var, std::size_t const dim)
static std::pair< double, double > getDimLength (NcVar const &var, std::size_t const dim)
static std::vector< std::string > getArrays (NcFile const &dataset)
static void showArrays (NcFile const &dataset)
static void showArraysDims (NcVar const &var)
static std::pair< double, double > getBoundaries (NcVar const &var)
static MathLib::Point3d getOrigin (NcFile const &dataset, NcVar const &var, std::vector< std::size_t > const &dim_idx_map, std::size_t const time_offset)
static void flipRaster (std::vector< double > &data, std::size_t const layers, std::size_t const width, std::size_t const height)
static bool canConvert (NcVar const &var)
static std::string arraySelectionLoop (NcFile const &dataset)
static bool dimensionSelectionLoop (NcVar const &var, std::vector< std::size_t > &dim_idx_map)
static std::pair< std::size_t, std::size_t > timestepSelectionLoop (NcVar const &var, std::size_t const dim_idx)
static MeshLib::MeshElemType elemSelectionLoop (std::size_t const dim)
static OutputType multFilesSelectionLoop (std::pair< std::size_t, std::size_t > const &time_bounds)
static std::string getIterationString (std::size_t i, std::size_t max)
static double getResolution (NcFile const &dataset, NcVar const &var)
static GeoLib::RasterHeader createRasterHeader (NcFile const &dataset, NcVar const &var, std::vector< std::size_t > const &dim_idx_map, std::vector< std::size_t > const &length, std::size_t const time_offset)
static std::vector< std::size_t > getLength (NcVar const &var, std::size_t const time_offset)
static std::vector< double > getData (NcVar const &var, std::size_t const total_length, std::size_t const time_step, std::vector< std::size_t > const &length)
static bool assignDimParams (NcVar const &var, std::vector< std::size_t > &dim_idx_map, TCLAP::ValueArg< std::size_t > &arg_dim_time, TCLAP::ValueArg< std::size_t > &arg_dim1, TCLAP::ValueArg< std::size_t > &arg_dim2, TCLAP::ValueArg< std::size_t > &arg_dim3)
static std::pair< std::size_t, std::size_t > assignTimeBounds (NcVar const &var, TCLAP::ValueArg< std::size_t > &arg_time_start, TCLAP::ValueArg< std::size_t > &arg_time_end)
static MeshLib::MeshElemType assignElemType (TCLAP::ValueArg< std::string > &arg_elem_type)
static bool convert (NcFile const &dataset, NcVar const &var, std::string const &output_name, std::vector< std::size_t > const &dim_idx_map, std::size_t const time_offset, std::pair< std::size_t, std::size_t > const &time_bounds, OutputType const output, MeshLib::MeshElemType const elem_type)
int main (int argc, char *argv[])

Variables

static const double no_data_output = -9999
static double no_data_input = -9999

Enumeration Type Documentation

◆ OutputType

enum class OutputType
strong
Enumerator
INVALID 
IMAGES 
SINGLEMESH 
MULTIMESH 

Definition at line 33 of file NetCdfConverter.cpp.

Function Documentation

◆ arraySelectionLoop()

std::string arraySelectionLoop ( NcFile const & dataset)
static

Definition at line 209 of file NetCdfConverter.cpp.

210{
211 std::vector<std::string> const& names = getArrays(dataset);
212 showArrays(dataset);
213 std::size_t const idx =
214 parseInput("Enter data array index: ", dataset.getVarCount(), true);
215
216 if (static_cast<int>(idx) == dataset.getVarCount() ||
217 !canConvert(dataset.getVar(names[idx])))
218 return arraySelectionLoop(dataset);
219
220 return names[idx];
221}
static void showArrays(NcFile const &dataset)
static std::string arraySelectionLoop(NcFile const &dataset)
static std::size_t parseInput(std::string const &request_str, std::size_t const max_val, bool const has_info=false)
static std::vector< std::string > getArrays(NcFile const &dataset)
static bool canConvert(NcVar const &var)
constexpr ranges::views::view_closure names
For an element of a range view return its name.
Definition Mesh.h:222

References arraySelectionLoop(), canConvert(), getArrays(), parseInput(), and showArrays().

Referenced by arraySelectionLoop(), and main().

◆ assignDimParams()

bool assignDimParams ( NcVar const & var,
std::vector< std::size_t > & dim_idx_map,
TCLAP::ValueArg< std::size_t > & arg_dim_time,
TCLAP::ValueArg< std::size_t > & arg_dim1,
TCLAP::ValueArg< std::size_t > & arg_dim2,
TCLAP::ValueArg< std::size_t > & arg_dim3 )
static

Definition at line 452 of file NetCdfConverter.cpp.

458{
459 std::size_t dim_param_count = 0;
460 if (arg_dim_time.isSet())
461 dim_param_count++;
462 if (arg_dim1.isSet())
463 dim_param_count++;
464 if (arg_dim2.isSet())
465 dim_param_count++;
466 if (arg_dim3.isSet())
467 dim_param_count++;
468
469 std::size_t const n_dims = var.getDimCount();
470 if (dim_param_count != n_dims)
471 {
472 ERR("Number of parameters set does not fit number of parameters for "
473 "specified variable.");
474 return false;
475 }
476
477 if (arg_dim_time.getValue() >= n_dims || arg_dim1.getValue() >= n_dims ||
478 arg_dim2.getValue() >= n_dims || arg_dim3.getValue() >= n_dims)
479 {
480 ERR("Maximum allowed dimension for variable \"{:s}\" is {:d}.",
481 var.getName(), n_dims - 1);
482 return false;
483 }
484
485 if (arg_dim_time.isSet())
486 dim_idx_map[0] = arg_dim_time.getValue();
487 std::size_t const temp_offset = (arg_dim_time.isSet()) ? 1 : 0;
488 dim_idx_map[0 + temp_offset] = arg_dim1.getValue();
489 dim_idx_map[1 + temp_offset] = arg_dim2.getValue();
490 if (n_dims == (3 + temp_offset))
491 dim_idx_map[2 + temp_offset] = arg_dim3.getValue();
492
493 return true;
494}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40

References ERR().

Referenced by main().

◆ assignElemType()

MeshLib::MeshElemType assignElemType ( TCLAP::ValueArg< std::string > & arg_elem_type)
static

Definition at line 528 of file NetCdfConverter.cpp.

530{
531 if (arg_elem_type.getValue() == "tri")
533 if (arg_elem_type.getValue() == "quad")
535 if (arg_elem_type.getValue() == "prism")
537 if (arg_elem_type.getValue() == "hex")
539 // this should never happen
541}

References MeshLib::HEXAHEDRON, MeshLib::INVALID, MeshLib::PRISM, MeshLib::QUAD, and MeshLib::TRIANGLE.

Referenced by main().

◆ assignTimeBounds()

std::pair< std::size_t, std::size_t > assignTimeBounds ( NcVar const & var,
TCLAP::ValueArg< std::size_t > & arg_time_start,
TCLAP::ValueArg< std::size_t > & arg_time_end )
static

Definition at line 496 of file NetCdfConverter.cpp.

500{
501 auto const bounds = getBoundaries(var);
502 if (arg_time_start.getValue() > bounds.second)
503 {
504 ERR("Start time step larger than total number of time steps. Resetting "
505 "to 0.");
506 arg_time_start.reset();
507 }
508
509 if (!arg_time_end.isSet())
510 return {arg_time_start.getValue(), arg_time_start.getValue()};
511
512 if (arg_time_end.getValue() > bounds.second)
513 {
514 ERR("End time step larger than total number of time steps. Resetting "
515 "to starting time step");
516 return {arg_time_start.getValue(), arg_time_start.getValue()};
517 }
518
519 if (arg_time_end.getValue() < arg_time_start.getValue())
520 {
521 ERR("End time step larger than starting time step. Swapping values");
522 return {arg_time_end.getValue(), arg_time_start.getValue()};
523 }
524
525 return {arg_time_start.getValue(), arg_time_end.getValue()};
526}
static std::pair< double, double > getBoundaries(NcVar const &var)

References ERR(), and getBoundaries().

Referenced by main().

◆ canConvert()

bool canConvert ( NcVar const & var)
static

Definition at line 200 of file NetCdfConverter.cpp.

201{
202 bool ret(var.getDimCount() < 2);
203 if (ret)
204 ERR("Only 2+ dimensional variables can be converted into OGS "
205 "Meshes.\n");
206 return !ret;
207}

References ERR().

Referenced by arraySelectionLoop().

◆ checkExit()

void checkExit ( std::string const & str)
static

Definition at line 41 of file NetCdfConverter.cpp.

42{
43 if (str == "x" || str == "exit")
44 exit(0);
45}

Referenced by elemSelectionLoop(), and parseInput().

◆ convert()

bool convert ( NcFile const & dataset,
NcVar const & var,
std::string const & output_name,
std::vector< std::size_t > const & dim_idx_map,
std::size_t const time_offset,
std::pair< std::size_t, std::size_t > const & time_bounds,
OutputType const output,
MeshLib::MeshElemType const elem_type )
static

Definition at line 543 of file NetCdfConverter.cpp.

550{
551 std::unique_ptr<MeshLib::Mesh> mesh;
552 std::vector<std::size_t> const length = getLength(var, time_offset);
553 std::size_t const array_length = std::accumulate(
554 length.cbegin(), length.cend(), 1, std::multiplies<std::size_t>());
555 for (std::size_t i = time_bounds.first; i <= time_bounds.second; ++i)
556 {
557 std::string const step_str =
558 (time_bounds.first != time_bounds.second)
559 ? std::string(" time step " + std::to_string(i))
560 : "";
561 std::cout << "Converting" << step_str << "...\n";
562 std::vector<double> data_vec = getData(var, array_length, i, length);
563
564 // reverse lines in vertical direction if file has its origin in the
565 // northwest corner
566 std::size_t const n_dims = length.size();
567 NcVar const dim_var(getDimVar(dataset, var, n_dims - 2));
568 auto const bounds = (dim_var.isNull()) ? getDimLength(var, n_dims - 2)
569 : getBoundaries(dim_var);
570 if (bounds.first > bounds.second)
571 {
572 std::size_t n_layers =
573 (length.size() - time_offset == 3) ? length[n_dims - 3] : 1;
574 flipRaster(data_vec, n_layers, length[n_dims - 1],
575 length[n_dims - 2]);
576 }
577
578 GeoLib::RasterHeader const header =
579 createRasterHeader(dataset, var, dim_idx_map, length, time_offset);
580 MeshLib::UseIntensityAs const useIntensity =
582 if (output == OutputType::MULTIMESH)
583 {
584 mesh = MeshToolsLib::RasterToMesh::convert(data_vec.data(), header,
585 elem_type, useIntensity,
586 var.getName());
587 std::string const output_file_name(
588 BaseLib::dropFileExtension(output_name) +
589 getIterationString(i, time_bounds.second) + ".vtu");
590 if (MeshLib::IO::writeMeshToFile(*mesh.get(), output_file_name) !=
591 0)
592 {
593 return false;
594 }
595 }
596 else if (output == OutputType::SINGLEMESH)
597 {
598 std::string array_name(var.getName());
599 if (time_bounds.first != time_bounds.second)
600 array_name.append(getIterationString(i, time_bounds.second));
601 if (i == time_bounds.first) // create persistent mesh
603 data_vec.data(), header, elem_type, useIntensity,
604 array_name);
605 else // copy array to mesh
606 {
607 std::unique_ptr<MeshLib::Mesh> const temp(
608 MeshToolsLib::RasterToMesh::convert(data_vec.data(), header,
609 elem_type, useIntensity,
610 array_name));
611 MeshLib::PropertyVector<double> const* const vec =
612 temp->getProperties().getPropertyVector<double>(array_name);
613 if (vec == nullptr)
614 {
615 return false;
616 }
618 *mesh, array_name, MeshLib::MeshItemType::Cell, 1, *vec);
619 }
620 if (i == time_bounds.second)
621 {
622 std::string const output_file_name =
623 (BaseLib::getFileExtension(output_name) == ".vtu")
624 ? output_name
625 : output_name + ".vtu";
626 if (MeshLib::IO::writeMeshToFile(*mesh.get(),
627 output_file_name) != 0)
628 {
629 return false;
630 }
631 }
632 }
633 else // OutputType::IMAGES
634 {
635 GeoLib::Raster const raster(header, data_vec.data(),
636 data_vec.data() + header.n_cols *
637 header.n_rows *
638 header.n_depth);
639 std::string const output_file_name(
640 BaseLib::dropFileExtension(output_name) +
641 getIterationString(i, time_bounds.second) + ".asc");
643 output_file_name);
644 }
645 }
646 return true;
647}
static GeoLib::RasterHeader createRasterHeader(NcFile const &dataset, NcVar const &var, std::vector< std::size_t > const &dim_idx_map, std::vector< std::size_t > const &length, std::size_t const time_offset)
static std::pair< double, double > getDimLength(NcVar const &var, std::size_t const dim)
static std::string getIterationString(std::size_t i, std::size_t max)
static std::vector< std::size_t > getLength(NcVar const &var, std::size_t const time_offset)
static NcVar getDimVar(NcFile const &dataset, NcVar const &var, std::size_t const dim)
static std::vector< double > getData(NcVar const &var, std::size_t const total_length, std::size_t const time_step, std::vector< std::size_t > const &length)
static void writeRasterAsASC(GeoLib::Raster const &raster, std::string const &file_name)
Writes an Esri asc-file.
Class Raster is used for managing raster data.
Definition Raster.h:39
static std::unique_ptr< MeshLib::Mesh > convert(GeoLib::Raster const &raster, MeshLib::MeshElemType elem_type, MeshLib::UseIntensityAs intensity_type, std::string const &array_name="Colour")
std::string getFileExtension(const std::string &path)
std::string dropFileExtension(std::string const &filename)
int writeMeshToFile(const MeshLib::Mesh &mesh, std::filesystem::path const &file_path, std::set< std::string > output_variable_names, bool const use_compression, int const data_mode)
void addPropertyToMesh(Mesh &mesh, std::string_view name, MeshItemType item_type, std::size_t number_of_components, std::span< T const > values)
UseIntensityAs
Selection of possible interpretations for intensities.
Definition MeshEnums.h:94
Contains the relevant information when storing a geoscientific raster data.
Definition Raster.h:18

References MeshLib::addPropertyToMesh(), MeshLib::Cell, MeshToolsLib::RasterToMesh::convert(), createRasterHeader(), MeshLib::DATAVECTOR, BaseLib::dropFileExtension(), flipRaster(), getBoundaries(), getData(), getDimLength(), getDimVar(), BaseLib::getFileExtension(), getIterationString(), getLength(), MULTIMESH, GeoLib::RasterHeader::n_cols, GeoLib::RasterHeader::n_depth, GeoLib::RasterHeader::n_rows, SINGLEMESH, MeshLib::IO::writeMeshToFile(), and FileIO::AsciiRasterInterface::writeRasterAsASC().

Referenced by main().

◆ createRasterHeader()

GeoLib::RasterHeader createRasterHeader ( NcFile const & dataset,
NcVar const & var,
std::vector< std::size_t > const & dim_idx_map,
std::vector< std::size_t > const & length,
std::size_t const time_offset )
static

Definition at line 403 of file NetCdfConverter.cpp.

407{
408 MathLib::Point3d const origin =
409 getOrigin(dataset, var, dim_idx_map, time_offset);
410 double const res = getResolution(dataset, var);
411 std::size_t n_dims = var.getDimCount();
412 std::size_t z_length =
413 (n_dims - time_offset == 3) ? length[dim_idx_map.back()] : 1;
414 return {length[dim_idx_map[0 + time_offset]],
415 length[dim_idx_map[1 + time_offset]],
416 z_length,
417 origin,
418 res,
420}
static MathLib::Point3d getOrigin(NcFile const &dataset, NcVar const &var, std::vector< std::size_t > const &dim_idx_map, std::size_t const time_offset)
static const double no_data_output
static double getResolution(NcFile const &dataset, NcVar const &var)

References getOrigin(), getResolution(), and no_data_output.

Referenced by convert().

◆ dimensionSelectionLoop()

bool dimensionSelectionLoop ( NcVar const & var,
std::vector< std::size_t > & dim_idx_map )
static

Definition at line 223 of file NetCdfConverter.cpp.

225{
226 showArraysDims(var);
227 std::size_t const n_dims(var.getDimCount());
228 dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
229 bool is_time_dep(true);
230
231 // get temporal dimension
232 if (n_dims > 1)
233 {
234 std::string temp_str("");
235 std::cout << "Is the parameter time-dependent?\n";
236 while (dim_idx_map[0] == std::numeric_limits<std::size_t>::max() &&
237 is_time_dep == true)
238 {
239 std::cout
240 << "Enter ID for temporal dimension or \"c\" to continue: ";
241 std::getline(std::cin, temp_str);
242 std::stringstream str_stream(temp_str);
243 if (str_stream.str() == "c" || str_stream.str() == "continue")
244 is_time_dep = false;
245 else
246 {
247 if (!(str_stream >> dim_idx_map[0]))
248 {
250 dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
251 continue;
252 }
253 if (dim_idx_map[0] > n_dims - 1)
254 {
255 showErrorMessage(1, var.getDimCount() - 1);
256 dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
257 }
258 }
259 }
260 }
261 else
262 is_time_dep = false;
263
264 // get spatial dimension(s)
265 std::size_t const start_idx = (is_time_dep) ? 1 : 0;
266 std::array<std::string, 4> const dim_comment{
267 "(x / longitude)", "(y / latitude)", "(z / height / depth)",
268 "[Error: 4-dimensional non-temporal arrays are not supported]"};
269 for (std::size_t i = start_idx; i < n_dims; ++i)
270 {
271 dim_idx_map[i] = std::numeric_limits<std::size_t>::max();
272
273 std::string const request_str("Enter ID for dimension " +
274 std::to_string(i) + " " +
275 dim_comment[i - start_idx] + ": ");
276 std::size_t const idx =
277 parseInput(request_str, var.getDimCount(), true);
278
279 if (static_cast<int>(idx) == var.getDimCount())
280 {
281 showArraysDims(var);
282 i--;
283 continue;
284 }
285 dim_idx_map[i] = idx;
286 }
287
288 return is_time_dep;
289}
static void showErrorMessage(std::size_t const error_id, std::size_t const max=0)
static void showArraysDims(NcVar const &var)

References parseInput(), showArraysDims(), and showErrorMessage().

Referenced by main().

◆ elemSelectionLoop()

MeshLib::MeshElemType elemSelectionLoop ( std::size_t const dim)
static

Definition at line 311 of file NetCdfConverter.cpp.

312{
313 if (dim == 1)
315
318 {
319 std::cout << "\nSelect element type for result, choose ";
320
321 if (dim == 2)
322 std::cout << "(t)riangle or (q)uadliteral: ";
323 if (dim == 3)
324 std::cout << "(p)rism or (h)exahedron: ";
325 std::string type("");
326 std::getline(std::cin, type);
327 checkExit(type);
328 if (dim == 2)
329 {
330 if (type != "t" && type != "q" && type != "tri" && type != "quad" &&
331 type != "triangle" && type != "quatliteral")
332 continue;
333 if (type == "t" || type == "tri" || type == "triangle")
336 }
337
338 if (dim == 3)
339 {
340 if (type != "p" && type != "h" && type != "prism" &&
341 type != "hex" && type != "hexahedron")
342 continue;
343 if (type == "p" || type == "prism")
346 }
347 }
348 return t;
349}
static void checkExit(std::string const &str)
MeshElemType
Types of mesh elements supported by OpenGeoSys. Values are from VTKCellType enum.
Definition MeshEnums.h:38

References checkExit(), MeshLib::HEXAHEDRON, MeshLib::INVALID, MeshLib::LINE, MeshLib::PRISM, MeshLib::QUAD, and MeshLib::TRIANGLE.

Referenced by main().

◆ flipRaster()

void flipRaster ( std::vector< double > & data,
std::size_t const layers,
std::size_t const width,
std::size_t const height )
static

Definition at line 179 of file NetCdfConverter.cpp.

181{
182 std::size_t const length(data.size());
183 std::vector<double> tmp_vec;
184 tmp_vec.reserve(length);
185 for (std::size_t k = 0; k < layers; k++)
186 {
187 std::size_t const layer_end = (k + 1) * height * width;
188 for (std::size_t i = 0; i < height; i++)
189 {
190 std::size_t const line_idx(layer_end - (width * (i + 1)));
191 for (std::size_t j = 0; j < width; j++)
192 {
193 tmp_vec.push_back(data[line_idx + j]);
194 }
195 }
196 }
197 std::copy(tmp_vec.cbegin(), tmp_vec.cend(), data.begin());
198}

Referenced by convert().

◆ getArrays()

std::vector< std::string > getArrays ( NcFile const & dataset)
static

Definition at line 109 of file NetCdfConverter.cpp.

110{
111 auto const& names = dataset.getVars();
112 std::vector<std::string> var_names;
113 for (auto [name, var] : names)
114 {
115 (void)var;
116 var_names.push_back(name);
117 }
118 return var_names;
119}

Referenced by arraySelectionLoop().

◆ getBoundaries()

std::pair< double, double > getBoundaries ( NcVar const & var)
static

Definition at line 149 of file NetCdfConverter.cpp.

150{
151 if (var.getDimCount() == 1)
152 {
153 double start, end;
154 std::size_t const size = var.getDim(0).getSize();
155 var.getVar({0}, {1}, &start);
156 var.getVar({size - 1}, {1}, &end);
157 return std::make_pair(start, end);
158 }
159 return std::make_pair(0, 0);
160}
constexpr int size(int const displacement_dim)
Vectorized tensor size for given displacement dimension.

Referenced by assignTimeBounds(), convert(), getOrigin(), and getResolution().

◆ getData()

std::vector< double > getData ( NcVar const & var,
std::size_t const total_length,
std::size_t const time_step,
std::vector< std::size_t > const & length )
static

Definition at line 434 of file NetCdfConverter.cpp.

438{
439 std::size_t const n_dims(var.getDimCount());
440 std::vector<std::size_t> offset(n_dims, 0);
441 offset[0] = time_step;
442 std::vector<double> data_vec(total_length, 0);
443 var.getVar(offset, length, data_vec.data());
444
445 std::replace_if(
446 data_vec.begin(), data_vec.end(),
447 [](double const& x) { return x == no_data_input; }, no_data_output);
448
449 return data_vec;
450}

References no_data_output.

Referenced by convert().

◆ getDimLength()

std::pair< double, double > getDimLength ( NcVar const & var,
std::size_t const dim )
static

Definition at line 103 of file NetCdfConverter.cpp.

105{
106 return std::make_pair(0.0, static_cast<double>(var.getDim(dim).getSize()));
107}

Referenced by convert(), getOrigin(), and getResolution().

◆ getDimVar()

NcVar getDimVar ( NcFile const & dataset,
NcVar const & var,
std::size_t const dim )
static

Definition at line 96 of file NetCdfConverter.cpp.

98{
99 NcDim const& dim_obj = var.getDim(dim);
100 return dataset.getVar(dim_obj.getName());
101}

Referenced by convert(), getOrigin(), getResolution(), and main().

◆ getIterationString()

std::string getIterationString ( std::size_t i,
std::size_t max )
static

Definition at line 380 of file NetCdfConverter.cpp.

381{
382 std::size_t const max_length(std::to_string(max).length());
383 std::string const current_str(std::to_string(i));
384 return std::string(max_length - current_str.length(), '0') + current_str;
385}

Referenced by convert().

◆ getLength()

std::vector< std::size_t > getLength ( NcVar const & var,
std::size_t const time_offset )
static

Definition at line 422 of file NetCdfConverter.cpp.

424{
425 std::size_t const n_dims = (var.getDimCount());
426 std::vector<std::size_t> length(n_dims, 1);
427 for (std::size_t i = time_offset; i < n_dims; ++i)
428 {
429 length[i] = var.getDim(i).getSize();
430 }
431 return length;
432}

Referenced by convert().

◆ getOrigin()

MathLib::Point3d getOrigin ( NcFile const & dataset,
NcVar const & var,
std::vector< std::size_t > const & dim_idx_map,
std::size_t const time_offset )
static

Definition at line 162 of file NetCdfConverter.cpp.

165{
167 std::size_t const n_dims = var.getDimCount();
168 for (std::size_t i = time_offset; i < n_dims; ++i)
169 {
170 NcVar const& dim = getDimVar(dataset, var, dim_idx_map[i]);
171 auto const bounds = (dim.isNull()) ? getDimLength(var, dim_idx_map[i])
172 : getBoundaries(dim);
173 origin[i - time_offset] =
174 (bounds.first < bounds.second) ? bounds.first : bounds.second;
175 }
176 return origin;
177}
const Point3d ORIGIN
Definition Point3d.h:89

References getBoundaries(), getDimLength(), getDimVar(), and MathLib::ORIGIN.

Referenced by createRasterHeader().

◆ getResolution()

double getResolution ( NcFile const & dataset,
NcVar const & var )
static

Definition at line 387 of file NetCdfConverter.cpp.

388{
389 std::size_t const dim_idx = var.getDimCount() - 1;
390 NcVar const dim_var(getDimVar(dataset, var, dim_idx));
391 auto const bounds = (dim_var.isNull()) ? getDimLength(var, dim_idx)
392 : getBoundaries(dim_var);
393 std::size_t const dim_size = var.getDim(dim_idx).getSize();
394 if (dim_size == 0)
395 {
396 OGS_FATAL("Dimension '{:s}' has size 0. Aborting...",
397 var.getDim(dim_idx).getName());
398 }
399 return std::fabs(bounds.second - bounds.first) /
400 static_cast<double>(dim_size);
401}
#define OGS_FATAL(...)
Definition Error.h:19

References getBoundaries(), getDimLength(), getDimVar(), and OGS_FATAL.

Referenced by createRasterHeader().

◆ main()

int main ( int argc,
char * argv[] )

Definition at line 649 of file NetCdfConverter.cpp.

650{
651 TCLAP::CmdLine cmd(
652 "Converts NetCDF data into mesh file(s).\n\n "
653 "OpenGeoSys-6 software, version " +
655 ".\n"
656 "Copyright (c) 2012-2026, OpenGeoSys Community "
657 "(http://www.opengeosys.org)",
659
660 TCLAP::ValueArg<int> arg_nodata(
661 "n", "nodata",
662 "explicitly specifies the no data value used in the dataset (usually "
663 "it is not necessary to set this)",
664 false, no_data_input, "NODATA_VALUE");
665 cmd.add(arg_nodata);
666
667 std::vector<std::string> allowed_elems{"tri", "quad", "prism", "hex"};
668 TCLAP::ValuesConstraint<std::string> allowed_elem_vals(allowed_elems);
669 TCLAP::ValueArg<std::string> arg_elem_type(
670 "e", "elem-type", "the element type used in the resulting OGS mesh, ",
671 false, "", &allowed_elem_vals);
672 cmd.add(arg_elem_type);
673
674 TCLAP::SwitchArg arg_images(
675 "", "images",
676 "if set, all time steps will be written as ESRI image files (*.asc)");
677 cmd.add(arg_images);
678
679 TCLAP::SwitchArg arg_multi_files(
680 "", "multi-file",
681 "if set, each time step will be written to a separate mesh file");
682 cmd.add(arg_multi_files);
683
684 TCLAP::SwitchArg arg_single_file(
685 "", "single-file",
686 "if set, all time steps will be written to a single mesh file (with "
687 "one scalar array per time step)");
688 cmd.add(arg_single_file);
689
690 TCLAP::ValueArg<std::size_t> arg_time_end(
691 "", "timestep-last",
692 "last time step to be extracted (only for time-dependent variables!)",
693 false, 0, "TIME_END");
694 cmd.add(arg_time_end);
695
696 TCLAP::ValueArg<std::size_t> arg_time_start(
697 "", "timestep-first",
698 "first time step to be extracted (only for time-dependent variables!)",
699 false, 0, "TIMESTEP_FIRST");
700 cmd.add(arg_time_start);
701
702 std::vector<std::size_t> allowed_dims{0, 1, 2, 3};
703 TCLAP::ValuesConstraint<std::size_t> allowed_dim_vals(allowed_dims);
704 TCLAP::ValueArg<std::size_t> arg_dim3(
705 "", "dim3",
706 "index of third dimension (z/height/depth) for the selected variable",
707 false, 0, &allowed_dim_vals);
708 cmd.add(arg_dim3);
709
710 TCLAP::ValueArg<std::size_t> arg_dim2(
711 "", "dim2",
712 "index of second dimension (y/latitude) for the selected variable",
713 false, 0, &allowed_dim_vals);
714 cmd.add(arg_dim2);
715
716 TCLAP::ValueArg<std::size_t> arg_dim1(
717 "", "dim1",
718 "index of first dimension (x/longitude) for the selected variable",
719 false, 0, &allowed_dim_vals);
720 cmd.add(arg_dim1);
721
722 TCLAP::ValueArg<std::size_t> arg_dim_time(
723 "t", "time",
724 "index of the time-dependent dimension for the selected variable",
725 false, 0, &allowed_dim_vals);
726 cmd.add(arg_dim_time);
727
728 TCLAP::ValueArg<std::string> arg_varname(
729 "v", "var", "variable included in the the netCDF file", false, "",
730 "VAR_NAME");
731 cmd.add(arg_varname);
732
733 TCLAP::ValueArg<std::string> arg_output(
734 "o", "output", "Output (.vtu). The OGS mesh output file", true, "",
735 "OUTPUT_FILE");
736 cmd.add(arg_output);
737 TCLAP::ValueArg<std::string> arg_input("i", "input",
738 "Input (.nc). The netCDF input file",
739 true, "", "INPUT_FILE");
740 cmd.add(arg_input);
741 auto log_level_arg = BaseLib::makeLogLevelArg();
742 cmd.add(log_level_arg);
743 cmd.parse(argc, argv);
744
745 BaseLib::MPI::Setup mpi_setup(argc, argv);
746 BaseLib::initOGSLogger(log_level_arg.getValue());
747
748 NcFile dataset(arg_input.getValue().c_str(), NcFile::read);
749
750 if (dataset.isNull())
751 {
752 ERR("Error opening file.");
753 return -1;
754 }
755
756 std::size_t const mutex =
757 arg_single_file.isSet() + arg_multi_files.isSet() + arg_images.isSet();
758 if (mutex > 1)
759 {
760 ERR("Only one output format can be specified (single-file, multi-file, "
761 "or images)");
762 return EXIT_FAILURE;
763 }
764
765 std::cout << "OpenGeoSys NetCDF Converter\n";
766 if (!arg_varname.isSet())
767 {
768 std::cout << "File " << arg_input.getValue()
769 << " loaded. Press ENTER to display available data arrays.\n";
770 std::cin.ignore();
771 }
772
773 std::string const& output_name(arg_output.getValue());
774 std::string const& var_name = (arg_varname.isSet())
775 ? arg_varname.getValue()
776 : arraySelectionLoop(dataset);
777 NcVar const& var = dataset.getVar(var_name);
778 if (var.isNull())
779 {
780 ERR("Variable \"{:s}\" not found in file.", arg_varname.getValue());
781 return EXIT_FAILURE;
782 }
783
784 std::vector<std::size_t> dim_idx_map(var.getDimCount(), 0);
785 bool is_time_dep(false);
786 if (arg_dim1.isSet() && arg_dim2.isSet())
787 {
788 is_time_dep = arg_dim_time.isSet();
789 if (!assignDimParams(var, dim_idx_map, arg_dim_time, arg_dim1, arg_dim2,
790 arg_dim3))
791 {
792 return EXIT_FAILURE;
793 }
794 }
795 else
796 {
797 is_time_dep = dimensionSelectionLoop(var, dim_idx_map);
798 }
799
800 std::pair<std::size_t, std::size_t> time_bounds(0, 0);
801 if (is_time_dep)
802 time_bounds =
803 (arg_time_start.isSet())
804 ? assignTimeBounds(getDimVar(dataset, var, dim_idx_map[0]),
805 arg_time_start, arg_time_end)
806 : timestepSelectionLoop(var, dim_idx_map[0]);
807
809 if (arg_images.isSet())
810 {
811 output = OutputType::IMAGES;
812 }
813 else if (arg_multi_files.isSet())
814 {
815 output = OutputType::MULTIMESH;
816 }
817 else if (arg_single_file.isSet() || !is_time_dep ||
818 time_bounds.first == time_bounds.second)
819 {
820 output = OutputType::SINGLEMESH;
821 }
822 else
823 {
824 output = multFilesSelectionLoop(time_bounds);
825 }
826
827 std::size_t const temp_offset = (is_time_dep) ? 1 : 0;
828 std::size_t const n_dims = (var.getDimCount());
830
831 if (output != OutputType::IMAGES)
832 {
833 elem_type = (arg_elem_type.isSet())
834 ? assignElemType(arg_elem_type)
835 : elemSelectionLoop(n_dims - temp_offset);
836 if (elem_type == MeshLib::MeshElemType::INVALID)
837 elemSelectionLoop(n_dims - temp_offset);
838 }
839
840 if (arg_nodata.isSet())
841 {
842 no_data_input = arg_nodata.getValue();
843 }
844
845 if (!convert(dataset, var, output_name, dim_idx_map, is_time_dep,
846 time_bounds, output, elem_type))
847 {
848 return EXIT_FAILURE;
849 }
850
851 std::cout << "Conversion finished successfully.\n";
852 return EXIT_SUCCESS;
853}
static double no_data_input
static std::pair< std::size_t, std::size_t > assignTimeBounds(NcVar const &var, TCLAP::ValueArg< std::size_t > &arg_time_start, TCLAP::ValueArg< std::size_t > &arg_time_end)
static MeshLib::MeshElemType assignElemType(TCLAP::ValueArg< std::string > &arg_elem_type)
static MeshLib::MeshElemType elemSelectionLoop(std::size_t const dim)
static bool assignDimParams(NcVar const &var, std::vector< std::size_t > &dim_idx_map, TCLAP::ValueArg< std::size_t > &arg_dim_time, TCLAP::ValueArg< std::size_t > &arg_dim1, TCLAP::ValueArg< std::size_t > &arg_dim2, TCLAP::ValueArg< std::size_t > &arg_dim3)
static std::pair< std::size_t, std::size_t > timestepSelectionLoop(NcVar const &var, std::size_t const dim_idx)
static bool dimensionSelectionLoop(NcVar const &var, std::vector< std::size_t > &dim_idx_map)
static bool convert(NcFile const &dataset, NcVar const &var, std::string const &output_name, std::vector< std::size_t > const &dim_idx_map, std::size_t const time_offset, std::pair< std::size_t, std::size_t > const &time_bounds, OutputType const output, MeshLib::MeshElemType const elem_type)
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
GITINFOLIB_EXPORT const std::string ogs_version

References arraySelectionLoop(), assignDimParams(), assignElemType(), assignTimeBounds(), convert(), dimensionSelectionLoop(), elemSelectionLoop(), ERR(), getDimVar(), IMAGES, BaseLib::initOGSLogger(), MeshLib::INVALID, INVALID, BaseLib::makeLogLevelArg(), multFilesSelectionLoop(), MULTIMESH, no_data_input, GitInfoLib::GitInfo::ogs_version, SINGLEMESH, and timestepSelectionLoop().

◆ multFilesSelectionLoop()

OutputType multFilesSelectionLoop ( std::pair< std::size_t, std::size_t > const & time_bounds)
static

Definition at line 351 of file NetCdfConverter.cpp.

353{
355 while (t == OutputType::INVALID)
356 {
357 std::size_t const n_time_steps(time_bounds.second - time_bounds.first +
358 1);
359 std::cout << "\nThe selection includes " << n_time_steps
360 << " time steps.\n";
361 std::cout << "0. Save data in " << n_time_steps
362 << " mesh files with one scalar array each.\n";
363 std::cout << "1. Save data in one mesh file with " << n_time_steps
364 << " scalar arrays.\n";
365 std::cout << "2. Save data as " << n_time_steps << " ASC images.\n";
366
367 std::size_t const ret =
368 parseInput("Select preferred method: ", 3, false);
369
370 if (ret == 0)
372 else if (ret == 1)
374 else if (ret == 2)
376 }
377 return t;
378}

References IMAGES, INVALID, MULTIMESH, parseInput(), and SINGLEMESH.

Referenced by main().

◆ parseInput()

std::size_t parseInput ( std::string const & request_str,
std::size_t const max_val,
bool const has_info = false )
static

Definition at line 66 of file NetCdfConverter.cpp.

69{
70 while (true)
71 {
72 std::cout << request_str;
73 std::string str;
74 std::size_t val;
75 std::getline(std::cin, str);
76 checkExit(str);
77 if (has_info && str == "info")
78 return (max_val);
79 std::stringstream str_stream(str);
80 if (!(str_stream >> val))
81 {
82 std::size_t const error_val = (has_info) ? 2 : 0;
83 showErrorMessage(error_val);
84 continue;
85 }
86 if (val > max_val - 1)
87 {
88 showErrorMessage(1, max_val - 1);
89 continue;
90 }
91 return val;
92 }
93 return std::numeric_limits<std::size_t>::max();
94}

References checkExit(), and showErrorMessage().

Referenced by arraySelectionLoop(), dimensionSelectionLoop(), multFilesSelectionLoop(), and timestepSelectionLoop().

◆ showArrays()

void showArrays ( NcFile const & dataset)
static

Definition at line 121 of file NetCdfConverter.cpp.

122{
123 std::size_t const n_vars(dataset.getDimCount());
124 std::cout << "The NetCDF file contains the following " << n_vars
125 << " arrays:\n\n";
126 std::cout << "\tIndex\tArray Name\t#Dimensions\n";
127 std::cout << "-------------------------------------------\n";
128 auto const& names = dataset.getVars();
129 std::size_t count = 0;
130 for (auto [name, var] : names)
131 {
132 std::cout << "\t" << count++ << "\t" << name << "\t("
133 << var.getDimCount() << "D array)\n";
134 }
135 std::cout << "\n";
136}

Referenced by arraySelectionLoop().

◆ showArraysDims()

void showArraysDims ( NcVar const & var)
static

Definition at line 138 of file NetCdfConverter.cpp.

139{
140 std::cout << "Data array \"" << var.getName()
141 << "\" contains the following dimensions:\n";
142 std::size_t const n_dims(var.getDimCount());
143 for (std::size_t i = 0; i < n_dims; ++i)
144 std::cout << "\t" << i << "\t" << var.getDim(i).getName() << "\t("
145 << var.getDim(i).getSize() << " values)\n";
146 std::cout << "\n";
147}

Referenced by dimensionSelectionLoop().

◆ showErrorMessage()

void showErrorMessage ( std::size_t const error_id,
std::size_t const max = 0 )
static

Definition at line 47 of file NetCdfConverter.cpp.

49{
50 if (error_id == 0)
51 {
52 ERR("Input not valid.");
53 }
54 else if (error_id == 1)
55 {
56 ERR("Index not valid. Valid indices are in [0,{:d}].", max);
57 }
58 else if (error_id == 2)
59 {
60 ERR("Input not valid.");
61 std::cout << "Type \"info\" to display the available options again. "
62 "\"exit\" will exit the programme.\n";
63 }
64}

References ERR().

Referenced by dimensionSelectionLoop(), and parseInput().

◆ timestepSelectionLoop()

std::pair< std::size_t, std::size_t > timestepSelectionLoop ( NcVar const & var,
std::size_t const dim_idx )
static

Definition at line 291 of file NetCdfConverter.cpp.

293{
294 std::size_t const n_time_steps = var.getDim(dim_idx).getSize();
295 std::size_t const max_val = std::numeric_limits<std::size_t>::max();
296 std::pair<std::size_t, std::size_t> bounds(max_val, max_val);
297 std::cout << "\nThe dataset contains " << n_time_steps << " time steps.\n";
298 while (bounds.first == max_val)
299 {
300 bounds.first = parseInput(
301 "Specify first time step to export: ", n_time_steps, false);
302 }
303 while (bounds.first > bounds.second || bounds.second > n_time_steps)
304 {
305 bounds.second = parseInput(
306 "Specify last time step to export: ", n_time_steps, false);
307 }
308 return bounds;
309}

References parseInput().

Referenced by main().

Variable Documentation

◆ no_data_input

double no_data_input = -9999
static

Definition at line 31 of file NetCdfConverter.cpp.

Referenced by main().

◆ no_data_output

const double no_data_output = -9999
static

Definition at line 30 of file NetCdfConverter.cpp.

Referenced by createRasterHeader(), and getData().