Skip to content

Commit

Permalink
Implement flexible basis for SolutionArray::save CSV
Browse files Browse the repository at this point in the history
  • Loading branch information
ischoegl committed Jun 22, 2023
1 parent a13823b commit f832c7e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 24 deletions.
9 changes: 7 additions & 2 deletions include/cantera/base/SolutionArray.h
Expand Up @@ -215,8 +215,10 @@ class SolutionArray
*
* @param fname Name of CSV file
* @param overwrite Force overwrite if file exists; optional (default=false)
* @param basis Output mass ("Y"/"mass") or mole ("X"/"mole") fractions;
* if not specified (""), the native storage mode is used
*/
void writeEntry(const string& fname, bool overwrite=false);
void writeEntry(const string& fname, bool overwrite=false, const string& basis="");

/*!
* Write SolutionArray data to container file.
Expand Down Expand Up @@ -251,9 +253,12 @@ class SolutionArray
* @param overwrite Force overwrite if file and/or data entry exists; optional
* (default=false)
* @param compression Compression level; optional (default=0; HDF only)
* @param basis Output mass ("Y"/"mass") or mole ("X"/"mole") fractions (CSV
* only); if omitted (default=""), the native storage mode is used
*/
void save(const string& fname, const string& id="", const string& sub="",
const string& desc="", bool overwrite=false, int compression=0);
const string& desc="", bool overwrite=false, int compression=0,
const string& basis="");

/*!
* Read header data from container file.
Expand Down
19 changes: 12 additions & 7 deletions interfaces/cython/cantera/composite.py
Expand Up @@ -1233,29 +1233,34 @@ def from_pandas(self, df, normalize=True):
data_dict[label] = data_dict[label].astype('U')
self.restore_data(data_dict, normalize)

def save(self, fname, name=None, key=None, description=None,
overwrite=False, compression=0):
def save(self, fname, name=None, key=None, description=None, *,
overwrite=False, compression=0, basis=None):
"""
Save current `SolutionArray` and header to a container file.
Save current `SolutionArray` to a container or CSV file.
:param fname:
Name of output container file (YAML or HDF)
:param name:
Identifier of root location within the container file; the root location
contains header data and a subgroup holding the actual `SolutionArray`.
contains header data and a subgroup holding the actual `SolutionArray`
(HDF/YAML only).
:param key:
Name identifier for the subgroup holding the `SolutionArray` data and
metadata objects. If `None`, the subgroup name default to ``data``.
metadata objects. If `None`, the subgroup name default to ``data``
(HDF/YAML only).
:param description:
Custom comment describing the dataset to be stored.
Custom comment describing the dataset to be stored (HDF/YAML only).
:param overwrite:
Force overwrite if name exists; optional (default=`False`)
:param compression:
Compression level (0-9); optional (default=0; HDF only)
:param basis:
Output mass (``Y``/``mass``) or mole (``X``/``mole``) fractions (CSV only);
if not specified (`None`), the native storage mode is used
.. versionadded:: 3.0
"""
self._cxx_save(fname, name, key, description, overwrite, compression)
self._cxx_save(fname, name, key, description, overwrite, compression, basis)

def restore(self, fname, name=None, key=None):
"""
Expand Down
2 changes: 1 addition & 1 deletion interfaces/cython/cantera/solutionbase.pxd
Expand Up @@ -89,7 +89,7 @@ cdef extern from "cantera/base/SolutionArray.h" namespace "Cantera":
CxxAnyMap getAuxiliary(size_t) except +translate_exception
void setAuxiliary(size_t, CxxAnyMap&) except +translate_exception
void append(vector[double]&, CxxAnyMap&) except +translate_exception
void save(string&, string&, string&, string&, cbool, int) except +translate_exception
void save(string&, string&, string&, string&, cbool, int, string&) except +translate_exception
CxxAnyMap restore(string&, string&, string&) except +translate_exception

cdef shared_ptr[CxxSolutionArray] CxxNewSolutionArray "Cantera::SolutionArray::create" (
Expand Down
5 changes: 3 additions & 2 deletions interfaces/cython/cantera/solutionbase.pyx
Expand Up @@ -674,11 +674,12 @@ cdef class SolutionArrayBase:
cxx_state.push_back(item)
self.base.append(cxx_state, py_to_anymap(extra))

def _cxx_save(self, filename, name, key, description, overwrite, compression):
def _cxx_save(self, filename, name, key, description,
overwrite, compression, basis):
""" Interface `SolutionArray.save` with C++ core """
self.base.save(
stringify(str(filename)), stringify(name), stringify(key),
stringify(description), overwrite, compression)
stringify(description), overwrite, compression, stringify(basis))

def _cxx_restore(self, filename, name, key):
""" Interface `SolutionArray.restore` with C++ core """
Expand Down
39 changes: 27 additions & 12 deletions src/base/SolutionArray.cpp
Expand Up @@ -966,7 +966,7 @@ void SolutionArray::writeHeader(AnyMap& root, const string& id,
data.update(preamble(desc));
}

void SolutionArray::writeEntry(const string& fname, bool overwrite)
void SolutionArray::writeEntry(const string& fname, bool overwrite, const string& basis)
{
if (apiNdim() != 1) {
throw CanteraError("SolutionArray::writeEntry",
Expand All @@ -976,8 +976,18 @@ void SolutionArray::writeEntry(const string& fname, bool overwrite)
for (const auto& species : m_sol->thermo()->speciesNames()) {
speciesNames.insert(species);
}
const auto& nativeState = m_sol->thermo()->nativeState();
bool mole = nativeState.find("X") != nativeState.end();
bool mole;
if (basis == "") {
const auto& nativeState = m_sol->thermo()->nativeState();
mole = nativeState.find("X") != nativeState.end();
} else if (basis == "X" || basis == "mole") {
mole = true;
} else if (basis == "Y" || basis == "mass") {
mole = false;
} else {
throw CanteraError("SolutionArray::writeEntry",
"Invalid species basis '{}'.", basis);
}

auto names = componentNames();
size_t last = names.size() - 1;
Expand All @@ -1002,7 +1012,7 @@ void SolutionArray::writeEntry(const string& fname, bool overwrite)
key);
}
} else {
// Delay reading species data as basis can be either mole or mass
// Delay reading species data as base can be either mole or mass
isSpecies.push_back(true);
components.emplace_back(AnyValue());
col = components.size() - 1;
Expand Down Expand Up @@ -1265,14 +1275,26 @@ void SolutionArray::append(const vector<double>& state, const AnyMap& extra)
}

void SolutionArray::save(const string& fname, const string& id, const string& sub,
const string& desc, bool overwrite, int compression)
const string& desc, bool overwrite, int compression,
const string& basis)
{
if (m_size < m_dataSize) {
throw NotImplementedError("SolutionArray::save",
"Unable to save sliced data.");
}
size_t dot = fname.find_last_of(".");
string extension = (dot != npos) ? toLowerCopy(fname.substr(dot + 1)) : "";
if (extension == "csv") {
if (id != "") {
warn_user("SolutionArray::save", "Parameter 'id' not used for CSV output.");
}
writeEntry(fname, overwrite, basis);
return;
}
if (basis != "") {
warn_user("SolutionArray::save",
"Species basis '{}' not implemented for HDF5 or YAML output.", basis);
}
if (extension == "h5" || extension == "hdf" || extension == "hdf5") {
writeHeader(fname, id, desc, overwrite);
writeEntry(fname, id, sub, true, compression);
Expand All @@ -1293,13 +1315,6 @@ void SolutionArray::save(const string& fname, const string& id, const string& su
AnyMap::clearCachedFile(fname);
return;
}
if (extension == "csv") {
if (id != "") {
warn_user("SolutionArray::save", "Parameter 'id' not used for CSV output.");
}
writeEntry(fname, overwrite);
return;
}
throw CanteraError("SolutionArray::save",
"Unknown file extension '{}'.", extension);
}
Expand Down

0 comments on commit f832c7e

Please sign in to comment.