OGS
FileIO::CsvInterface Class Reference

Detailed Description

Interface for reading CSV file formats.

Definition at line 30 of file CsvInterface.h.

#include <CsvInterface.h>

Inheritance diagram for FileIO::CsvInterface:
[legend]
Collaboration diagram for FileIO::CsvInterface:
[legend]

Public Member Functions

 CsvInterface ()
 Constructor (only needed for writing files)
std::size_t getNArrays () const
 Returns the number of vectors currently staged for writing.
void addIndexVectorForWriting (std::size_t s)
 Adds an index vector of size s to the CSV file.
void setCsvHeader (bool write_header)
 Stores if the CSV file to be written should include a header or not.
template<typename T>
bool addVectorForWriting (std::string const &vec_name, std::vector< T > const &vec)
bool write () override
 Writes the CSV file.
Public Member Functions inherited from BaseLib::IO::Writer
 Writer ()
virtual ~Writer ()=default
std::string writeToString ()
 Writes the object to a string.

Static Public Member Functions

static std::vector< std::string > getColumnNames (std::string const &fname, char delim)
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points)
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points, std::string const &x_column_name, std::string const &y_column_name, std::string const &z_column_name="")
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points, std::size_t x_column_idx, std::size_t y_column_idx, std::size_t z_column_idx=std::numeric_limits< std::size_t >::max())
template<typename T>
static std::pair< int, std::vector< T > > readColumn (std::string const &fname, char delim, std::string const &column_name)
template<typename T>
static std::pair< int, std::vector< T > > readColumn (std::string const &fname, char delim, std::size_t column_idx)

Private Member Functions

std::size_t getVectorSize (std::size_t idx) const
 Returns the size of the vector with the given index.
void writeValue (std::size_t vec_idx, std::size_t in_vec_idx)

Static Private Member Functions

static int readPoints (std::ifstream &in, char delim, std::vector< GeoLib::Point * > &points, std::array< std::size_t, 3 > const &column_idx)
 Actual point reader for public methods.
template<typename T>
static std::pair< int, std::vector< T > > readColumn (std::ifstream &in, char delim, std::size_t column_idx)
 Actual column reader for public methods.
static std::size_t findColumn (std::string const &line, char delim, std::string const &column_name)

Private Attributes

bool _writeCsvHeader {true}
std::vector< std::string > _vec_names
std::vector< std::any > _data

Additional Inherited Members

Protected Attributes inherited from BaseLib::IO::Writer
std::ostringstream out
 The stream to write to.

Constructor & Destructor Documentation

◆ CsvInterface()

FileIO::CsvInterface::CsvInterface ( )
default

Constructor (only needed for writing files)

Member Function Documentation

◆ addIndexVectorForWriting()

void FileIO::CsvInterface::addIndexVectorForWriting ( std::size_t s)

Adds an index vector of size s to the CSV file.

Definition at line 244 of file CsvInterface.cpp.

245{
246 std::vector<int> idx_vec(s);
247 std::iota(idx_vec.begin(), idx_vec.end(), 0);
248 addVectorForWriting("Index", idx_vec);
249}
bool addVectorForWriting(std::string const &vec_name, std::vector< T > const &vec)

References addVectorForWriting().

Referenced by FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ addVectorForWriting()

template<typename T>
bool FileIO::CsvInterface::addVectorForWriting ( std::string const & vec_name,
std::vector< T > const & vec )
inline

Adds a data vector to the CSV file. All data vectors have to have the same size. Vectors will be written in the same sequence they have been added to the interface.

Definition at line 54 of file CsvInterface.h.

56 {
57 static_assert(
58 std::is_same_v<T, std::string> || std::is_same_v<T, double> ||
59 std::is_same_v<T, int>,
60 "CsvInterface can only write vectors of strings, doubles or ints.");
61
62 if (!_data.empty())
63 {
64 std::size_t const vec_size(getVectorSize(0));
65 if (vec_size != vec.size())
66 {
67 ERR("Vector size does not match existing data (should be "
68 "{:d}).",
69 vec_size);
70 return false;
71 }
72 }
73
74 _vec_names.push_back(vec_name);
75 _data.push_back(vec);
76 return true;
77 }
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
std::vector< std::any > _data
std::vector< std::string > _vec_names
std::size_t getVectorSize(std::size_t idx) const
Returns the size of the vector with the given index.

References _data, _vec_names, ERR(), and getVectorSize().

Referenced by addIndexVectorForWriting(), FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ findColumn()

std::size_t FileIO::CsvInterface::findColumn ( std::string const & line,
char delim,
std::string const & column_name )
staticprivate

Returns the number of the column with column_name (or std::numeric_limits::max() if no such column has been found).

Definition at line 216 of file CsvInterface.cpp.

218{
219 std::list<std::string> const fields = BaseLib::splitString(line, delim);
220 if (fields.empty())
221 {
222 return std::numeric_limits<std::size_t>::max();
223 }
224
225 std::size_t count(0);
226 for (const auto& field : fields)
227 {
228 if (field == column_name)
229 {
230 break;
231 }
232
233 count++;
234 }
235
236 if (count == fields.size())
237 {
238 return std::numeric_limits<std::size_t>::max();
239 }
240
241 return count;
242}
std::vector< std::string > splitString(std::string const &str)

References BaseLib::splitString().

Referenced by readColumn(), and readPoints().

◆ getColumnNames()

std::vector< std::string > FileIO::CsvInterface::getColumnNames ( std::string const & fname,
char delim )
static

Returns a vector containing the names of columns in the file (assuming the file has a header)

Definition at line 15 of file CsvInterface.cpp.

17{
18 std::ifstream in(fname.c_str());
19
20 if (!in.is_open())
21 {
22 ERR("CsvInterface::getColumnNames(): Could not open file {:s}.", fname);
23 return std::vector<std::string>();
24 }
25 std::string line;
26 if (!std::getline(in, line))
27 {
28 ERR("CsvInterface::getColumnNames(): Could not read line from file "
29 "{:s}. Is it empty?",
30 fname);
31 return {};
32 }
33
34 if (delim == '\n')
35 {
36 return {};
37 }
38
39 std::list<std::string> fields = BaseLib::splitString(line, delim);
40 if (fields.size() < 2)
41 {
42 for (char const d : {'\t', ';', ','})
43 {
44 fields = BaseLib::splitString(line, d);
45 if (fields.size() > 1)
46 {
47 break;
48 }
49 }
50 }
51 return {begin(fields), end(fields)};
52}

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

◆ getNArrays()

std::size_t FileIO::CsvInterface::getNArrays ( ) const
inline

Returns the number of vectors currently staged for writing.

Definition at line 37 of file CsvInterface.h.

37{ return _vec_names.size(); }

References _vec_names.

Referenced by FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ getVectorSize()

std::size_t FileIO::CsvInterface::getVectorSize ( std::size_t idx) const
private

Returns the size of the vector with the given index.

Definition at line 285 of file CsvInterface.cpp.

286{
287 if (_data[idx].type() == typeid(std::vector<std::string>))
288 {
289 return std::any_cast<std::vector<std::string>>(_data[idx]).size();
290 }
291 if (_data[idx].type() == typeid(std::vector<double>))
292 {
293 return std::any_cast<std::vector<double>>(_data[idx]).size();
294 }
295 if (_data[idx].type() == typeid(std::vector<int>))
296 {
297 return std::any_cast<std::vector<int>>(_data[idx]).size();
298 }
299 return 0;
300}
constexpr int size(int const displacement_dim)
Vectorized tensor size for given displacement dimension.

References _data.

Referenced by addVectorForWriting(), and write().

◆ readColumn() [1/3]

template<typename T>
std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::ifstream & in,
char delim,
std::size_t column_idx )
inlinestaticprivate

Actual column reader for public methods.

Definition at line 189 of file CsvInterface.h.

192 {
193 std::vector<T> data_array;
194 std::string line;
195 std::size_t line_count(0);
196 int error_count(0);
197 while (std::getline(in, line))
198 {
199 line_count++;
200 std::list<std::string> const fields =
201 BaseLib::splitString(line, delim);
202
203 if (fields.size() < column_idx + 1)
204 {
205 ERR("Line {:d} contains not enough columns of data. Skipping "
206 "line...",
207 line_count);
208 error_count++;
209 continue;
210 }
211 auto it = fields.begin();
212 std::advance(it, column_idx);
213
214 std::istringstream stream(*it);
215 T value;
216 if (!(stream >> value))
217 {
218 ERR("Error reading value in line {:d}.", line_count);
219 error_count++;
220 continue;
221 }
222
223 data_array.push_back(value);
224 }
225 return {error_count, data_array};
226 }

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

◆ readColumn() [2/3]

template<typename T>
std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::string const & fname,
char delim,
std::size_t column_idx )
inlinestatic

Definition at line 168 of file CsvInterface.h.

171 {
172 std::ifstream in(fname.c_str());
173 if (!in.is_open())
174 {
175 ERR("CsvInterface::readColumn(): Could not open file {:s}.", fname);
176 return {-1, {}};
177 }
178 return readColumn<T>(in, delim, column_idx);
179 }
static std::pair< int, std::vector< T > > readColumn(std::string const &fname, char delim, std::string const &column_name)

References ERR(), and readColumn().

◆ readColumn() [3/3]

template<typename T>
std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::string const & fname,
char delim,
std::string const & column_name )
inlinestatic

Reads a column of the given name from a CSV file.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
column_nameThe column's name to read
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file) and an possibly empty vector containing the read values

Definition at line 145 of file CsvInterface.h.

147 {
148 std::ifstream in(fname.c_str());
149 if (!in.is_open())
150 {
151 ERR("CsvInterface::readColumn(): Could not open file {:s}.", fname);
152 return {-1, {}};
153 }
154
155 std::string line;
156 std::getline(in, line);
157 std::size_t const column_idx =
158 CsvInterface::findColumn(line, delim, column_name);
159 if (column_idx == std::numeric_limits<std::size_t>::max())
160 {
161 ERR("Column '{:s}' not found in file header.", column_name);
162 return {-1, {}};
163 }
164 return readColumn<T>(in, delim, column_idx);
165 }
static std::size_t findColumn(std::string const &line, char delim, std::string const &column_name)

References ERR(), findColumn(), and readColumn().

Referenced by readColumn(), and readColumn().

◆ readPoints() [1/4]

int FileIO::CsvInterface::readPoints ( std::ifstream & in,
char delim,
std::vector< GeoLib::Point * > & points,
std::array< std::size_t, 3 > const & column_idx )
staticprivate

Actual point reader for public methods.

Definition at line 162 of file CsvInterface.cpp.

165{
166 std::array<std::size_t, 3> order = {{0, 1, 2}};
167 std::sort(order.begin(), order.end(),
168 [&column_idx](std::size_t idx1, std::size_t idx2)
169 { return column_idx[idx1] < column_idx[idx2]; });
170 std::array<std::size_t, 3> const column_advance = {
171 {column_idx[order[0]], column_idx[order[1]] - column_idx[order[0]],
172 column_idx[order[2]] - column_idx[order[1]]}};
173
174 std::string line;
175 std::size_t line_count(0);
176 std::size_t error_count(0);
177 std::list<std::string>::const_iterator it;
178
179 while (std::getline(in, line))
180 {
181 line_count++;
182 std::list<std::string> const fields = BaseLib::splitString(line, delim);
183
184 if (fields.size() < column_idx[order[2]] + 1)
185 {
186 ERR("Line {:d} contains not enough columns of data. Skipping "
187 "line...",
188 line_count);
189 error_count++;
190 continue;
191 }
192
193 it = fields.begin();
194 try
195 {
196 std::advance(it, column_advance[0]);
197 std::array<double, 3> point{};
198 point[order[0]] = std::stod(*it);
199 std::advance(it, column_advance[1]);
200 point[order[1]] = std::stod(*it);
201 std::advance(it, column_advance[2]);
202 point[order[2]] =
203 (column_idx[1] == column_idx[2]) ? 0 : std::stod(*it);
204 points.push_back(new GeoLib::Point(point[0], point[1], point[2]));
205 }
206 catch (const std::invalid_argument&)
207 {
208 ERR("Error converting data to coordinates in line {:d}.",
209 line_count);
210 error_count++;
211 }
212 }
213 return error_count;
214}

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

◆ readPoints() [2/4]

int FileIO::CsvInterface::readPoints ( std::string const & fname,
char delim,
std::vector< GeoLib::Point * > & points )
static

Reads 3D points from a CSV file. It is assumed that the file has a header specifying a name for each of the columns. The first three columns will be interpreted as x-, y- and z-coordinate, respectively.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 54 of file CsvInterface.cpp.

56{
57 std::ifstream in(fname.c_str());
58
59 if (!in.is_open())
60 {
61 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
62 return -1;
63 }
64
65 std::string line;
66 std::getline(in, line);
67
68 std::size_t line_count(0);
69 std::size_t error_count(0);
70 std::list<std::string>::const_iterator it;
71 while (std::getline(in, line))
72 {
73 line_count++;
74 std::list<std::string> const fields = BaseLib::splitString(line, delim);
75
76 if (fields.size() < 3)
77 {
78 ERR("Line {:d} contains not enough columns of data. Skipping "
79 "line...",
80 line_count);
81 error_count++;
82 continue;
83 }
84 it = fields.begin();
85 try
86 {
87 std::array<double, 3> point{};
88 point[0] = std::stod(*it);
89 point[1] = std::stod(*(++it));
90 point[2] = std::stod(*(++it));
91 points.push_back(new GeoLib::Point(point[0], point[1], point[2]));
92 }
93 catch (const std::invalid_argument&)
94 {
95 ERR("Error converting data to coordinates in line {:d}.",
96 line_count);
97 }
98 }
99 return error_count;
100}

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

Referenced by readPoints(), and readPoints().

◆ readPoints() [3/4]

int FileIO::CsvInterface::readPoints ( std::string const & fname,
char delim,
std::vector< GeoLib::Point * > & points,
std::size_t x_column_idx,
std::size_t y_column_idx,
std::size_t z_column_idx = std::numeric_limits<std::size_t>::max() )
static

Reads 3D points from a headerless CSV file, so columns for x-, y- and z-coordinates have to be specified using indices (starting with 0). If z_column_idx is not given (or set to numeric_limits::max()), all z-coordinates will be set to zero.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
x_column_idxIndex of the column to be interpreted as x-coordinate
y_column_idxIndex of the column to be interpreted as y-coordinate
z_column_idxIndex of the column to be interpreted as z-coordinate
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 139 of file CsvInterface.cpp.

143{
144 std::ifstream in(fname.c_str());
145
146 if (!in.is_open())
147 {
148 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
149 return -1;
150 }
151
152 if (z_column_idx == std::numeric_limits<std::size_t>::max())
153 {
154 z_column_idx = y_column_idx;
155 }
156 std::array<std::size_t, 3> const column_idx = {
157 {x_column_idx, y_column_idx, z_column_idx}};
158
159 return readPoints(in, delim, points, column_idx);
160}
static int readPoints(std::string const &fname, char delim, std::vector< GeoLib::Point * > &points)

References ERR(), and readPoints().

◆ readPoints() [4/4]

int FileIO::CsvInterface::readPoints ( std::string const & fname,
char delim,
std::vector< GeoLib::Point * > & points,
std::string const & x_column_name,
std::string const & y_column_name,
std::string const & z_column_name = "" )
static

Reads 3D points from a CSV file. It is assumed that the file has a header specifying a name for each of the columns. The columns specified in the function call will be used for reading x-, y- and z-coordinates, respectively If z_column_name is an empty string or not given at all, all z-coordinates will be set to zero.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
x_column_nameName of the column to be interpreted as x-coordinate
y_column_nameName of the column to be interpreted as y-coordinate
z_column_nameName of the column to be interpreted as z-coordinate
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 102 of file CsvInterface.cpp.

107{
108 std::ifstream in(fname.c_str());
109 std::array<std::string, 3> const column_names = {
110 {x_column_name, y_column_name, z_column_name}};
111
112 if (!in.is_open())
113 {
114 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
115 return -1;
116 }
117
118 std::string line;
119 std::getline(in, line);
120 std::array<std::size_t, 3> const column_idx = {
121 {CsvInterface::findColumn(line, delim, x_column_name),
122 CsvInterface::findColumn(line, delim, y_column_name),
123 (z_column_name.empty())
124 ? CsvInterface::findColumn(line, delim, y_column_name)
125 : CsvInterface::findColumn(line, delim, z_column_name)}};
126
127 for (std::size_t i = 0; i < 3; ++i)
128 {
129 if (column_idx[i] == std::numeric_limits<std::size_t>::max())
130 {
131 ERR("Column '{:s}' not found in file header.", column_names[i]);
132 return -1;
133 }
134 }
135
136 return readPoints(in, delim, points, column_idx);
137}
CsvInterface()
Constructor (only needed for writing files)

References ERR(), findColumn(), and readPoints().

◆ setCsvHeader()

void FileIO::CsvInterface::setCsvHeader ( bool write_header)
inline

Stores if the CSV file to be written should include a header or not.

Definition at line 48 of file CsvInterface.h.

48{ _writeCsvHeader = write_header; }

References _writeCsvHeader.

◆ write()

bool FileIO::CsvInterface::write ( )
overridevirtual

Writes the CSV file.

Implements BaseLib::IO::Writer.

Definition at line 251 of file CsvInterface.cpp.

252{
253 if (_data.empty())
254 {
255 ERR("CsvInterface::write() - No data to write.");
256 return false;
257 }
258
259 std::size_t const n_vecs(_data.size());
260 std::size_t const vec_size(getVectorSize(0));
261
262 if (_writeCsvHeader)
263 {
264 out << _vec_names[0];
265 for (std::size_t i = 1; i < n_vecs; ++i)
266 {
267 out << "\t" << _vec_names[i];
268 }
269 out << "\n";
270 }
271
272 for (std::size_t j = 0; j < vec_size; ++j)
273 {
274 writeValue(0, j);
275 for (std::size_t i = 1; i < n_vecs; ++i)
276 {
277 out << "\t";
278 writeValue(i, j);
279 }
280 out << "\n";
281 }
282 return true;
283}
std::ostringstream out
The stream to write to.
Definition Writer.h:36
void writeValue(std::size_t vec_idx, std::size_t in_vec_idx)

References _data, _vec_names, _writeCsvHeader, ERR(), getVectorSize(), BaseLib::IO::Writer::out, and writeValue().

◆ writeValue()

void FileIO::CsvInterface::writeValue ( std::size_t vec_idx,
std::size_t in_vec_idx )
private

Writes a value from a vector to the file.

Parameters
vec_idxIndex of the vector
in_vec_idxEntry in the selected vector

Definition at line 302 of file CsvInterface.cpp.

303{
304 if (_data[vec_idx].type() == typeid(std::vector<std::string>))
305 {
307 _data[vec_idx])[in_vec_idx];
308 }
309 else if (_data[vec_idx].type() == typeid(std::vector<double>))
310 {
311 out << std::any_cast<std::vector<double>>(_data[vec_idx])[in_vec_idx];
312 }
313 else if (_data[vec_idx].type() == typeid(std::vector<int>))
314 {
315 out << std::any_cast<std::vector<int>>(_data[vec_idx])[in_vec_idx];
316 }
317}

References _data, and BaseLib::IO::Writer::out.

Referenced by write().

Member Data Documentation

◆ _data

std::vector<std::any> FileIO::CsvInterface::_data
private

Definition at line 245 of file CsvInterface.h.

Referenced by addVectorForWriting(), getVectorSize(), write(), and writeValue().

◆ _vec_names

std::vector<std::string> FileIO::CsvInterface::_vec_names
private

Definition at line 244 of file CsvInterface.h.

Referenced by addVectorForWriting(), getNArrays(), and write().

◆ _writeCsvHeader

bool FileIO::CsvInterface::_writeCsvHeader {true}
private

Definition at line 243 of file CsvInterface.h.

243{true};

Referenced by setCsvHeader(), and write().


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