Skip to content

Commit

Permalink
[base] Implement import of SolutionArray from yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
ischoegl committed Sep 29, 2022
1 parent 6c6aee8 commit be7ef2f
Showing 1 changed file with 133 additions and 14 deletions.
147 changes: 133 additions & 14 deletions src/base/SolutionArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "cantera/base/Solution.h"
#include "cantera/base/stringUtils.h"
#include "cantera/thermo/ThermoPhase.h"
#include "cantera/thermo/SurfPhase.h"
#include <set>

#if CT_USE_HIGHFIVE_HDF
#include <highfive/H5File.hpp>
Expand Down Expand Up @@ -47,7 +49,7 @@ void SolutionArray::initialize(const std::vector<std::string>& extra)

m_offsets = m_sol->thermo()->nativeState();
m_stride = m_sol->thermo()->stateSize();
m_work.reset(new vector_fp(m_size * m_stride));
m_work.reset(new vector_fp(m_size * m_stride, 0.));
m_data = m_work->data();
m_managed = false;
for (auto& key : extra) {
Expand Down Expand Up @@ -171,31 +173,148 @@ void SolutionArray::restore(const h5::File& file, const std::string& id)

void SolutionArray::restore(const AnyMap& root, const std::string& id)
{
// locate SolutionArray based on 'id'
std::vector<std::string> tokens;
tokenizePath(id, tokens);
std::string field = tokens[0];
if (!root.hasKey(field) || !root[field].is<AnyMap>()) {
throw InputFileError("SolutionArray::restore", root,
"No field or solution with id '{}'", field);
}

const AnyMap* ptr = &root[field].as<AnyMap>(); // use raw pointer to avoid copying
std::string path = field;
tokens.erase(tokens.begin());
const AnyMap* ptr = &root; // use raw pointer to avoid copying
std::string path = "";
for (auto& field : tokens) {
path += "/" + field;
const AnyMap& sub = *ptr;
if (!sub.hasKey(field) || !sub[field].is<AnyMap>()) {
throw CanteraError("SolutionArray::restore",
"No field or solution with id '{}'", path);
"No field or solution with id '{}'", path);
}
ptr = &sub[field].as<AnyMap>(); // AnyMap lacks 'operator=' for const AnyMap
}

const AnyMap& sub = *ptr;
m_size = sub.getInt("points", 1);

// @todo: restore data
// set size and initialize
m_size = sub.getInt("points", 0);
if (!sub.hasKey("T") && !sub.hasKey("temperature")) {
// overwrite size - Sim1D erroneously assigns '1' (Cantera 2.6)
m_size = 0;
}
initialize({});

// restore data
std::set<std::string> exclude = {"points", "X", "Y"};
if (m_size == 0) {
// no data points
} else if (m_size == 1) {
// single data point
double T = sub["temperature"].asDouble();
double P = sub.getDouble("pressure", OneAtm); // missing - Sim1D (Cantera 2.6)
std::set<std::string> props = {"temperature", "pressure"};
exclude.insert(props.begin(), props.end());
if (sub.hasKey("mass-fractions")) {
auto Y = sub["mass-fractions"].asMap<double>();
m_sol->thermo()->setState_TPY(T, P, Y);
exclude.insert("mass-fractions");
} else if (sub.hasKey("coverages")) {
m_sol->thermo()->setState_TP(T, P);
auto cov = sub["coverages"].asMap<double>();
exclude.insert("coverages");
auto surf = std::dynamic_pointer_cast<SurfPhase>(m_sol->thermo());
if (!surf) {
throw CanteraError("SolutionArray::restore",
"Restoring of coverages requires surface phase");
}
surf->setCoveragesByName(cov);
} else {
throw NotImplementedError("SolutionArray::restore",
"Unknown YAML serialization format.");
}
for (const auto& prop : m_sol->thermo()->nativeState()) {
if (prop.first == "T") {
m_data[prop.second] = m_sol->thermo()->temperature();
} else if (prop.first == "D") {
m_data[prop.second] = m_sol->thermo()->density();
} else if (prop.first == "P") {
m_data[prop.second] = m_sol->thermo()->pressure();
} else if (prop.first == "Y") {
m_sol->thermo()->getMassFractions(&m_data[prop.second]);
} else if (prop.first == "X") {
m_sol->thermo()->getMoleFractions(&m_data[prop.second]);
} else {
throw NotImplementedError("SolutionArray::restore",
"Unable to restore property '{}'.", prop.first);
}
}
} else {
// multiple data points
const auto& nativeState = m_sol->thermo()->nativeState();
for (const auto& item : sub) {
const std::string& name = item.first;
const AnyValue& value = item.second;
size_t offset = npos;
if (value.is<std::vector<double>>()) {
const vector_fp& data = value.as<std::vector<double>>();
size_t species = m_sol->thermo()->speciesIndex(name);
if (data.size() != m_size) {
// meta data
continue;
} else if (species != npos) {
// species
if (nativeState.count("X")) {
offset = nativeState.find("X")->second + species;
} else if (nativeState.count("Y")) {
offset = nativeState.find("Y")->second + species;
}
} else if (nativeState.count(name)) {
// property
offset = nativeState.find(name)->second;
} else {
// extra
m_other.emplace(name, std::make_shared<vector_fp>(m_size));
auto& extra = m_other[name];
std::copy(data.begin(), data.end(), extra->begin());
}

if (offset != npos) {
for (size_t i = 0; i < m_size; i++) {
m_data[offset + i * m_stride] = data[i];
}
}
exclude.insert(item.first);
}
}

// check that state data are complete
std::set<std::string> props = {};
std::set<std::string> missingProps = {};
for (const auto& item : nativeState) {
if (exclude.count(item.first)) {
props.insert(item.first);
} else {
missingProps.insert(item.first);
}
}

std::set<std::string> TY = {"T", "Y"};
if (props == TY && missingProps.count("D") && sub.hasKey("pressure")) {
// missing "D" - Sim1D (Cantera 2.6)
double P = sub["pressure"].asDouble();
const size_t offset_T = nativeState.find("T")->second;
const size_t offset_D = nativeState.find("D")->second;
const size_t offset_Y = nativeState.find("Y")->second;
for (size_t i = 0; i < m_size; i++) {
double T = m_data[offset_T + i * m_stride];
m_sol->thermo()->setState_TPY(T, P, &m_data[offset_Y + i * m_stride]);
m_data[offset_D + i * m_stride] = m_sol->thermo()->density();
}
} else if (missingProps.size()) {
throw CanteraError("SolutionArray::restore",
"Incomplete state information.");
}
}

// add meta data
for (const auto& item : sub) {
if (!exclude.count(item.first)) {
m_meta[item.first] = item.second;
}
}
}

}

0 comments on commit be7ef2f

Please sign in to comment.