OGS
TecPlotTools.cpp File Reference
#include <tclap/CmdLine.h>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "BaseLib/Logging.h"
#include "BaseLib/MPI.h"
#include "BaseLib/StringTools.h"
#include "BaseLib/TCLAPArguments.h"
#include "GeoLib/Point.h"
#include "InfoLib/GitInfo.h"
#include "MeshLib/IO/VtkIO/VtuInterface.h"
#include "MeshLib/Mesh.h"
#include "MeshToolsLib/MeshGenerators/RasterToMesh.h"
Include dependency graph for TecPlotTools.cpp:

Go to the source code of this file.

Functions

std::string getValue (std::string const &line, std::string const &val_name, bool is_string)
std::string getName (std::string const &line)
 Returns the name/title from the "Zone"-description.
std::string_view getZonetype (std::string const &line)
std::pair< std::size_t, std::size_t > getDimensions (std::string const &line)
 Returns raster dimensions from the "Zone"-description.
std::string trimVariable (std::string &var)
 Trims a substring containing a variable-name.
std::vector< std::string > getVariables (std::string const &line)
 Returns an vector of variable names from the "Variables"-description.
bool dataCountError (std::string const &name, std::size_t const &current, std::size_t const &total)
 Tests if the number of read values equals the number of expected values.
bool dataCountError (std::ofstream &out, std::string const &name, std::size_t const &current, std::size_t const &total)
void resetDataStructures (std::size_t const &n_scalars, std::vector< std::vector< double > > &scalars, std::size_t &val_count)
 Resets all data structures after a new "Variables"-description is found.
void writeTecPlotSection (std::ofstream &out, std::string const &file_name, std::size_t &write_count, std::size_t &val_count, std::size_t &val_total)
 Writes one section/zone into a separate TecPlot file.
int writeDataToMesh (std::string const &file_name, std::size_t &write_count, std::vector< std::string > const &vec_names, std::vector< std::vector< double > > const &scalars, std::pair< std::size_t, std::size_t > const &dims)
 Writes one section/zone into a separate OGS-mesh.
void skipGeometrySection (std::ifstream &in, std::string &line)
 If a geometry-section is encountered, it is currently ignored.
int splitFile (std::ifstream &in, std::string const &file_name)
 Splits a TecPlot file containing multiple sections/zones into separate files.
int convertFile (std::ifstream &in, std::string const &file_name)
int main (int argc, char *argv[])

Function Documentation

◆ convertFile()

int convertFile ( std::ifstream & in,
std::string const & file_name )

Converts a TecPlot file into one or more OGS-meshes (one mesh per section/zone)

Definition at line 333 of file TecPlotTools.cpp.

334{
335 std::string line;
336 std::string name;
337 std::pair<std::size_t, std::size_t> dims(0, 0);
338 std::vector<std::string> var_names;
339 std::vector<std::vector<double>> scalars;
340 std::size_t val_count(0);
341 std::size_t val_total(0);
342 std::size_t write_count(0);
343 while (std::getline(in, line))
344 {
345 if (line.find("GEOMETRY") != std::string::npos)
346 {
347 skipGeometrySection(in, line);
348 }
349
350 if (line.empty())
351 {
352 continue;
353 }
354 if (line.find("TITLE") != std::string::npos)
355 {
356 if (dataCountError(name, val_count, val_total))
357 {
358 return -3;
359 }
360 if (val_count != 0)
361 {
362 writeDataToMesh(file_name, write_count, var_names, scalars,
363 dims);
364 resetDataStructures(var_names.size(), scalars, val_count);
365 }
366 continue;
367 }
368 if (line.find("VARIABLES") != std::string::npos)
369 {
370 if (val_count != 0)
371 {
372 if (dataCountError(name, val_count, val_total))
373 {
374 return -3;
375 }
376 writeDataToMesh(file_name, write_count, var_names, scalars,
377 dims);
378 }
379 var_names.clear();
380 var_names = getVariables(line);
381 resetDataStructures(var_names.size(), scalars, val_count);
382 continue;
383 }
384 if (line.find("ZONE") != std::string::npos)
385 {
386 if (val_count != 0)
387 {
388 if (dataCountError(name, val_count, val_total))
389 {
390 return -3;
391 }
392 writeDataToMesh(file_name, write_count, var_names, scalars,
393 dims);
394 resetDataStructures(var_names.size(), scalars, val_count);
395 }
396 name = getName(line);
397 if (auto const zonetype = getZonetype(line); zonetype != "ORDERED")
398 {
399 ERR("Given zonetype '{:s}' is not supported. Only 'ORDERED' "
400 "zonetype data can be converted.",
401 zonetype);
402 return -4;
403 }
404 dims = getDimensions(line);
405 val_total = dims.first * dims.second;
406 val_count = 0;
407 continue;
408 }
409
410 double x;
411 std::stringstream iss(line);
412 std::size_t i(0);
413 std::size_t const n_scalars(scalars.size());
414 while (iss >> x)
415 {
416 if (i > n_scalars - 1)
417 {
418 ERR("Too much data for existing scalar arrays");
419 return -3;
420 }
421 scalars[i++].push_back(x);
422 }
423 if (i < n_scalars)
424 {
425 ERR("Not enough data for existing scalar arrays");
426 return -3;
427 }
428 val_count++;
429 }
430 if (dataCountError(name, val_count, val_total))
431 {
432 return -3;
433 }
434 writeDataToMesh(file_name, write_count, var_names, scalars, dims);
435 INFO("Finished conversion.");
436 return 0;
437}
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
std::string getName(std::string const &line)
Returns the name/title from the "Zone"-description.
std::string_view getZonetype(std::string const &line)
bool dataCountError(std::string const &name, std::size_t const &current, std::size_t const &total)
Tests if the number of read values equals the number of expected values.
void skipGeometrySection(std::ifstream &in, std::string &line)
If a geometry-section is encountered, it is currently ignored.
void resetDataStructures(std::size_t const &n_scalars, std::vector< std::vector< double > > &scalars, std::size_t &val_count)
Resets all data structures after a new "Variables"-description is found.
std::pair< std::size_t, std::size_t > getDimensions(std::string const &line)
Returns raster dimensions from the "Zone"-description.
int writeDataToMesh(std::string const &file_name, std::size_t &write_count, std::vector< std::string > const &vec_names, std::vector< std::vector< double > > const &scalars, std::pair< std::size_t, std::size_t > const &dims)
Writes one section/zone into a separate OGS-mesh.
std::vector< std::string > getVariables(std::string const &line)
Returns an vector of variable names from the "Variables"-description.

References dataCountError(), ERR(), getDimensions(), getName(), getVariables(), getZonetype(), INFO(), resetDataStructures(), skipGeometrySection(), and writeDataToMesh().

Referenced by main().

◆ dataCountError() [1/2]

bool dataCountError ( std::ofstream & out,
std::string const & name,
std::size_t const & current,
std::size_t const & total )

Tests if the number of read values equals the number of expected values and closes the stream

Definition at line 150 of file TecPlotTools.cpp.

154{
155 if (dataCountError(name, current, total))
156 {
157 out.close();
158 return true;
159 }
160 return false;
161}

References dataCountError().

◆ dataCountError() [2/2]

bool dataCountError ( std::string const & name,
std::size_t const & current,
std::size_t const & total )

Tests if the number of read values equals the number of expected values.

Definition at line 134 of file TecPlotTools.cpp.

137{
138 if (current != total)
139 {
140 ERR("Data rows found do not fit specified dimensions for section "
141 "'{:s}'.",
142 name);
143 return true;
144 }
145 return false;
146}

References ERR().

Referenced by convertFile(), dataCountError(), and splitFile().

◆ getDimensions()

std::pair< std::size_t, std::size_t > getDimensions ( std::string const & line)

Returns raster dimensions from the "Zone"-description.

Definition at line 89 of file TecPlotTools.cpp.

90{
91 std::pair<std::size_t, std::size_t> dims;
92 std::stringstream start(getValue(line, "I=", false));
93 start >> dims.first;
94 std::stringstream end(getValue(line, "J=", false));
95 end >> dims.second;
96 return dims;
97}
std::string getValue(std::string const &line, std::string const &val_name, bool is_string)

References getValue().

Referenced by convertFile(), and splitFile().

◆ getName()

◆ getValue()

std::string getValue ( std::string const & line,
std::string const & val_name,
bool is_string )

Returns the value for the given parameter name (i.e. for "x = 3" it returns "3")

Definition at line 24 of file TecPlotTools.cpp.

27{
28 std::string value;
29 std::size_t start(line.find(val_name));
30 std::size_t end(std::string::npos);
31 if (start == end)
32 {
33 ERR("Value not found.");
34 return "";
35 }
36 value = line.substr(start + 1, std::string::npos);
37 if (is_string)
38 {
39 start = value.find("\"");
40 value = value.substr(start + 1, std::string::npos);
41 end = value.find("\"");
42 }
43 else
44 {
45 start = value.find_first_not_of(" ");
46 value = value.substr(start + 1, std::string::npos);
47 BaseLib::trim(value);
48 end = value.find_first_of(" ");
49 }
50 value = value.substr(0, end);
51 BaseLib::trim(value);
52 return value;
53}
void trim(std::string &str, char ch)

References ERR(), and BaseLib::trim().

Referenced by getDimensions(), getName(), and main().

◆ getVariables()

std::vector< std::string > getVariables ( std::string const & line)

Returns an vector of variable names from the "Variables"-description.

Definition at line 109 of file TecPlotTools.cpp.

110{
111 std::string const var_str("VARIABLES");
112 std::size_t start(line.find(var_str));
113 std::string all_vars =
114 line.substr(start + var_str.length(), std::string::npos);
115 start = all_vars.find("=");
116 all_vars = all_vars.substr(start + 1, std::string::npos);
117 BaseLib::trim(all_vars);
118
119 std::vector<std::string> variables;
120 std::size_t end = 0;
121 while (end != std::string::npos)
122 {
123 end = all_vars.find_first_of(" ");
124 std::string var = all_vars.substr(0, end);
125 variables.push_back(trimVariable(var));
126 all_vars = all_vars.substr(end + 1, std::string::npos);
127 BaseLib::trim(all_vars);
128 }
129
130 return variables;
131}
std::string trimVariable(std::string &var)
Trims a substring containing a variable-name.

References BaseLib::trim(), and trimVariable().

Referenced by convertFile().

◆ getZonetype()

std::string_view getZonetype ( std::string const & line)

Definition at line 61 of file TecPlotTools.cpp.

62{
63 auto start = line.find("ZONETYPE=");
64 if (start == std::string::npos)
65 {
67 "A required 'ZONETYPE=' substring is not available in the ZONE "
68 "description: '{:s}'.",
69 line);
70 }
71 start += std::size("ZONETYPE=") - 1;
72
73 auto end = line.find(',', start);
74 if (end == std::string::npos)
75 {
77 "Expected the 'ZONETYPE=type' to be followed by a comma in the "
78 "ZONE description '{:s}'. The zone type starts at position {:d}.",
79 line, start);
80 }
81 if (start == end)
82 {
83 ERR("ZONETYPE string is empty in ZONE description '{:s}'.", line);
84 }
85 return std::string_view(&line[start], end - start);
86}
#define OGS_FATAL(...)
Definition Error.h:19

References ERR(), and OGS_FATAL.

Referenced by convertFile().

◆ main()

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

Small collection of scripts to handle TecPlot files.

Return codes: 0 : no errors -1 : missing arguments -2 : file I/O error -3 : index error -4 : error interpreting data -5 : error creating data structures

Definition at line 450 of file TecPlotTools.cpp.

451{
452 TCLAP::CmdLine cmd(
453 "TecPlot Parser\n\n"
454 "OpenGeoSys-6 software, version " +
456 ".\n"
457 "Copyright (c) 2012-2026, OpenGeoSys Community "
458 "(http://www.opengeosys.org)",
460 TCLAP::SwitchArg split_arg("s", "split",
461 "split time steps into separate files");
462 cmd.add(split_arg);
463 TCLAP::SwitchArg convert_arg("c", "convert",
464 "convert TecPlot data into OGS meshes");
465 cmd.add(convert_arg);
466 TCLAP::ValueArg<std::string> output_arg("o", "output-file",
467 "Output (.vtu). Output mesh file",
468 false, "", "OUTPUT_FILE");
469 cmd.add(output_arg);
470 TCLAP::ValueArg<std::string> input_arg("i", "input-file",
471 "Input (.plt). TecPlot input file",
472 true, "", "INPUT_FILE");
473 cmd.add(input_arg);
474 auto log_level_arg = BaseLib::makeLogLevelArg();
475 cmd.add(log_level_arg);
476 cmd.parse(argc, argv);
477
478 BaseLib::MPI::Setup mpi_setup(argc, argv);
479 BaseLib::initOGSLogger(log_level_arg.getValue());
480
481 if (!input_arg.isSet())
482 {
483 ERR("No input file given. Please specify TecPlot (*.plt) file");
484 return -1;
485 }
486
487 if (convert_arg.getValue() && !output_arg.isSet())
488 {
489 ERR("No output file given. Please specify OGS mesh (*.vtu) file");
490 return -1;
491 }
492
493 std::ifstream in(input_arg.getValue().c_str());
494 if (!in.is_open())
495 {
496 ERR("Could not open file {:s}.", input_arg.getValue());
497 return -2;
498 }
499
500 if (!convert_arg.isSet() && !split_arg.isSet())
501 {
502 INFO("Nothing to do. Use -s to split or -c to convert.");
503 return 0;
504 }
505
506 std::string const filename =
507 (output_arg.isSet()) ? output_arg.getValue() : input_arg.getValue();
508 int return_val(0);
509 if (split_arg.getValue())
510 {
511 return_val = splitFile(in, filename);
512 }
513 else if (convert_arg.getValue())
514 {
515 return_val = convertFile(in, filename);
516 }
517
518 in.close();
519 return return_val;
520}
int convertFile(std::ifstream &in, std::string const &file_name)
int splitFile(std::ifstream &in, std::string const &file_name)
Splits a TecPlot file containing multiple sections/zones into separate files.
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
GITINFOLIB_EXPORT const std::string ogs_version

References convertFile(), ERR(), INFO(), BaseLib::initOGSLogger(), BaseLib::makeLogLevelArg(), GitInfoLib::GitInfo::ogs_version, and splitFile().

◆ resetDataStructures()

void resetDataStructures ( std::size_t const & n_scalars,
std::vector< std::vector< double > > & scalars,
std::size_t & val_count )

Resets all data structures after a new "Variables"-description is found.

Definition at line 164 of file TecPlotTools.cpp.

167{
168 scalars.clear();
169 scalars.reserve(n_scalars);
170 for (std::size_t i = 0; i < n_scalars; ++i)
171 {
172 scalars.emplace_back(0);
173 }
174 val_count = 0;
175}

Referenced by convertFile().

◆ skipGeometrySection()

void skipGeometrySection ( std::ifstream & in,
std::string & line )

If a geometry-section is encountered, it is currently ignored.

Definition at line 256 of file TecPlotTools.cpp.

257{
258 while (std::getline(in, line))
259 {
260 if ((line.find("TITLE") != std::string::npos) ||
261 (line.find("VARIABLES") != std::string::npos) ||
262 (line.find("ZONE") != std::string::npos))
263 {
264 return;
265 }
266 }
267}

Referenced by convertFile().

◆ splitFile()

int splitFile ( std::ifstream & in,
std::string const & file_name )

Splits a TecPlot file containing multiple sections/zones into separate files.

Definition at line 270 of file TecPlotTools.cpp.

271{
272 std::ofstream out;
273 std::string line;
274 std::string name;
275 std::size_t val_count(0);
276 std::size_t val_total(0);
277 std::size_t write_count(0);
278 while (std::getline(in, line))
279 {
280 if (line.find("TITLE") != std::string::npos)
281 {
282 if (dataCountError(out, name, val_count, val_total))
283 {
284 return -3;
285 }
286 writeTecPlotSection(out, file_name, write_count, val_count,
287 val_total);
288 out << line << "\n";
289 continue;
290 }
291 if (line.find("VARIABLES") != std::string::npos)
292 {
293 if (dataCountError(out, name, val_count, val_total))
294 {
295 return -3;
296 }
297 writeTecPlotSection(out, file_name, write_count, val_count,
298 val_total);
299 out << line << "\n";
300 continue;
301 }
302 if (line.find("ZONE") != std::string::npos)
303 {
304 if (dataCountError(out, name, val_count, val_total))
305 {
306 return -3;
307 }
308 writeTecPlotSection(out, file_name, write_count, val_count,
309 val_total);
310 out << line << "\n";
311 name = getName(line);
312 std::pair<std::size_t, std::size_t> dims = getDimensions(line);
313 val_total = dims.first * dims.second;
314 val_count = 0;
315 continue;
316 }
317
318 out << line << "\n";
319 val_count++;
320 }
321 if (dataCountError(out, name, val_count, val_total))
322 {
323 return -3;
324 }
325 INFO("Writing time step #{}", write_count);
326 out.close();
327 INFO("Finished split.");
328 return 0;
329}
void writeTecPlotSection(std::ofstream &out, std::string const &file_name, std::size_t &write_count, std::size_t &val_count, std::size_t &val_total)
Writes one section/zone into a separate TecPlot file.

References dataCountError(), getDimensions(), getName(), INFO(), and writeTecPlotSection().

Referenced by main().

◆ trimVariable()

std::string trimVariable ( std::string & var)

Trims a substring containing a variable-name.

Definition at line 100 of file TecPlotTools.cpp.

101{
102 std::size_t const start = var.find_first_not_of("\"");
103 var = var.substr(start, std::string::npos);
104 std::size_t const end = var.find_first_of("\"");
105 return var.substr(0, end);
106}

Referenced by getVariables().

◆ writeDataToMesh()

int writeDataToMesh ( std::string const & file_name,
std::size_t & write_count,
std::vector< std::string > const & vec_names,
std::vector< std::vector< double > > const & scalars,
std::pair< std::size_t, std::size_t > const & dims )

Writes one section/zone into a separate OGS-mesh.

Definition at line 200 of file TecPlotTools.cpp.

205{
206 double cellsize = 0;
207 for (std::size_t i = 0; i < vec_names.size(); ++i)
208 {
209 if (vec_names[i] == "x" || vec_names[i] == "X")
210 {
211 cellsize = scalars[i][1] - scalars[i][0];
212 break;
213 }
214 }
215
216 if (cellsize == 0)
217 {
218 ERR("Cell size not found. Aborting...");
219 return -4;
220 }
221
222 GeoLib::Point origin(0, 0, 0);
223 GeoLib::RasterHeader header{dims.first, dims.second, 1,
224 origin, cellsize, -9999};
225
226 std::unique_ptr<MeshLib::Mesh> mesh(
227 MeshToolsLib::RasterToMesh::convert(scalars[0].data(),
228 header,
231 vec_names[0]));
232 MeshLib::Properties& properties = mesh->getProperties();
233 for (std::size_t i = 1; i < vec_names.size(); ++i)
234 {
235 auto* const prop = properties.createNewPropertyVector<double>(
236 vec_names[i], MeshLib::MeshItemType::Cell, 1);
237 if (!prop)
238 {
239 ERR("Error creating array '{:s}'.", vec_names[i]);
240 return -5;
241 }
242 prop->assign(scalars[i]);
243 }
244
245 std::size_t const delim_pos(file_name.find_last_of("."));
246 std::string const base_name(file_name.substr(0, delim_pos + 1));
247 std::string const extension(file_name.substr(delim_pos, std::string::npos));
248
249 INFO("Writing section #{}", write_count);
250 MeshLib::IO::VtuInterface vtu(mesh.get());
251 vtu.writeToFile(base_name + std::to_string(write_count++) + extension);
252 return 0;
253}
Reads and writes VtkXMLUnstructuredGrid-files (vtu) to and from OGS data structures....
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
constexpr void assign(R &&r)
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")
Contains the relevant information when storing a geoscientific raster data.
Definition Raster.h:18

References MeshLib::PropertyVector< PROP_VAL_TYPE >::assign(), MeshLib::Cell, MeshToolsLib::RasterToMesh::convert(), MeshLib::Properties::createNewPropertyVector(), MeshLib::DATAVECTOR, ERR(), INFO(), MeshLib::QUAD, and MeshLib::IO::VtuInterface::writeToFile().

Referenced by convertFile().

◆ writeTecPlotSection()

void writeTecPlotSection ( std::ofstream & out,
std::string const & file_name,
std::size_t & write_count,
std::size_t & val_count,
std::size_t & val_total )

Writes one section/zone into a separate TecPlot file.

Definition at line 178 of file TecPlotTools.cpp.

183{
184 if (write_count == 0 || val_total != 0)
185 {
186 std::size_t const delim_pos(file_name.find_last_of("."));
187 std::string const base_name(file_name.substr(0, delim_pos + 1));
188 std::string const extension(
189 file_name.substr(delim_pos, std::string::npos));
190
191 val_count = 0;
192 val_total = 0;
193 INFO("Writing section #{}", write_count);
194 out.close();
195 out.open(base_name + std::to_string(write_count++) + extension);
196 }
197}

References INFO().

Referenced by splitFile().