OGS
createLayeredMeshFromRasters.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include <tclap/CmdLine.h>
5
6#include <algorithm>
7#include <iterator>
8#include <memory>
9#include <range/v3/algorithm/copy.hpp>
10#include <range/v3/view/join.hpp>
11#include <range/v3/view/repeat_n.hpp>
12#include <string>
13#include <vector>
14
15#include "BaseLib/FileTools.h"
17#include "BaseLib/Logging.h"
18#include "BaseLib/MPI.h"
21#include "InfoLib/GitInfo.h"
24#include "MeshLib/Mesh.h"
26
28 MeshLib::Mesh* subsurface_mesh)
29{
30 auto const* surface_material_ids = materialIDs(*sfc_mesh);
31 auto* subsurface_material_ids = materialIDs(*subsurface_mesh);
32 // reset the material ids
33 if (!surface_material_ids)
34 {
35 OGS_FATAL("Surface mesh does not contain material IDs");
36 }
37 if (surface_material_ids->empty())
38 {
39 OGS_FATAL("Surface mesh material IDs doesn't contain any values");
40 }
41 if (!subsurface_material_ids)
42 {
43 OGS_FATAL("Subsurface mesh does not contain material IDs");
44 }
45 if (subsurface_material_ids->size() % surface_material_ids->size() != 0)
46 {
47 OGS_FATAL("Could not determine the number of subsurface layers.");
48 }
49 int const number_of_layers =
50 subsurface_material_ids->size() / surface_material_ids->size();
51
52 ranges::copy(
53 ranges::views::repeat_n(*surface_material_ids, number_of_layers) |
54 ranges::views::join,
55 subsurface_material_ids->begin());
56}
57
58int main(int argc, char* argv[])
59{
60 TCLAP::CmdLine cmd(
61 "Creates a layered 3D OGS mesh from an existing 2D OGS mesh and a list "
62 "of raster files representing subsurface layers. Supported raster "
63 "formats are ArcGIS ascii rasters (*.asc), Surfer Grids (*.grd), or "
64 "gridded XYZ rasters (*.xyz)."
65 "Only input meshes consisting of line and triangle elements are "
66 "currently supported as mapping of quads might result in invalid mesh "
67 "elements.\n\n"
68 "OpenGeoSys-6 software, version " +
70 ".\n"
71 "Copyright (c) 2012-2026, OpenGeoSys Community "
72 "(http://www.opengeosys.org)",
74
75 TCLAP::SwitchArg use_ascii_arg("", "ascii_output",
76 "Write VTU output in ASCII format.");
77 cmd.add(use_ascii_arg);
78
79 double min_thickness(std::numeric_limits<double>::epsilon());
80 TCLAP::ValueArg<double> min_thickness_arg(
81 "t", "thickness",
82 "The minimum thickness of a layer to be integrated at any given "
83 "location, (min = 0)",
84 false, min_thickness, "MIN_THICKNESS");
85 cmd.add(min_thickness_arg);
86
87 TCLAP::ValueArg<std::string> raster_path_arg(
88 "r", "raster-list",
89 "Input (.vtu). An ascii-file containing a list of input "
90 "raster files, starting from"
91 "top (DEM) to bottom",
92 true, "", "INPUT_FILE_LIST");
93 cmd.add(raster_path_arg);
94
95 TCLAP::SwitchArg keep_materials_arg(
96 "", "keep-surface-material-ids",
97 "if the argument is present the materials defined in the surface mesh "
98 "are used to set the material information for the subsurface cells",
99 false);
100 cmd.add(keep_materials_arg);
101
102 TCLAP::ValueArg<std::string> mesh_out_arg(
103 "o", "output-mesh-file",
104 "Output (.vtu). The file name of the resulting 3D mesh", true, "",
105 "OUTPUT_FILE");
106 cmd.add(mesh_out_arg);
107
108 TCLAP::ValueArg<std::string> mesh_arg(
109 "i", "input-mesh-file",
110 "Input (.vtu). The file name of the 2D input mesh", true, "",
111 "INPUT_FILE");
112 cmd.add(mesh_arg);
113 auto log_level_arg = BaseLib::makeLogLevelArg();
114 cmd.add(log_level_arg);
115
116 cmd.parse(argc, argv);
117
118 BaseLib::MPI::Setup mpi_setup(argc, argv);
119 BaseLib::initOGSLogger(log_level_arg.getValue());
120
121 if (min_thickness_arg.isSet())
122 {
123 min_thickness = min_thickness_arg.getValue();
124 if (min_thickness < 0)
125 {
126 ERR("Minimum layer thickness must be non-negative value.");
127 return EXIT_FAILURE;
128 }
129 }
130
131 INFO("Reading mesh '{:s}' ... ", mesh_arg.getValue());
132 std::unique_ptr<MeshLib::Mesh> const sfc_mesh(
133 MeshLib::IO::readMeshFromFile(mesh_arg.getValue()));
134 if (!sfc_mesh)
135 {
136 ERR("Error reading mesh '{:s}'.", mesh_arg.getValue());
137 return EXIT_FAILURE;
138 }
139 if (sfc_mesh->getDimension() != 2)
140 {
141 ERR("Input mesh must be a 2D mesh.");
142 return EXIT_FAILURE;
143 }
144 INFO("done.");
145
146 std::vector<std::string> raster_paths =
147 BaseLib::IO::readStringListFromFile(raster_path_arg.getValue());
148 if (raster_paths.size() < 2)
149 {
150 ERR("At least two raster files needed to create 3D mesh.");
151 return EXIT_FAILURE;
152 }
153 std::reverse(raster_paths.begin(), raster_paths.end());
154
156 if (auto const rasters = FileIO::readRasters(raster_paths))
157 {
158 if (!mapper.createLayers(*sfc_mesh, *rasters, min_thickness))
159 {
160 return EXIT_FAILURE;
161 }
162 }
163 else
164 {
165 ERR("Reading raster files.");
166 return EXIT_FAILURE;
167 }
168
169 auto const result_mesh = mapper.getMesh("SubsurfaceMesh");
170 if (result_mesh == nullptr)
171 {
172 ERR("Mapper returned empty result for 'SubsurfaceMesh'.");
173 return EXIT_FAILURE;
174 }
175
176 if (keep_materials_arg.getValue())
177 {
179 result_mesh.get());
180 }
181
182 std::string output_name(mesh_out_arg.getValue());
183 if (!BaseLib::hasFileExtension(".vtu", output_name))
184 {
185 output_name.append(".vtu");
186 }
187
188 INFO("Writing mesh '{:s}' ... ", output_name);
189 auto const data_mode =
190 use_ascii_arg.getValue() ? vtkXMLWriter::Ascii : vtkXMLWriter::Binary;
191
192 MeshLib::IO::writeVtu(*result_mesh, output_name, data_mode);
193 INFO("done.");
194
195 return EXIT_SUCCESS;
196}
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
virtual bool createLayers(MeshLib::Mesh const &mesh, std::vector< GeoLib::Raster const * > const &rasters, double minimum_thickness, double noDataReplacementValue=0.0) final
std::unique_ptr< MeshLib::Mesh > getMesh(std::string const &mesh_name) const
Returns a mesh of the subsurface representation.
Manipulating and adding prism element layers to an existing 2D mesh.
int main(int argc, char *argv[])
void assignSurfaceMaterialIDsToSubsurfaceLayers(MeshLib::Mesh *sfc_mesh, MeshLib::Mesh *subsurface_mesh)
std::vector< std::string > readStringListFromFile(std::string const &filename)
Reads non-empty lines from a list of strings from a file into a vector.
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
bool hasFileExtension(std::string const &extension, std::string const &filename)
std::optional< std::vector< GeoLib::Raster const * > > readRasters(std::vector< std::string > const &raster_paths)
GITINFOLIB_EXPORT const std::string ogs_version
int writeVtu(MeshLib::Mesh const &mesh, std::string const &file_name, int const data_mode)
MeshLib::Mesh * readMeshFromFile(const std::string &file_name, bool const compute_element_neighbors)