OGS
FileIO::GMSInterface Class Referencefinal

Detailed Description

Manages the import and export of Aquaveo GMS files into and out of GeoLib.

This class currently supports reading and writing ASCII borehole files as well as (partially) reading mesh files. The 3dm-mesh-file-reader is based on example meshes and does currently only support the following element types: E4T (tetrahedra), E4P/E5P (pyramids) and E6W (wedges/prisms). Not supported are E8H (Hex), E4Q (Quad), E3T (Tri) as well as higher order elements. Please refer to the file format documentation of GMS for details.

Definition at line 34 of file GMSInterface.h.

#include <GMSInterface.h>

Static Public Member Functions

static void writeBoreholesToGMS (const std::vector< GeoLib::Point * > *stations, const std::string &filename)
static int readBoreholesFromGMS (std::vector< GeoLib::Point * > &boreholes, const std::string &filename)
 Imports borehole data from a file in GMS-format.
static MeshLib::MeshreadMesh (const std::string &filename)
 Reads a GMS *.3dm file and converts it to an CFEMesh.

Member Function Documentation

◆ readBoreholesFromGMS()

int FileIO::GMSInterface::readBoreholesFromGMS ( std::vector< GeoLib::Point * > & boreholes,
const std::string & filename )
static

Imports borehole data from a file in GMS-format.

Definition at line 34 of file GMSInterface.cpp.

36{
37 std::ifstream in(filename.c_str());
38 if (!in.is_open())
39 {
40 ERR("GMSInterface::readBoreholeFromGMS(): Could not open file {:s}.",
41 filename);
42 return 0;
43 }
44
45 double depth(-9999.0);
46 std::string line;
47 std::string cName;
48 std::string sName;
49 std::list<std::string>::const_iterator it;
50 GeoLib::StationBorehole* newBorehole = nullptr;
51
52 /* skipping first line because it contains field names */
53 std::getline(in, line);
54
55 /* read all stations */
56 while (std::getline(in, line))
57 {
58 std::list<std::string> fields = BaseLib::splitString(line, '\t');
59
60 if (fields.size() >= 5)
61 {
62 if (*fields.begin() == cName) // add new layer
63 {
64 it = fields.begin();
65 auto const pnt = parsePointCoordinates(it);
66
67 // check if current layer has a thickness of 0.0.
68 // if so skip it since it will mess with the vtk-visualisation
69 // later on!
70 if (pnt[2] != depth)
71 {
72 if (newBorehole == nullptr)
73 OGS_FATAL("Trying to access a nullptr.");
74 newBorehole->addSoilLayer(pnt[0], pnt[1], pnt[2], sName);
75 sName = (*(++it));
76 depth = pnt[2];
77 }
78 else
79 {
80 WARN(
81 "GMSInterface::readBoreholeFromGMS(): Skipped layer "
82 "'{:s}' in borehole '{:s}' because of thickness 0.0.",
83 sName, cName);
84 }
85 }
86 else // add new borehole
87 {
88 if (newBorehole != nullptr)
89 {
90 newBorehole->setDepth((*newBorehole)[2] - depth);
91 boreholes.push_back(newBorehole);
92 }
93 cName = *fields.begin();
94 it = fields.begin();
95 auto const pnt = parsePointCoordinates(it);
96 sName = (*(++it));
98 cName, pnt[0], pnt[1], pnt[2], 0);
99 depth = pnt[2];
100 }
101 }
102 else
103 {
104 ERR("GMSInterface::readBoreholeFromGMS(): Error reading format.");
105 }
106 }
107 // write the last borehole from the file
108 if (newBorehole != nullptr)
109 {
110 newBorehole->setDepth((*newBorehole)[2] - depth);
111 boreholes.push_back(newBorehole);
112 }
113 in.close();
114
115 if (boreholes.empty())
116 {
117 return 0;
118 }
119 return 1;
120}
#define OGS_FATAL(...)
Definition Error.h:19
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
static StationBorehole * createStation(const std::string &name, double x, double y, double z, double depth, const std::string &date="")
Creates a new borehole object based on the given parameters.
void addSoilLayer(double thickness, const std::string &soil_name)
Add a soil layer to the boreholes stratigraphy.
void setDepth(double depth)
Sets the depth of the borehole.
std::vector< std::string > splitString(std::string const &str)
std::array< double, 3 > parsePointCoordinates(It &it)

References GeoLib::StationBorehole::addSoilLayer(), GeoLib::StationBorehole::createStation(), ERR(), OGS_FATAL, GeoLib::StationBorehole::setDepth(), BaseLib::splitString(), and WARN().

Referenced by MainWindow::loadFile().

◆ readMesh()

MeshLib::Mesh * FileIO::GMSInterface::readMesh ( const std::string & filename)
static

Reads a GMS *.3dm file and converts it to an CFEMesh.

Definition at line 170 of file GMSInterface.cpp.

171{
172 std::string line;
173
174 std::ifstream in(filename.c_str());
175 if (!in.is_open())
176 {
177 ERR("GMSInterface::readMesh(): Could not open file {:s}.", filename);
178 return nullptr;
179 }
180
181 // Read data from file
182 std::getline(in, line); // "MESH3D"
183 if (line != "MESH3D" && line != "MESH2D")
184 {
185 ERR("GMSInterface::readMesh(): Could not read expected file "
186 "header.");
187 return nullptr;
188 }
189 bool const is_3d = (line == "MESH3D");
190
191 std::string mesh_name = BaseLib::extractBaseNameWithoutExtension(filename);
192 INFO("Reading SMS/GMS mesh...");
193 std::vector<MeshLib::Node*> nodes;
194 std::vector<MeshLib::Element*> elements;
195 std::vector<int> mat_ids;
196 std::map<unsigned, unsigned> id_map;
197
198 // elements are listed before nodes in 3dm-format, therefore
199 // traverse file twice and read first nodes and then elements
200 std::string dummy;
201 unsigned id(0);
202 unsigned count(0);
203 double x[3];
204 // read nodes
205 while (std::getline(in, line))
206 {
207 if (line[0] == 'N') // "ND" for Node
208 {
209 std::stringstream str(line);
210 str >> dummy >> id >> x[0] >> x[1] >> x[2];
211 auto* node = new MeshLib::Node(x, id);
212 id_map.insert(std::pair<unsigned, unsigned>(id, count++));
213 nodes.push_back(node);
214 }
215 }
216 in.close();
217
218 // NOTE: Element types E8H (Hex), E4Q (Quad) are not implemented yet
219 // read elements
220 in.open(filename.c_str());
221 std::getline(in, line); // "MESH2D" / "MESH3D"
222 unsigned node_idx[6];
223 int mat_id(0);
224 while (std::getline(in, line))
225 {
226 std::string element_id(line.substr(0, 3));
227 std::stringstream str(line);
228
229 if (element_id == "MES") // "MESHNAME"
230 {
231 str >> dummy >> mesh_name;
232 mesh_name = mesh_name.substr(1, mesh_name.length() - 2);
233 }
234 else if (!is_3d && element_id == "E3T") // Triangle
235 {
236 str >> dummy >> id >> node_idx[0] >> node_idx[1] >> node_idx[2] >>
237 mat_id;
238 std::array<MeshLib::Node*, 3> tri_nodes;
239 for (unsigned k(0); k < 3; k++)
240 {
241 tri_nodes[k] = nodes[id_map.find(node_idx[k])->second];
242 }
243 elements.push_back(new MeshLib::Tri(tri_nodes));
244 mat_ids.push_back(mat_id);
245 }
246 else if (!is_3d && element_id == "E6T") // Triangle
247 {
248 str >> dummy >> id >> node_idx[0] >> node_idx[3] >> node_idx[1] >>
249 node_idx[4] >> node_idx[2] >> node_idx[5] >> mat_id;
250 std::array<MeshLib::Node*, 3> tri_nodes;
251 for (unsigned k(0); k < 3; k++)
252 {
253 tri_nodes[k] = nodes[id_map.find(node_idx[k])->second];
254 }
255 elements.push_back(new MeshLib::Tri(tri_nodes));
256 mat_ids.push_back(mat_id);
257 }
258 else if (is_3d && element_id == "E6W") // Prism
259 {
260 str >> dummy >> id >> node_idx[0] >> node_idx[1] >> node_idx[2] >>
261 node_idx[3] >> node_idx[4] >> node_idx[5] >> mat_id;
262 std::array<MeshLib::Node*, 6> prism_nodes;
263 for (unsigned k(0); k < 6; k++)
264 {
265 prism_nodes[k] = nodes[id_map.find(node_idx[k])->second];
266 }
267 elements.push_back(new MeshLib::Prism(prism_nodes));
268 mat_ids.push_back(mat_id);
269 }
270 else if (is_3d && element_id == "E4T") // Tet
271 {
272 str >> dummy >> id >> node_idx[0] >> node_idx[1] >> node_idx[2] >>
273 node_idx[3] >> mat_id;
274 std::array<MeshLib::Node*, 4> tet_nodes;
275 for (unsigned k(0); k < 4; k++)
276 {
277 tet_nodes[k] = nodes[id_map.find(node_idx[k])->second];
278 }
279 elements.push_back(new MeshLib::Tet(tet_nodes));
280 mat_ids.push_back(mat_id);
281 }
282 // Pyramid (two versions exist for some reason)
283 else if (is_3d && (element_id == "E4P" || element_id == "E5P"))
284 {
285 str >> dummy >> id >> node_idx[0] >> node_idx[1] >> node_idx[2] >>
286 node_idx[3] >> node_idx[4] >> mat_id;
287 std::array<MeshLib::Node*, 5> pyramid_nodes;
288 for (unsigned k(0); k < 5; k++)
289 {
290 pyramid_nodes[k] = nodes[id_map.find(node_idx[k])->second];
291 }
292 elements.push_back(new MeshLib::Pyramid(pyramid_nodes));
293 mat_ids.push_back(mat_id);
294 }
295 else if (element_id == "ND ")
296 { // Node
297 continue; // skip because nodes have already been read
298 }
299 else // default
300 {
301 WARN(
302 "GMSInterface::readMesh() - Element type '{:s}' not "
303 "recognised.",
304 element_id);
305 return nullptr;
306 }
307 }
308
309 in.close();
310 INFO("finished.");
311
312 MeshLib::Properties properties;
313 if (mat_ids.size() == elements.size())
314 {
315 auto* const opt_pv = properties.createNewPropertyVector<int>(
316 "MaterialIDs", MeshLib::MeshItemType::Cell);
317 if (!opt_pv)
318 {
319 ERR("Could not create PropertyVector for material ids.");
320 BaseLib::cleanupVectorElements(nodes, elements);
321 return nullptr;
322 }
323 opt_pv->assign(mat_ids);
324 }
325 else
326 {
327 ERR("Ignoring Material IDs information (does not match number of "
328 "elements).");
329 }
330 return new MeshLib::Mesh(mesh_name, nodes, elements,
331 true /* compute_element_neighbors */, properties);
332}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
constexpr void assign(R &&r)
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
std::string extractBaseNameWithoutExtension(std::string const &pathname)
TemplateElement< MeshLib::TetRule4 > Tet
Definition Tet.h:14
TemplateElement< MeshLib::TriRule3 > Tri
Definition Tri.h:15
TemplateElement< MeshLib::PyramidRule5 > Pyramid
Definition Pyramid.h:14
TemplateElement< MeshLib::PrismRule6 > Prism
Definition Prism.h:14

References MeshLib::PropertyVector< PROP_VAL_TYPE >::assign(), MeshLib::Cell, BaseLib::cleanupVectorElements(), MeshLib::Properties::createNewPropertyVector(), ERR(), BaseLib::extractBaseNameWithoutExtension(), INFO(), MeshLib::Node, and WARN().

Referenced by MainWindow::loadFile().

◆ writeBoreholesToGMS()

void FileIO::GMSInterface::writeBoreholesToGMS ( const std::vector< GeoLib::Point * > * stations,
const std::string & filename )
static

Exports borehole data from all boreholes in a list to a file in GMS-format. (Note: there are some hardcoded tmp-files in the method that you might need to change!)

Definition at line 122 of file GMSInterface.cpp.

124{
125 std::ofstream out(filename.c_str(), std::ios::out);
126
127 // write header
128 out << "name"
129 << "\t" << std::fixed << "X"
130 << "\t"
131 << "Y"
132 << "\t"
133 << "Z"
134 << "\t"
135 << "soilID"
136 << "\n";
137
138 for (auto station_as_point : *stations)
139 {
140 auto const* station =
141 static_cast<GeoLib::StationBorehole*>(station_as_point);
142 std::vector<GeoLib::Point*> const& profile = station->getProfile();
143 std::vector<std::string> const& soilNames = station->getSoilNames();
144 std::string current_soil_name;
145
146 std::size_t nLayers = profile.size();
147 for (std::size_t i = 1; i < nLayers; i++)
148 {
149 if ((i > 1) && (soilNames[i] == soilNames[i - 1]))
150 {
151 continue;
152 }
153 current_soil_name = soilNames[i];
154
155 out << station->getName() << "\t" << std::fixed
156 << (*(profile[i - 1]))[0] << "\t" << (*(profile[i - 1]))[1]
157 << "\t" << (*(profile[i - 1]))[2] << "\t"
158 << current_soil_name /*idx*/ << "\n";
159 }
160 out << station->getName() << "\t" << std::fixed
161 << (*(profile[nLayers - 1]))[0] << "\t"
162 << (*(profile[nLayers - 1]))[1] << "\t"
163 << (*(profile[nLayers - 1]))[2] << "\t" << current_soil_name
164 << "\n"; // this line marks the end of the borehole
165 }
166
167 out.close();
168}

References GeoLib::StationBorehole::getProfile().

Referenced by MainWindow::exportBoreholesToGMS(), and StationTreeView::exportStation().


The documentation for this class was generated from the following files: