#include <TextInFile.hpp>
Classes | |
class | ColumnInfo |
Public Member Functions | |
TextInFile (const SimulationItem *item, string filename, string description, bool resource=false) | |
~TextInFile () | |
void | addColumn (string description, string quantity=string(), string defaultUnit=string()) |
void | close () |
vector< Array > | readAllColumns () |
template<typename... Columns, typename = std::enable_if_t<sizeof...(Columns) != 0>> | |
void | readAllColumns (Columns &... columns) |
vector< Array > | readAllRows () |
bool | readNonLeaf (int &nx, int &ny, int &nz) |
bool | readRow (Array &values) |
template<typename... Values, typename = std::enable_if_t<CompileTimeUtils::isFloatArgList<Values...>()>> | |
bool | readRow (Values &... values) |
void | useColumns (string columns) |
Private Member Functions | |
size_t | indexForName (string name) const |
size_t | waveIndexForSpecificQuantity () const |
Static Private Member Functions | |
template<typename... Columns> | |
static void | assignColumns (size_t index, vector< Array > &result, Array &column, Columns &... columns) |
static void | assignColumns (size_t, vector< Array > &) |
template<typename... Values> | |
static void | assignValues (size_t index, const Array &result, double &value, Values &... values) |
static void | assignValues (size_t, const Array &) |
Private Attributes | |
bool | _allowZeroCols |
vector< ColumnInfo > | _colv |
bool | _doAutoCols |
bool | _hasBinaryOpen |
bool | _hasFileInfo |
bool | _hasProgInfo |
bool | _hasTextOpen |
bool | _haveZeroCols |
std::ifstream | _in |
bool | _isResource |
Log * | _log |
vector< size_t > | _logColIndices |
size_t | _numLogCols |
StoredColumns | _scol |
Units * | _units |
This class allows reading a table of floating point values from a column text file with support for unit conversions. The filename is specified in the constructor, and information about the columns expected in the file is specified by calling the addColumn() function for each column.
When reading a column text file, empty lines and lines starting with # are ignored, except for the unit specification header lines described below. Other lines must contain a predefined number of floating point values separated by whitespace (spaces or tabs). The number of expected values is determined for each input file under program control. It is an error for a line to contain fewer values than expected (or for any of the values to be improperly formatted). On the other hand, any additional information on a line beyond the last expected value is ignored.
It is recommended that the header of the input file includes column information in the format described below. This provides formal documentation about the contents of the file and specifies the units used for the values in each column. If there is no column information in the file (i.e. none of the header lines match the syntax decribed below), the default units are used as specified by the program (i.e. the client class invoking TextInFile).
For example, a two-column input file might have the following header:
# My personal SED written from Python # column 1: wavelength (Angstrom) # column 2: specific luminosity (W/Hz) # ... data ...
There must be a header line for each column with the following contents from left to right:
Extra whitespace is allowed between the various fields. The unit string must exactly match one of the unit strings supported by SKIRT for the expected quantity. The column info lines must occur in the same order as the data columns. Extra header lines are allowed between, before, and after the column info lines.
By default, the columns in the file must be in the exact order as expected by the program (i.e. the client class invoking TextInFile). However, some client classes offer a user-configurable useColumns property that allows column reordering, as described in the documentation for the TextInFile::useColumns() function.
Reading large text files can be very slow. Therefore, in certain cases, this class supports the possibility to provide the input file in a much faster SKIRT-specific binary file format, i.e. the stored columns format described in the StoredColumns class. This file format has the following limitations:
If the input file provided to the TextInFile constructor has the .scol filename extension, the implementation automatically switches to reading the binary file format instead of the regular column text format. This is fully transparent to the caller of the TextInFile class.
TextInFile::TextInFile | ( | const SimulationItem * | item, |
string | filename, | ||
string | description, | ||
bool | resource = false |
||
) |
The constructor opens the specified file for reading; if the file can't be opened, a FatalError is thrown. The constructor takes several arguments: (1) item specifies a simulation item in the hierarchy of the caller (usually the caller itself) used to retrieve the input file path and an appropriate logger; (2) filename specifies the name of the file, including filename extension but excluding path and simulation prefix; (3) description describes the contents of the file for use in the log message issued after the file is successfully opened; (4) resource indicates whether the file is located in the resources directory (true) or in the regular user input file directory (false, the default value).
If the specified file has the .scol filename extension, the implementation automatically switches to reading the binary SKIRT column file format instead of the regular column text format. For more information, see the class header.
TextInFile::~TextInFile | ( | ) |
void TextInFile::addColumn | ( | string | description, |
string | quantity = string() , |
||
string | defaultUnit = string() |
||
) |
This function (virtually) adds a new column to the text file, characterized by the given description and unit information. The description argument is used only for logging purposes. The quantity argument specifies the physical quantity represented by the column. It must match one of the quantity strings supported by the Units system, or one of the special quantity strings recognized by this class (see below). The defaultUnit argument specifies the default unit string, which is used in case the input file does not contain column information.
In addition to the quantity strings supported by the Units system, this function supports the following special quantity strings.
The function looks for and, if present, reads the header information line corresponding to this column. The unit information from the header is stored with the information provided by the function arguments for later use.
void TextInFile::close | ( | ) |
This function closes the file if it was not already closed. It is best to call close() or allow the object to go out of scope before logging other messages or starting another significant chunk of work.
|
private |
This function returns the zero-based index of the column that has a file info description equal to the given name, or an error value if there is no such column or if there are multiple such columns.
vector< Array > TextInFile::readAllColumns | ( | ) |
This function reads all rows from a column text file (from the current position until the end of the file), transposes the data repesentation from rows into columns, and returns the resulting values as a vector of column arrays. For each row, this function behaves just like readRow(Array&).
|
inline |
This function reads all rows from a column text file (from the current position until the end of the file), transposes the data repesentation from rows into columns, and stores the resulting column arrays in the variables passed to the function by reference. For each row, this function behaves just like readRow(Array&).
vector< Array > TextInFile::readAllRows | ( | ) |
This function reads all rows from a column text file (from the current position until the end of the file), and returns the resulting values as a vector of row arrays. For each row, this function behaves just like readRow(Array&).
bool TextInFile::readNonLeaf | ( | int & | nx, |
int & | ny, | ||
int & | nz | ||
) |
This is a specialty function intended for use by the AdaptiveMeshSnapshot class when importing an adaptive mesh text column file. The function attempts to read a line containing a nonleaf node specification. Such a line starts with an exclamation mark, which must be followed by three integers (one subdivision specifier for each dimension).
If the next line (after skipping comments and empty lines) starts with an exclamation mark, the function processes it as a nonleaf node specification. If this is successful, the function stores the parsed specifiers in the arguments and returns true. If the line cannot be parsed, a fatal error is thrown.
If the next line (after skipping comments and empty lines) does not start with an exclamation mark, the contents of the function arguments is undefined and the function returns false. In this case, the function has not consumed any information other than comments and white space. The file cursor is left just before the next regular line (i.e. a line not starting with an exclamation mark), or at the end of the file.
bool TextInFile::readRow | ( | Array & | values | ) |
This function reads the next row from a column text file and stores the resulting values in the array passed to the function by reference. The function first skips empty lines and lines starting with a hash character, and then reads a single text line containing data values separated by white space.
The number of expected values corresponds to the number of columns in the file, which is determined by repeated calls to the addColumn() function. If the data line contains fewer values than expected, or if any of the values is improperly formatted for a floating point number, the function throws a FatalError (the size and contents of the values array are undefined). Any additional information on the line beyond the last expected value is ignored.
If a row was successfully read, the input values are converted from the input units (as specified in the file header or using the default given in the addColumn() function) to SKIRT-internal units. Finally, the values array is set to the appropriate length, the converted input values are stored into it in column order, and the function returns true.
If the end of the file is reached before a row can be read, the function returns false and the size and contents of the values array are undefined.
|
inline |
This variadic template function reads the next row from a column text file and stores the resulting values in the variables passed to the function by reference. For example:
double a,b,c,d; bool success = in.readRow(a,b,c,d); // reads a row from a file with 4 columns
This function behaves just like the readRow(Array&) version. The number of arguments must match the number of columns in the file.
void TextInFile::useColumns | ( | string | columns | ) |
The columns string argument of this function specifies a mapping between the "physical" columns in the file (defined by the column information in the file header) and the "logical" columns expected by the program (defined by the TextInFile client through repeated calls to the addColumn() function). Once this mapping has been established, the program only sees the logical ordering. In other words, the subsequent calls to the addColumn() function are matched to the corresponding logical columns, and the readXxx() functions retrieve logical columns only.
The useColumns() function can be called with a non-empty columns string at most once for each file, and such invocation should occur before the first invocation of the addColumn() function. Calling this function with an empty columns string is equivalent to not calling it at all.
If the columns string is non-empty, the input file must contain valid column information in the file header, as described in the header of this class.
Explicit column re-ordering
The columns string is interpreted as a comma-separated sequence of physical column names. Within each column name, consecutive white space characters are replaced by a single space, and white space at the start and at the end is removed. The following rules then apply:
As an exception to the above rules, the special column name "0" does not map to a column in the file but instead introduces a "virtual" logical column containing zero values. This avoids the need for including zero-value columns in the file.
Automatic column re-ordering
If the columns string is equal to "*" or "*0", automatic column re-ordering is activated. In this mode, the names provided in the file header for physical columns must match logical column names. The following rules apply:
|
private |
This function returns the logical index of the first logical column that is described as "wavelength" and that both logically and physically precedes the current column, or the error value if there is no such column.