14 #include <type_traits> 28 : _filename(filename),
30 _ignore_empty_lines(true),
45 std::size_t size_raw = 0;
46 std::size_t size_offsets = 0;
49 if (_communicator ==
nullptr || _communicator->rank() == 0)
55 std::ifstream stream_data(_filename);
56 if (stream_data.peek() == std::ifstream::traits_type::eof())
60 if (_format_flag == FormatFlag::ROWS)
61 readRowData(stream_data, raw);
63 readColumnData(stream_data, raw);
66 n_cols = _names.size();
72 size_raw = raw.size();
73 size_offsets = _row_offsets.size();
76 if (_communicator !=
nullptr)
79 _communicator->broadcast(n_cols);
80 _names.resize(n_cols);
81 _communicator->broadcast(_names);
84 _communicator->broadcast(size_raw);
86 _communicator->broadcast(raw);
89 if (_format_flag == FormatFlag::ROWS)
91 _communicator->broadcast(size_offsets);
92 _row_offsets.resize(size_offsets);
93 _communicator->broadcast(_row_offsets);
101 if (_format_flag == FormatFlag::ROWS)
103 typename std::vector<T>::iterator start = raw.begin();
104 for (std::size_t j = 0; j < n_cols; ++j)
106 _data[j] = std::vector<T>(start, start + _row_offsets[j]);
107 std::advance(start, _row_offsets[j]);
114 mooseAssert(raw.size() % n_cols == 0,
115 "The raw data is not evenly divisible by the number of columns.");
116 const std::size_t n_rows = raw.size() / n_cols;
117 for (std::size_t j = 0; j < n_cols; ++j)
119 _data[j].resize(n_rows);
120 for (std::size_t i = 0; i < n_rows; ++i)
121 _data[j][i] = raw[i * n_cols + j];
126 template <
typename T>
130 std::size_t n_entries = 0;
131 for (std::size_t i = 0; i < _data.size(); ++i)
132 n_entries += _data[i].size();
137 template <
typename T>
138 const std::vector<std::string> &
144 template <
typename T>
145 const std::vector<std::vector<T>> &
152 const std::vector<Point>
155 std::vector<Point> point_data;
157 for (std::size_t i = 0; i < _data.size(); ++i)
171 if (_data.at(i).size() != LIBMESH_DIM)
172 mooseError(
"Each point in file ", _filename,
" must have ", LIBMESH_DIM,
" entries");
174 for (std::size_t j = 0; j < LIBMESH_DIM; ++j)
175 point(j) = _data.at(i).at(j);
177 point_data.push_back(point);
183 template <
typename T>
184 const std::vector<Point>
190 template <
typename T>
191 const std::vector<T> &
194 const auto it = find(_names.begin(), _names.end(),
name);
195 if (it == _names.end())
196 mooseError(
"Could not find '",
name,
"' in header of file ", _filename,
".");
197 return _data[std::distance(_names.begin(), it)];
200 template <
typename T>
201 const std::vector<T> &
204 if (index >= _data.size())
207 " is out-of-range for the available data in file '",
215 template <
typename T>
224 unsigned int count = 0;
227 std::size_t n_cols = INVALID_SIZE;
230 while (std::getline(stream_data, line))
237 if (preprocessLine(line, count))
241 if (_names.empty() && header(line))
244 for (std::string & str : _names)
250 processLine(line, row, count);
253 if (n_cols == INVALID_SIZE)
257 if (row.size() != n_cols)
260 ") does not match the number of columns expected (",
262 ") based on the first row of the file when reading row ",
269 output.insert(output.end(), row.begin(), row.end());
275 _names.resize(n_cols);
277 for (std::size_t i = 0; i < n_cols; ++i)
279 std::stringstream ss;
280 ss <<
"column_" << std::setw(padding) << std::setfill(
'0') << i;
281 _names[i] = ss.str();
286 template <
typename T>
293 unsigned int linenum = 0;
297 _row_offsets.clear();
300 while (std::getline(stream_data, line))
307 if (preprocessLine(line, linenum))
312 std::size_t index = line.find_first_of(
delimiter(line));
313 _names.push_back(line.substr(0, index));
314 line = line.substr(index);
318 processLine(line, row, linenum);
321 _row_offsets.push_back(row.size());
324 output.insert(output.end(), row.begin(), row.end());
331 for (std::size_t i = 0; i < _row_offsets.size(); ++i)
333 std::stringstream ss;
334 ss <<
"row_" << std::setw(padding) << std::setfill(
'0') << i;
335 _names.push_back(ss.str());
340 template <
typename T>
345 std::size_t index = _row_comment.empty() ? line.size() : line.find_first_of(_row_comment);
351 if (_ignore_empty_lines)
354 mooseError(
"Failed to read line ", num,
" in file ", _filename,
". The line is empty.");
359 template <
typename T>
362 std::vector<T> & row,
363 const unsigned int & num)
365 std::string line_copy = line;
367 if constexpr (!std::is_same_v<T, std::string>)
375 bool status = MooseUtils::tokenizeAndConvert<T>(line_copy, row,
delimiter(line));
377 mooseError(
"Failed to convert a delimited data into double when reading line ",
387 template <
typename T>
391 if (_delimiter.empty())
393 if (line.find(
",") != std::string::npos)
395 else if (line.find(
"\t") != std::string::npos)
403 template <
typename T>
407 switch (_header_flag)
409 case HeaderFlag::OFF:
416 std::vector<double> row;
417 bool contains_alpha = !MooseUtils::tokenizeAndConvert<double>(line, row,
delimiter(line));
421 _header_flag = contains_alpha ? HeaderFlag::ON : HeaderFlag::OFF;
422 return contains_alpha;
std::string name(const ElemQuality q)
std::string toLower(const std::string &name)
Convert supplied string to lower case.
void tokenize(const std::string &str, std::vector< T > &elements, unsigned int min_len=1, const std::string &delims="/")
This function will split the passed in string on a set of delimiters appending the substrings to the ...
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
const std::vector< Point > getDataAsPoints() const
Get the data in Point format.
DelimitedFileReaderTempl(const std::string &filename, const libMesh::Parallel::Communicator *comm=nullptr)
void readRowData(std::ifstream &stream_data, std::vector< T > &output)
void readColumnData(std::ifstream &stream_data, std::vector< T > &output)
Read the numeric data as rows or columns into a single vector.
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
Checks to see if a file is readable (exists and permissions)
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
std::size_t numEntries() const
Get the total number of entries in the file.
void read()
Perform the actual data reading.
bool header(const std::string &line)
Return the header flag, if it is set to AUTO attempt to determine if a header exists in line...
const std::vector< std::vector< T > > & getData() const
Return the rows/columns of data.
const std::string & delimiter(const std::string &line)
Determine the delimiter.
bool preprocessLine(std::string &line, const unsigned int &num)
Check the content of the line and if it should be skipped.
int numDigits(const T &num)
Return the number of digits for a number.
Utility class for reading delimited data (e.g., CSV data).
void processLine(const std::string &line, std::vector< T > &row, const unsigned int &num)
Populate supplied vector with content from line.
const std::vector< std::string > & getNames() const
Return the column/row names.
std::string replaceAll(std::string str, const std::string &from, const std::string &to)
Replaces all occurrences of from in str with to and returns the result.