16#include <boost/algorithm/string.hpp>
17#include <boost/range/adaptor/reversed.hpp>
22namespace ba = boost::algorithm;
29const map<string, string> aliasMap = {
33 {
"Y",
"mass-fractions"},
34 {
"X",
"mole-fractions"},
36 {
"U",
"specific-internal-energy"},
37 {
"V",
"specific-volume"},
38 {
"H",
"specific-enthalpy"},
39 {
"S",
"specific-entropy"},
40 {
"Q",
"vapor-fraction"},
43const map<string, string> reverseAliasMap = {
49 {
"spread-rate",
"spreadRate"},
50 {
"spread_rate",
"spreadRate"},
52 {
"radial-pressure-gradient",
"Lambda"},
55 {
"electric-field",
"eField"},
56 {
"oxidizer-velocity",
"Uo"},
63 return reverseAliasMap;
66SolutionArray::SolutionArray(
const shared_ptr<Solution>& sol,
67 int size,
const AnyMap& meta)
73 if (!m_sol || !m_sol->thermo()) {
74 throw CanteraError(
"SolutionArray::SolutionArray",
75 "Unable to create SolutionArray from invalid Solution object.");
77 m_stride = m_sol->thermo()->stateSize();
78 m_sol->thermo()->addSpeciesLock();
79 m_data = make_shared<vector<double>>(m_dataSize * m_stride, 0.);
80 m_extra = make_shared<map<string, AnyValue>>();
81 m_order = make_shared<map<int, string>>();
82 for (
size_t i = 0; i < m_dataSize; ++i) {
83 m_active.push_back(
static_cast<int>(i));
87 m_apiShape[0] =
static_cast<long>(m_dataSize);
90SolutionArray::SolutionArray(
const SolutionArray& other,
91 const vector<int>& selected)
93 , m_size(selected.size())
94 , m_dataSize(other.m_data->size())
95 , m_stride(other.m_stride)
96 , m_data(other.m_data)
97 , m_extra(other.m_extra)
98 , m_order(other.m_order)
101 m_sol->thermo()->addSpeciesLock();
102 if (!other.m_shared) {
108 m_active.reserve(selected.size());
109 for (auto loc : selected) {
110 m_active.push_back(other.m_active.at(loc));
113 for (
auto loc : m_active) {
114 if (loc < 0 || loc >= (
int)m_dataSize) {
115 IndexError(
"SolutionArray::SolutionArray",
"indices", loc, m_dataSize);
118 set<int> unique(selected.begin(), selected.end());
119 if (unique.size() < selected.size()) {
120 throw CanteraError(
"SolutionArray::SolutionArray",
"Indices must be unique.");
124SolutionArray::~SolutionArray()
126 m_sol->thermo()->removeSpeciesLock();
132void resetSingle(AnyValue& extra,
const vector<int>& slice);
135AnyValue getSingle(
const AnyValue& extra,
const vector<int>& slice);
138void setSingle(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice);
141void resizeSingle(AnyValue& extra,
size_t size,
const AnyValue& value);
144void resetMulti(AnyValue& extra,
const vector<int>& slice);
147AnyValue getMulti(
const AnyValue& extra,
const vector<int>& slice);
150void setMulti(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice);
153void resizeMulti(AnyValue& extra,
size_t size,
const AnyValue& value);
156void setAuxiliarySingle(
size_t loc, AnyValue& extra,
const AnyValue& value);
159void setAuxiliaryMulti(
size_t loc, AnyValue& extra,
const AnyValue& data);
162void setScalar(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice);
168 size_t nState =
m_sol->thermo()->stateSize();
169 vector<double> state(nState);
170 m_sol->thermo()->saveState(state);
171 for (
size_t k = 0; k <
m_size; ++k) {
174 for (
auto& [key, extra] : *
m_extra) {
175 if (extra.is<
void>()) {
177 }
else if (extra.isVector<
double>()) {
178 resetSingle<double>(extra,
m_active);
179 }
else if (extra.isVector<
long int>()) {
180 resetSingle<long int>(extra,
m_active);
181 }
else if (extra.isVector<
string>()) {
182 resetSingle<string>(extra,
m_active);
183 }
else if (extra.isVector<vector<double>>()) {
184 resetMulti<double>(extra,
m_active);
185 }
else if (extra.isVector<vector<long int>>()) {
186 resetMulti<long int>(extra,
m_active);
187 }
else if (extra.isVector<vector<string>>()) {
188 resetMulti<string>(extra,
m_active);
191 "Unable to reset component '{}' with type '{}'.",
192 key, extra.type_str());
201 "Resize is ambiguous for multi-dimensional arrays; use setApiShape "
204 if (
m_data.use_count() > 1) {
206 "Unable to resize as data are shared by multiple objects.");
215 for (
auto dim : shape) {
220 "Unable to set shape of shared data as sizes are inconsistent:\n"
221 "active size is {} but shape implies {}.",
m_size,
size);
224 if (
m_data.use_count() > 1) {
226 "Unable to set shape as data are shared by multiple objects.");
238 for (
auto& [key, data] : *
m_extra) {
243 m_active.push_back(
static_cast<int>(i));
249vector<string> doubleColumn(
string name,
const vector<double>& comp,
255 string notation = fmt::format(
"{{:{}.{}g}}", width, (width - 1) / 2);
256 int csize =
static_cast<int>(comp.size());
257 int dots = csize + 1;
259 for (
const auto& val : comp) {
261 raw.push_back(boost::trim_copy(fmt::format(fmt::runtime(notation), val)));
264 dots = (rows + 1) / 2;
265 for (
int row = 0; row < dots; row++) {
266 data.push_back(comp[row]);
267 raw.push_back(boost::trim_copy(
268 fmt::format(fmt::runtime(notation), comp[row])));
270 for (
int row = csize - rows / 2; row < csize; row++) {
271 data.push_back(comp[row]);
272 raw.push_back(boost::trim_copy(
273 fmt::format(fmt::runtime(notation), comp[row])));
278 bool isFloat =
false;
279 bool isScientific =
false;
283 for (
const auto& repr : raw) {
285 if (name[0] ==
'-') {
287 name = name.substr(1);
289 if (name.find(
'e') != string::npos) {
293 tail = name.find(
'e') - name.find(
'.');
296 tail = std::max(tail, name.find(
'e') - name.find(
'.'));
300 }
else if (name.find(
'.') != string::npos) {
304 head = std::max(head, name.find(
'.'));
305 tail = std::max(tail, name.size() - name.find(
'.'));
308 head = std::max(head, name.size());
311 size_t maxLen = std::max((
size_t)4, head + tail + exp + isFloat + 1);
312 size_t over = std::max(0, (
int)name.size() - (
int)maxLen);
315 notation = fmt::format(
" {{:>{}.{}e}}", over + maxLen, tail);
316 }
else if (isFloat) {
318 notation = fmt::format(
" {{:>{}.{}f}}", over + maxLen, tail);
321 notation = fmt::format(
" {{:>{}.0f}}", over + maxLen);
323 maxLen = fmt::format(fmt::runtime(notation), 0.).size();
326 string section = fmt::format(
"{{:>{}}}", maxLen);
327 vector<string> col = {fmt::format(fmt::runtime(section), name)};
329 for (
const auto& val : data) {
330 col.push_back(fmt::format(fmt::runtime(notation), val));
333 col.push_back(fmt::format(fmt::runtime(section),
"..."));
339vector<string> integerColumn(
string name,
const vector<long int>& comp,
343 vector<long int> data;
344 string notation = fmt::format(
"{{:{}}}", width);
346 int csize =
static_cast<int>(comp.size());
347 int dots = csize + 1;
349 for (
const auto& val : comp) {
351 string formatted = boost::trim_copy(
352 fmt::format(fmt::runtime(notation), val));
353 if (formatted[0] ==
'-') {
354 formatted = formatted.substr(1);
356 maxLen = std::max(maxLen, formatted.size());
359 dots = (rows + 1) / 2;
360 for (
int row = 0; row < dots; row++) {
361 data.push_back(comp[row]);
362 string formatted = boost::trim_copy(
363 fmt::format(fmt::runtime(notation), comp[row]));
364 if (formatted[0] ==
'-') {
365 formatted = formatted.substr(1);
367 maxLen = std::max(maxLen, formatted.size());
369 for (
int row = csize - rows / 2; row < csize; row++) {
370 data.push_back(comp[row]);
371 string formatted = boost::trim_copy(
372 fmt::format(fmt::runtime(notation), comp[row]));
373 if (formatted[0] ==
'-') {
374 formatted = formatted.substr(1);
376 maxLen = std::max(maxLen, formatted.size());
382 notation = fmt::format(
"{{:<{}}}", maxLen);
385 maxLen = std::max(maxLen, name.size());
386 notation = fmt::format(
" {{:>{}}}", maxLen + 1);
390 vector<string> col = {fmt::format(fmt::runtime(notation), name)};
392 for (
const auto& val : data) {
393 col.push_back(fmt::format(fmt::runtime(notation), val));
396 col.push_back(fmt::format(fmt::runtime(notation),
".."));
402vector<string> stringColumn(
string name,
const vector<string>& comp,
407 string notation = fmt::format(
"{{:{}}}", width);
409 int csize =
static_cast<int>(comp.size());
410 int dots = csize + 1;
412 for (
const auto& val : comp) {
414 maxLen = std::max(maxLen,
415 boost::trim_copy(fmt::format(fmt::runtime(notation), val)).size());
418 dots = (rows + 1) / 2;
419 for (
int row = 0; row < dots; row++) {
420 data.push_back(comp[row]);
421 maxLen = std::max(maxLen,
423 fmt::format(fmt::runtime(notation), comp[row])).size());
425 for (
int row = csize - rows / 2; row < csize; row++) {
426 data.push_back(comp[row]);
427 maxLen = std::max(maxLen,
429 fmt::format(fmt::runtime(notation), comp[row])).size());
434 notation = fmt::format(
" {{:>{}}}", maxLen);
435 vector<string> col = {fmt::format(fmt::runtime(notation), name)};
437 for (
const auto& val : data) {
438 col.push_back(fmt::format(fmt::runtime(notation), val));
441 col.push_back(fmt::format(fmt::runtime(notation),
"..."));
447vector<string> formatColumn(
string name,
const AnyValue& comp,
int rows,
int width)
449 if (comp.isVector<
double>()) {
450 return doubleColumn(name, comp.asVector<
double>(), rows, width);
452 if (comp.isVector<
long int>()) {
453 return integerColumn(name, comp.asVector<
long int>(), rows, width);
455 if (comp.isVector<
string>()) {
456 return stringColumn(name, comp.asVector<
string>(), rows, width);
462 if (comp.isVector<vector<double>>()) {
463 repr =
"[ <double> ]";
464 size =
len(comp.asVector<vector<double>>());
465 }
else if (comp.isVector<vector<long int>>()) {
466 repr =
"[ <long int> ]";
467 size =
len(comp.asVector<vector<long int>>());
468 }
else if (comp.isVector<vector<string>>()) {
469 repr =
"[ <string> ]";
470 size =
len(comp.asVector<vector<string>>());
473 "formatColumn",
"Encountered invalid data for component '{}'.", name);
475 size_t maxLen = std::max(repr.size(), name.size());
478 string notation = fmt::format(
" {{:>{}}}", maxLen);
479 repr = fmt::format(fmt::runtime(notation), repr);
480 vector<string> col = {fmt::format(fmt::runtime(notation), name)};
482 for (
int row = 0; row < size; row++) {
486 int dots = (rows + 1) / 2;
487 for (
int row = 0; row < dots; row++) {
490 col.push_back(fmt::format(fmt::runtime(notation),
"..."));
491 for (
int row = size - rows / 2; row < size; row++) {
502 fmt::memory_buffer b;
504 vector<string> components;
512 vector<long int> index;
516 vector<vector<string>> cols = {integerColumn(
"", index, rows, col_width)};
517 vector<vector<string>> tail;
518 size_t size = cols.back().size();
524 int back =
len(components) - 1;
525 int fLen =
len(cols.back()[0]);
529 while (!done && front <= back) {
531 while (bLen + sep <= fLen && front <= back) {
533 key = components[back];
534 auto col = formatColumn(key,
getComponent(key), rows, col_width);
535 if (
len(col[0]) + fLen + bLen + sep > width) {
540 bLen +=
len(tail.back()[0]);
543 if (done || front > back) {
546 while (fLen <= bLen + sep && front <= back) {
548 key = components[front];
549 auto col = formatColumn(key,
getComponent(key), rows, col_width);
550 if (
len(col[0]) + fLen + bLen + sep > width) {
555 fLen +=
len(cols.back()[0]);
559 if (cols.size() + tail.size() < components.size() + 1) {
561 cols.push_back(vector<string>(
size + 1,
" ..."));
564 cols.insert(cols.end(), tail.rbegin(), tail.rend());
567 for (
size_t row = 0; row <
size; row++) {
568 for (
const auto& col : cols) {
569 fmt_append(b, col[row]);
575 fmt_append(b,
"\n[{} rows x {} components; state='{}']",
576 m_size, components.size(),
m_sol->thermo()->nativeMode());
579 return to_string(b) + err.
what();
586 return m_sol->thermo();
591 return m_sol->transportModel();
596 vector<string> components;
600 components.push_back(
m_order->at(pos));
606 for (
auto code :
phase->nativeMode()) {
607 string name = string(1, code);
608 if (name ==
"X" || name ==
"Y") {
609 for (
auto& spc :
phase->speciesNames()) {
610 components.push_back(spc);
613 components.push_back(name);
620 components.push_back(
m_order->at(pos));
631 "Component '{}' already exists.", name);
655 vector<string> names;
658 const auto& name =
m_order->at(pos);
659 if (all || !
m_extra->at(name).is<
void>()) {
660 names.push_back(name);
668 const auto& name =
m_order->at(pos);
669 if (all || !
m_extra->at(name).is<
void>()) {
670 names.push_back(name);
683 if (
m_sol->thermo()->speciesIndex(name,
false) !=
npos) {
687 if (name ==
"X" || name ==
"Y") {
691 if (checkAlias && reverseAliasMap.count(name)) {
696 return (
m_sol->thermo()->nativeState().count(name));
702 if (!
hasComponent(name,
false) && reverseAliasMap.count(name)) {
703 _name = reverseAliasMap.at(name);
706 "Unknown component '{}'.", name);
712 const auto& extra =
m_extra->at(_name);
713 if (extra.is<
void>()) {
719 if (extra.isVector<
long int>()) {
720 return getSingle<long int>(extra,
m_active);
722 if (extra.isVector<
double>()) {
723 return getSingle<double>(extra,
m_active);
725 if (extra.isVector<
string>()) {
726 return getSingle<string>(extra,
m_active);
728 if (extra.isVector<vector<double>>()) {
729 return getMulti<double>(extra,
m_active);
731 if (extra.isVector<vector<long int>>()) {
732 return getMulti<long int>(extra,
m_active);
734 if (extra.isVector<vector<string>>()) {
735 return getMulti<string>(extra,
m_active);
738 "Unable to get sliced data for component '{}' with type '{}'.",
739 name, extra.type_str());
743 vector<double> data(
m_size);
744 size_t ix =
m_sol->thermo()->speciesIndex(_name,
false);
747 ix =
m_sol->thermo()->nativeState()[_name];
752 for (
size_t k = 0; k <
m_size; ++k) {
759bool isSimpleVector(
const AnyValue& any) {
770 "Unknown component '{}'.", name);
780 "Invalid type of component '{}': expected simple array type, "
781 "but received '{}'.", name, data.
type_str());
785 "Invalid size of component '{}': expected size {} but received {}.",
789 auto& vec = data.
asVector<
double>();
790 size_t ix =
m_sol->thermo()->speciesIndex(name,
false);
792 ix =
m_sol->thermo()->nativeState()[name];
796 for (
size_t k = 0; k <
m_size; ++k) {
803 size_t loc_ =
static_cast<size_t>(loc);
806 "Unable to set location in empty SolutionArray.");
807 }
else if (loc < 0) {
810 "Both current and buffered indices are invalid.");
815 }
else if (loc_ >=
m_size) {
820 size_t nState =
m_sol->thermo()->stateSize();
828 size_t nState =
m_sol->thermo()->stateSize();
835 size_t nState =
m_sol->thermo()->stateSize();
836 vector<double> out(nState);
837 m_sol->thermo()->saveState(out);
843 size_t nState =
m_sol->thermo()->stateSize();
844 if (state.size() != nState) {
846 "Expected array to have length {}, but received an array of length {}.",
847 nState, state.size());
850 m_sol->thermo()->restoreState(state);
856 auto nativeState =
phase->nativeState();
857 if (nativeState.size() < 3) {
860 size_t nState =
phase->stateSize();
861 vector<double> out(nState);
862 if (nativeState.count(
"Y")) {
863 size_t offset = nativeState[
"Y"];
864 for (
int loc = 0; loc < static_cast<int>(
m_size); loc++) {
867 m_sol->thermo()->saveState(out);
870 }
else if (nativeState.count(
"X")) {
871 size_t offset = nativeState[
"X"];
872 for (
int loc = 0; loc < static_cast<int>(
m_size); loc++) {
875 m_sol->thermo()->saveState(out);
880 "Not implemented for mode '{}'.",
phase->nativeMode());
888 for (
const auto& [key, extra] : *
m_extra) {
889 if (extra.is<
void>()) {
891 }
else if (extra.isVector<
long int>()) {
892 out[key] = extra.asVector<
long int>()[
m_loc];
893 }
else if (extra.isVector<
double>()) {
894 out[key] = extra.asVector<
double>()[
m_loc];
895 }
else if (extra.isVector<
string>()) {
896 out[key] = extra.asVector<
string>()[
m_loc];
897 }
else if (extra.isVector<vector<long int>>()) {
898 out[key] = extra.asVector<vector<long int>>()[
m_loc];
899 }
else if (extra.isVector<vector<double>>()) {
900 out[key] = extra.asVector<vector<double>>()[
m_loc];
901 }
else if (extra.isVector<vector<string>>()) {
902 out[key] = extra.asVector<vector<string>>()[
m_loc];
905 "Unable to retrieve data for component '{}' with type '{}'.",
906 key, extra.type_str());
915 for (
const auto& [name, value] : data) {
918 "Unknown auxiliary component '{}'.", name);
920 auto& extra =
m_extra->at(name);
921 if (extra.is<
void>()) {
924 "Unable to set location for type '{}': "
925 "component is not initialized.", name);
931 if (extra.isVector<
long int>()) {
932 setAuxiliarySingle<long int>(
m_loc, extra, value);
933 }
else if (extra.isVector<
double>()) {
934 setAuxiliarySingle<double>(
m_loc, extra, value);
935 }
else if (extra.isVector<
string>()) {
936 setAuxiliarySingle<string>(
m_loc, extra, value);
937 }
else if (extra.isVector<vector<long int>>()) {
938 setAuxiliaryMulti<long int>(
m_loc, extra, value);
939 }
else if (extra.isVector<vector<double>>()) {
940 setAuxiliaryMulti<double>(
m_loc, extra, value);
941 }
else if (extra.isVector<vector<string>>()) {
942 setAuxiliaryMulti<string>(
m_loc, extra, value);
945 "Unable to set entry for type '{}'.", extra.type_str());
950 "Encountered incompatible value for component '{}':\n{}",
956AnyMap preamble(
const string& desc)
960 data[
"description"] = desc;
962 data[
"generator"] =
"Cantera SolutionArray";
963 data[
"cantera-version"] = CANTERA_VERSION;
964 data[
"git-commit"] = gitCommit();
969 struct tm* newtime = localtime(&aclock);
970 data[
"date"] = stripnonprint(asctime(newtime));
975AnyMap& openField(AnyMap& root,
const string& name)
982 vector<string> tokens;
986 for (
auto& field : tokens) {
989 if (sub.hasKey(field) && !sub[field].is<AnyMap>()) {
990 throw CanteraError(
"openField",
991 "Encountered invalid existing field '{}'.", path);
992 }
else if (!sub.hasKey(field)) {
993 sub[field] = AnyMap();
995 ptr = &sub[field].as<AnyMap>();
1001 const string& desc,
bool overwrite)
1007 "Group name '{}' exists; use 'overwrite' argument to overwrite.", name);
1016 const string& desc,
bool overwrite)
1018 AnyMap& data = openField(root, name);
1019 if (!data.
empty()) {
1022 "Field name '{}' exists; use 'overwrite' argument to overwrite.", name);
1026 data.
update(preamble(desc));
1033 "Tabular output of CSV data only works for 1D SolutionArray objects.");
1035 set<string> speciesNames;
1036 for (
const auto& species :
m_sol->thermo()->speciesNames()) {
1037 speciesNames.insert(species);
1041 const auto& nativeState =
m_sol->thermo()->nativeState();
1042 mole = nativeState.find(
"X") != nativeState.end();
1043 }
else if (basis ==
"X" || basis ==
"mole") {
1045 }
else if (basis ==
"Y" || basis ==
"mass") {
1049 "Invalid species basis '{}'.", basis);
1053 size_t last = names.size() - 1;
1054 vector<AnyValue> components;
1055 vector<bool> isSpecies;
1056 fmt::memory_buffer header;
1057 for (
const auto& key : names) {
1060 if (speciesNames.find(key) == speciesNames.end()) {
1062 isSpecies.push_back(
false);
1064 col = components.size() - 1;
1065 if (!components[col].isVector<double>() &&
1066 !components[col].isVector<long int>() &&
1067 !components[col].isVector<string>())
1070 "Multi-dimensional column '{}' is not supported for CSV output.",
1075 isSpecies.push_back(
true);
1076 components.emplace_back(
AnyValue());
1077 col = components.size() - 1;
1079 label =
"X_" + label;
1081 label =
"Y_" + label;
1084 if (label.find(
"\"") != string::npos || label.find(
"\n") != string::npos) {
1086 "Detected column name containing double quotes or line feeds: '{}'.",
1089 string sep = (col == last) ?
"" :
",";
1090 if (label.find(
",") != string::npos) {
1091 fmt_append(header,
"\"{}\"{}", label, sep);
1093 fmt_append(header,
"{}{}", label, sep);
1098 if (std::ifstream(fname).good()) {
1101 "File '{}' already exists; use option 'overwrite' to replace CSV file.",
1104 std::remove(fname.c_str());
1106 std::ofstream output(fname);
1107 output << to_string(header) << std::endl;
1109 size_t maxLen =
npos;
1110 vector<double> buf(speciesNames.size(), 0.);
1111 for (
int row = 0; row < static_cast<int>(
m_size); row++) {
1112 fmt::memory_buffer line;
1113 if (maxLen !=
npos) {
1114 line.reserve(maxLen);
1118 m_sol->thermo()->getMoleFractions(buf.data());
1120 m_sol->thermo()->getMassFractions(buf.data());
1124 for (
size_t col = 0; col < components.size(); col++) {
1125 string sep = (col == last) ?
"" :
",";
1126 if (isSpecies[col]) {
1127 fmt_append(line,
"{:.9g}{}", buf[idx++], sep);
1129 auto& data = components[col];
1130 if (data.isVector<
double>()) {
1131 fmt_append(line,
"{:.9g}{}", data.asVector<
double>()[row], sep);
1132 }
else if (data.isVector<
long int>()) {
1133 fmt_append(line,
"{}{}", data.asVector<
long int>()[row], sep);
1134 }
else if (data.isVector<
bool>()) {
1135 fmt_append(line,
"{}{}",
1136 static_cast<bool>(data.asVector<
bool>()[row]), sep);
1138 auto value = data.asVector<
string>()[row];
1139 if (value.find(
"\"") != string::npos ||
1140 value.find(
"\n") != string::npos)
1143 "Detected value containing double quotes or line feeds: "
1146 if (value.find(
",") != string::npos) {
1147 fmt_append(line,
"\"{}\"{}", value, sep);
1149 fmt_append(line,
"{}{}", value, sep);
1154 output << to_string(line) << std::endl;
1155 maxLen = std::max(maxLen, line.size());
1160 const string& sub,
bool overwrite,
int compression)
1164 "Group name specifying root location must not be empty.");
1168 "Unable to save sliced data.");
1183 "Group name '{}' exists; use 'overwrite' argument to overwrite.", name);
1195 if (!
m_meta.hasKey(
"transport-model") &&
m_sol->transport()) {
1196 more[
"transport-model"] =
m_sol->transportModel();
1204 const auto& nativeState =
m_sol->thermo()->nativeState();
1205 size_t nSpecies =
m_sol->thermo()->nSpecies();
1206 for (
auto& [key,
offset] : nativeState) {
1207 if (key ==
"X" || key ==
"Y") {
1208 vector<vector<double>> prop;
1209 for (
size_t i = 0; i <
m_size; i++) {
1211 prop.emplace_back(
m_data->begin() + first,
1212 m_data->begin() + first + nSpecies);
1223 for (
const auto& [key, value] : *
m_extra) {
1224 if (isSimpleVector(value)) {
1226 }
else if (value.is<
void>()) {
1230 "Unable to save component '{}' with data type {}.",
1231 key, value.type_str());
1241 "Field name specifying root location must not be empty.");
1245 "Unable to save sliced data.");
1253 AnyMap& data = openField(root, path);
1254 bool preexisting = !data.
empty();
1255 if (preexisting && !overwrite) {
1257 "Field name '{}' exists; use 'overwrite' argument to overwrite.", name);
1264 if (
m_sol->transport() &&
m_sol->transportModel() !=
"none") {
1265 data[
"transport-model"] =
m_sol->transportModel();
1273 for (
auto& [_, key] : *
m_order) {
1280 data[
"temperature"] =
phase->temperature();
1281 data[
"pressure"] =
phase->pressure();
1282 auto surf = std::dynamic_pointer_cast<SurfPhase>(
phase);
1283 auto nSpecies =
phase->nSpecies();
1284 vector<double> values(nSpecies);
1286 surf->getCoverages(&values[0]);
1288 phase->getMassFractions(&values[0]);
1291 for (
size_t k = 0; k < nSpecies; k++) {
1292 if (values[k] != 0.0) {
1293 items[
phase->speciesName(k)] = values[k];
1297 data[
"coverages"] = std::move(items);
1299 data[
"mass-fractions"] = std::move(items);
1302 for (
auto& code :
phase->nativeMode()) {
1303 string name(1, code);
1304 if (name ==
"X" || name ==
"Y") {
1305 for (
auto& spc :
phase->speciesNames()) {
1308 data[
"basis"] = name ==
"X" ?
"mole" :
"mass";
1316 {{
"head",
"type"}, {
"head",
"size"}, {
"head",
"basis"}});
1318 data[
"__type__"] =
"SolutionArray";
1331 "Unable to append multi-dimensional arrays.");
1347 const string& desc,
bool overwrite,
int compression,
1348 const string& basis)
1352 "Unable to save sliced data.");
1354 size_t dot = fname.find_last_of(
".");
1356 if (extension ==
"csv") {
1359 "Parameter 'name' not used for CSV output.");
1366 "Argument 'basis' is not used for HDF or YAML output.", basis);
1368 if (extension ==
"h5" || extension ==
"hdf" || extension ==
"hdf5") {
1370 writeEntry(fname, name, sub,
true, compression);
1373 if (extension ==
"yaml" || extension ==
"yml") {
1376 std::ifstream file(fname);
1377 if (file.good() && file.peek() != std::ifstream::traits_type::eof()) {
1384 std::ofstream out(fname);
1385 out << data.toYamlString();
1390 "Unknown file extension '{}'.", extension);
1400const AnyMap& locateField(
const AnyMap& root,
const string& name)
1407 vector<string> tokens;
1408 tokenizePath(name, tokens);
1409 const AnyMap* ptr = &root;
1411 for (
auto& field : tokens) {
1412 path +=
"/" + field;
1413 const AnyMap& sub = *ptr;
1414 if (!sub.hasKey(field) || !sub[field].is<AnyMap>()) {
1415 throw CanteraError(
"SolutionArray::locateField",
1416 "No field or solution with name '{}'.", path);
1418 ptr = &sub[field].as<AnyMap>();
1425 auto sub = locateField(root, name);
1427 for (
const auto& [key, value] : sub) {
1428 if (!sub[key].is<AnyMap>()) {
1429 header[key] = value;
1436 const string& name,
const string& sub)
1438 size_t dot = fname.find_last_of(
".");
1441 if (extension ==
"csv") {
1443 "CSV import not implemented; if using Python, data can be imported via "
1444 "'read_csv' instead.");
1446 if (extension ==
"h5" || extension ==
"hdf" || extension ==
"hdf5") {
1449 }
else if (extension ==
"yaml" || extension ==
"yml") {
1455 "Unknown file extension '{}'; supported extensions include "
1456 "'h5'/'hdf'/'hdf5' and 'yml'/'yaml'.", extension);
1465 "Component '{}' does not exist.", name);
1467 auto& extra = (*m_extra)[name];
1468 if (!extra.is<
void>()) {
1470 "Component '{}' is already initialized.", name);
1473 if (value.
is<
long int>()) {
1474 extra = vector<long int>(
m_dataSize, value.
as<
long int>());
1475 }
else if (value.
is<
double>()) {
1476 extra = vector<double>(
m_dataSize, value.
as<
double>());
1477 }
else if (value.
is<
string>()) {
1478 extra = vector<string>(
m_dataSize, value.
as<
string>());
1479 }
else if (value.
isVector<
long int>()) {
1481 }
else if (value.
isVector<
double>()) {
1483 }
else if (value.
isVector<
string>()) {
1485 }
else if (value.
is<
void>()) {
1490 "Unable to initialize component '{}' with type '{}'.",
1496 "Encountered incompatible value for initializing component '{}':\n{}",
1505 "Component '{}' does not exist.", name);
1507 auto& extra = (*m_extra)[name];
1508 if (extra.is<
void>()) {
1514 if (extra.isVector<
long int>()) {
1515 resizeSingle<long int>(extra,
m_dataSize, value);
1516 }
else if (extra.isVector<
double>()) {
1517 resizeSingle<double>(extra,
m_dataSize, value);
1518 }
else if (extra.isVector<
string>()) {
1519 resizeSingle<string>(extra,
m_dataSize, value);
1520 }
else if (extra.isVector<vector<double>>()) {
1521 resizeMulti<double>(extra,
m_dataSize, value);
1522 }
else if (extra.isVector<vector<long int>>()) {
1523 resizeMulti<long int>(extra,
m_dataSize, value);
1524 }
else if (extra.isVector<vector<string>>()) {
1525 resizeMulti<string>(extra,
m_dataSize, value);
1528 "Unable to resize using type '{}'.", extra.type_str());
1533 "Encountered incompatible value for resizing component '{}':\n{}",
1542 "Extra component '{}' does not exist.", name);
1545 auto& extra =
m_extra->at(name);
1553 if (extra.is<
void>()) {
1556 "Unable to replace '{}' for sliced data.", name);
1566 "Unable to initialize '{}' with non-empty values when SolutionArray is "
1571 "Unable to initialize '{}' with empty array when SolutionArray is not "
1579 if (data.
is<
long int>()) {
1580 setScalar<long int>(extra, data,
m_active);
1581 }
else if (data.
is<
double>()) {
1582 setScalar<double>(extra, data,
m_active);
1583 }
else if (data.
is<
string>()) {
1584 setScalar<string>(extra, data,
m_active);
1585 }
else if (data.
isVector<
long int>()) {
1586 setSingle<long int>(extra, data,
m_active);
1587 }
else if (data.
isVector<
double>()) {
1588 setSingle<double>(extra, data,
m_active);
1589 }
else if (data.
isVector<
string>()) {
1590 setSingle<string>(extra, data,
m_active);
1591 }
else if (data.
isVector<vector<long int>>()) {
1592 setMulti<long int>(extra, data,
m_active);
1593 }
else if (data.
isVector<vector<double>>()) {
1594 setMulti<double>(extra, data,
m_active);
1595 }
else if (data.
isVector<vector<string>>()) {
1596 setMulti<string>(extra, data,
m_active);
1599 "Unable to set sliced data for component '{}' with type '{}'.",
1608 const auto& nativeState =
m_sol->thermo()->nativeState();
1609 bool usesNativeState =
false;
1610 auto surf = std::dynamic_pointer_cast<SurfPhase>(
m_sol->thermo());
1612 for (
const auto& item :
m_sol->thermo()->fullStates()) {
1615 usesNativeState =
true;
1616 for (
size_t i = 0; i < item.size(); i++) {
1618 name = string(1, item[i]);
1619 if (surf && (name ==
"X" || name ==
"Y")) {
1622 usesNativeState =
false;
1625 if (names.count(name)) {
1627 usesNativeState &= nativeState.count(name) > 0;
1628 }
else if (aliasMap.count(name) && names.count(aliasMap.at(name))) {
1630 usesNativeState &= nativeState.count(name) > 0;
1637 mode = (name ==
"C") ? item.substr(0, 2) +
"C" : item;
1642 if (surf && names.count(
"T") && names.count(
"X") && names.count(
"density")) {
1644 return "legacySurf";
1646 if (names.count(
"mass-flux") && names.count(
"mass-fractions")) {
1648 return "legacyInlet";
1651 "Detected incomplete thermodynamic information. Full states for a '{}' "
1652 "phase\nmay be defined by the following modes:\n'{}'\n"
1653 "Available data are: '{}'",
m_sol->thermo()->type(),
1654 ba::join(
m_sol->thermo()->fullStates(),
"', '"), ba::join(names,
"', '"));
1656 if (usesNativeState && native) {
1663 const string& mode,
bool alias)
1666 if (mode ==
"native") {
1667 for (
const auto& [name,
offset] :
m_sol->thermo()->nativeState()) {
1668 states.insert(alias ? aliasMap.at(name) : name);
1671 for (
const auto& m : mode) {
1672 const string name = string(1, m);
1673 states.insert(alias ? aliasMap.at(name) : name);
1680string getName(
const set<string>& names,
const string& name)
1682 if (names.count(name)) {
1685 const auto& alias = aliasMap.at(name);
1686 if (names.count(alias)) {
1698 "Group name specifying root location must not be empty.");
1701 if (sub !=
"" && file.
checkGroup(name +
"/" + sub,
true)) {
1703 }
else if (sub ==
"" && file.
checkGroup(name +
"/data",
true)) {
1709 "Group name specifying data entry is empty.");
1714 if (
m_meta.hasKey(
"size")) {
1718 }
else if (
m_meta.hasKey(
"api-shape")) {
1721 m_meta.erase(
"api-shape");
1734 if (states.count(
"C")) {
1735 if (names.count(
"X")) {
1738 mode = mode.substr(0, 2) +
"X";
1739 }
else if (names.count(
"Y")) {
1742 mode = mode.substr(0, 2) +
"Y";
1747 size_t nSpecies =
m_sol->thermo()->nSpecies();
1748 size_t nState =
m_sol->thermo()->stateSize();
1749 const auto& nativeStates =
m_sol->thermo()->nativeState();
1750 if (mode ==
"native") {
1752 for (
const auto& [name,
offset] : nativeStates) {
1753 if (name ==
"X" || name ==
"Y") {
1756 auto prop = data.
asVector<vector<double>>();
1758 std::copy(prop[i].begin(), prop[i].end(),
1767 }
else if (mode ==
"TPX") {
1770 vector<double> T = std::move(data.
asVector<
double>());
1772 vector<double> P = std::move(data.
asVector<
double>());
1774 vector<vector<double>> X = std::move(data.
asVector<vector<double>>());
1776 m_sol->thermo()->setMoleFractions_NoNorm(X[i].data());
1777 m_sol->thermo()->setState_TP(T[i], P[i]);
1780 }
else if (mode ==
"TDX") {
1783 vector<double> T = std::move(data.
asVector<
double>());
1785 vector<double> D = std::move(data.
asVector<
double>());
1787 vector<vector<double>> X = std::move(data.
asVector<vector<double>>());
1789 m_sol->thermo()->setMoleFractions_NoNorm(X[i].data());
1790 m_sol->thermo()->setState_TD(T[i], D[i]);
1793 }
else if (mode ==
"TPY") {
1796 vector<double> T = std::move(data.
asVector<
double>());
1798 vector<double> P = std::move(data.
asVector<
double>());
1800 vector<vector<double>> Y = std::move(data.
asVector<vector<double>>());
1802 m_sol->thermo()->setMassFractions_NoNorm(Y[i].data());
1803 m_sol->thermo()->setState_TP(T[i], P[i]);
1806 }
else if (mode ==
"legacySurf") {
1810 vector<double> T = std::move(data.
asVector<
double>());
1812 vector<vector<double>> X = std::move(data.
asVector<vector<double>>());
1814 m_sol->thermo()->setMoleFractions_NoNorm(X[i].data());
1815 m_sol->thermo()->setTemperature(T[i]);
1819 "Detected legacy HDF format with incomplete state information\nfor name "
1820 "'{}' (pressure missing).", path);
1821 }
else if (mode ==
"") {
1823 "Data are not consistent with full state modes.");
1826 "Import of '{}' data is not supported.", mode);
1830 if (
m_meta.hasKey(
"components")) {
1831 const auto& components =
m_meta[
"components"].asVector<
string>();
1833 for (
const auto& name : components) {
1834 if (
hasComponent(name,
false) || name ==
"X" || name ==
"Y") {
1838 if (reverseAliasMap.count(name)) {
1839 _name = reverseAliasMap.at(name);
1847 m_meta.erase(
"components");
1850 warn_user(
"SolutionArray::readEntry",
"Detected legacy HDF format.");
1851 for (
const auto& name : names) {
1852 if (!
hasComponent(name,
false) && name !=
"X" && name !=
"Y") {
1854 if (reverseAliasMap.count(name)) {
1855 _name = reverseAliasMap.at(name);
1865 if (
m_meta.hasKey(
"transport-model")) {
1866 m_sol->setTransportModel(
m_meta[
"transport-model"].asString());
1874 "Field name specifying root location must not be empty.");
1876 auto path = locateField(root, name);
1877 if (path.hasKey(
"generator") && sub !=
"") {
1879 path = locateField(root, name +
"/" + sub);
1880 }
else if (sub ==
"" && path.hasKey(
"data")) {
1882 path = locateField(root, name +
"/data");
1887 if (path.hasKey(
"size")) {
1889 resize(path[
"size"].asInt());
1890 }
else if (path.hasKey(
"api-shape")) {
1892 auto& shape = path[
"api-shape"].asVector<
long int>();
1896 size = path.getInt(
"points", 0);
1897 if (!path.hasKey(
"T") && !path.hasKey(
"temperature")) {
1906 set<string> exclude = {
"size",
"api-shape",
"points",
"X",
"Y"};
1907 set<string> names = path.keys();
1908 size_t nState =
m_sol->thermo()->stateSize();
1914 if (mode ==
"TPY") {
1915 double T = path[getName(names,
"T")].asDouble();
1916 double P = path[getName(names,
"P")].asDouble();
1917 auto Y = path[
"mass-fractions"].asMap<
double>();
1918 m_sol->thermo()->setState_TPY(T, P, Y);
1919 }
else if (mode ==
"TPC") {
1920 auto surf = std::dynamic_pointer_cast<SurfPhase>(
m_sol->thermo());
1921 double T = path[getName(names,
"T")].asDouble();
1922 double P = path[
"pressure"].asDouble();
1923 m_sol->thermo()->setState_TP(T, P);
1924 auto cov = path[
"coverages"].asMap<
double>();
1925 surf->setCoveragesByName(cov);
1926 }
else if (mode ==
"legacyInlet") {
1929 double T = path[getName(names,
"T")].asDouble();
1930 auto Y = path[
"mass-fractions"].asMap<
double>();
1931 m_sol->thermo()->setState_TPY(T,
m_sol->thermo()->pressure(), Y);
1933 "Detected legacy YAML format with incomplete state information\n"
1934 "for name '{}' (pressure missing).", name +
"/" + sub);
1935 }
else if (mode ==
"") {
1937 "Data are not consistent with full state modes.");
1940 "Import of '{}' data is not supported.", mode);
1942 m_sol->thermo()->saveState(nState,
m_data->data());
1944 exclude.insert(props.begin(), props.end());
1947 if (path.hasKey(
"components")) {
1948 const auto& components = path[
"components"].asVector<
string>();
1950 for (
const auto& name : components) {
1955 if (reverseAliasMap.count(name)) {
1956 _name = reverseAliasMap.at(name);
1961 exclude.insert(name);
1965 for (
const auto& [name, value] : path) {
1966 if (value.isVector<
double>()) {
1967 const vector<double>& data = value.asVector<
double>();
1971 if (reverseAliasMap.count(name)) {
1972 _name = reverseAliasMap.at(name);
1977 exclude.insert(name);
1984 const auto& nativeState =
m_sol->thermo()->nativeState();
1986 set<string> missingProps;
1987 for (
const auto& [name,
offset] : nativeState) {
1988 if (exclude.count(name)) {
1991 missingProps.insert(name);
1995 set<string> TY = {
"T",
"Y"};
1996 if (props == TY && missingProps.count(
"D") && path.hasKey(
"pressure")) {
1998 double P = path[
"pressure"].asDouble();
1999 const size_t offset_T = nativeState.find(
"T")->second;
2000 const size_t offset_D = nativeState.find(
"D")->second;
2001 const size_t offset_Y = nativeState.find(
"Y")->second;
2003 double T = (*m_data)[offset_T + i *
m_stride];
2004 m_sol->thermo()->setState_TPY(
2006 (*m_data)[offset_D + i *
m_stride] =
m_sol->thermo()->density();
2008 }
else if (missingProps.size()) {
2010 "Incomplete state information: missing '{}'.",
2011 ba::join(missingProps,
"', '"));
2016 for (
const auto& [name, value] : path) {
2017 if (!exclude.count(name)) {
2022 if (
m_meta.hasKey(
"transport-model")) {
2023 m_sol->setTransportModel(
m_meta[
"transport-model"].asString());
2032 vector<T> data(slice.size());
2033 const auto& vec = extra.
asVector<T>();
2034 for (
size_t k = 0; k < slice.size(); ++k) {
2035 data[k] = vec[slice[k]];
2043AnyValue getMulti(
const AnyValue& extra,
const vector<int>& slice)
2045 vector<vector<T>> data(slice.size());
2046 const auto& vec = extra.asVector<vector<T>>();
2047 for (
size_t k = 0; k < slice.size(); ++k) {
2048 data[k] = vec[slice[k]];
2056void setScalar(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice)
2058 T value = data.as<T>();
2059 if (extra.isVector<T>()) {
2060 auto& vec = extra.asVector<T>();
2061 for (
size_t k = 0; k < slice.size(); ++k) {
2062 vec[slice[k]] = value;
2065 throw CanteraError(
"SolutionArray::setScalar",
2066 "Incompatible input data: unable to assign '{}' data to '{}'.",
2067 data.type_str(), extra.type_str());
2072void setSingle(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice)
2074 size_t size = slice.size();
2075 if (extra.vectorSize() == size && data.vectorSize() == size) {
2079 if (extra.matrixShape().first == size && data.vectorSize() == size) {
2083 if (extra.type_str() != data.type_str()) {
2085 throw CanteraError(
"SolutionArray::setSingle",
2086 "Incompatible types: expected '{}' but received '{}'.",
2087 extra.type_str(), data.type_str());
2089 const auto& vData = data.asVector<T>();
2090 if (vData.size() != size) {
2091 throw CanteraError(
"SolutionArray::setSingle",
2092 "Invalid input data size: expected {} entries but received {}.",
2093 size, vData.size());
2095 auto& vec = extra.asVector<T>();
2096 for (
size_t k = 0; k < size; ++k) {
2097 vec[slice[k]] = vData[k];
2102void setMulti(AnyValue& extra,
const AnyValue& data,
const vector<int>& slice)
2104 if (!data.isMatrix<T>()) {
2105 throw CanteraError(
"SolutionArray::setMulti",
2106 "Invalid input data shape: inconsistent number of columns.");
2108 size_t size = slice.size();
2109 auto [rows, cols] = data.matrixShape();
2110 if (extra.matrixShape().first == size && rows == size) {
2114 if (extra.vectorSize() == size && rows == size) {
2118 if (extra.type_str() != data.type_str()) {
2120 throw CanteraError(
"SolutionArray::setMulti",
2121 "Incompatible types: expected '{}' but received '{}'.",
2122 extra.type_str(), data.type_str());
2125 throw CanteraError(
"SolutionArray::setMulti",
2126 "Invalid input data shape: expected {} rows but received {}.",
2129 if (extra.matrixShape().second != cols) {
2130 throw CanteraError(
"SolutionArray::setMulti",
2131 "Invalid input data shape: expected {} columns but received {}.",
2132 extra.matrixShape().second, cols);
2134 const auto& vData = data.asVector<vector<T>>();
2135 auto& vec = extra.asVector<vector<T>>();
2136 for (
size_t k = 0; k < slice.size(); ++k) {
2137 vec[slice[k]] = vData[k];
2142void resizeSingle(AnyValue& extra,
size_t size,
const AnyValue& value)
2145 if (value.is<
void>()) {
2146 defaultValue = vector<T>(1)[0];
2148 defaultValue = value.as<T>();
2150 extra.asVector<T>().resize(size, defaultValue);
2154void resizeMulti(AnyValue& extra,
size_t size,
const AnyValue& value)
2156 vector<T> defaultValue;
2157 if (value.is<
void>()) {
2158 defaultValue = vector<T>(extra.matrixShape().second);
2160 defaultValue = value.as<vector<T>>();
2162 extra.asVector<vector<T>>().resize(size, defaultValue);
2166void resetSingle(AnyValue& extra,
const vector<int>& slice)
2168 T defaultValue = vector<T>(1)[0];
2169 vector<T>& data = extra.asVector<T>();
2170 for (
size_t k = 0; k < slice.size(); ++k) {
2171 data[slice[k]] = defaultValue;
2176void resetMulti(AnyValue& extra,
const vector<int>& slice)
2178 vector<T> defaultValue = vector<T>(extra.matrixShape().second);
2179 vector<vector<T>>& data = extra.asVector<vector<T>>();
2180 for (
size_t k = 0; k < slice.size(); ++k) {
2181 data[slice[k]] = defaultValue;
2186void setAuxiliarySingle(
size_t loc, AnyValue& extra,
const AnyValue& value)
2188 extra.asVector<T>()[loc] = value.as<T>();
2192void setAuxiliaryMulti(
size_t loc, AnyValue& extra,
const AnyValue& data)
2194 const auto& value = data.asVector<T>();
2195 auto& vec = extra.asVector<vector<T>>();
2196 if (value.size() != vec[loc].size()) {
2197 throw CanteraError(
"SolutionArray::setAuxiliaryMulti",
2198 "New element size {} does not match existing column size {}.",
2199 value.size(), vec[loc].size());
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase,...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
void setLoc(int line, int column)
For values which are derived from an input file, set the line and column of this value in that file.
A map of string keys to values whose type can vary at runtime.
bool empty() const
Return boolean indicating whether AnyMap is empty.
static void clearCachedFile(const string &filename)
Remove the specified file from the input cache if it is present.
void clear()
Erase all items in the mapping.
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
static bool addOrderingRules(const string &objectType, const vector< vector< string > > &specs)
Add global rules for setting the order of elements when outputting AnyMap objects to YAML.
A wrapper for a variable whose type is determined at runtime.
bool isVector() const
Returns true if the held value is a vector of the specified type, such as vector<double>.
pair< size_t, size_t > matrixShape() const
Returns rows and columns of a matrix.
size_t vectorSize() const
Returns size of the held vector.
bool isScalar() const
Returns true if the held value is a scalar type (such as double, long int, string,...
bool is() const
Returns true if the held value is of the specified type.
const vector< T > & asVector(size_t nMin=npos, size_t nMax=npos) const
Return the held value, if it is a vector of type T.
const T & as() const
Get the value of this key as the specified type.
string type_str() const
Returns a string specifying the type of the held value.
Base class for exceptions thrown by Cantera classes.
const char * what() const override
Get a description of the error.
virtual string getMessage() const
Method overridden by derived classes to format the error message.
An array index is out of range.
An error indicating that an unimplemented function has been called.
size_t m_size
Number of entries in SolutionArray.
void append(const vector< double > &state, const AnyMap &extra)
Append location entry at end of SolutionArray.
string transportModel()
Retrieve associated Transport model.
size_t m_loc
Buffered location within data vector.
void setLoc(int loc, bool restore=true)
Update the buffered location used to access SolutionArray entries.
string _detectMode(const set< string > &names, bool native=true)
Identify storage mode of state data.
size_t m_dataSize
Total size of unsliced data.
static AnyMap readHeader(const string &fname, const string &name)
Read header information from a HDF container file.
size_t m_stride
Stride between SolutionArray entries.
void _setExtra(const string &name, const AnyValue &data=AnyValue())
Set extra SolutionArray component.
string info(const vector< string > &keys, int rows=10, int width=80)
Print a concise summary of a SolutionArray.
vector< string > listExtra(bool all=true) const
Retrieve list of extra component names.
void setApiShape(const vector< long int > &shape)
Set SolutionArray shape information used by high-level API's.
void setAuxiliary(int loc, const AnyMap &data)
Set auxiliary data for a given location.
static void writeHeader(const string &fname, const string &name, const string &desc, bool overwrite=false)
Write header data to a HDF container file.
AnyMap restore(const string &fname, const string &name, const string &sub="")
Restore SolutionArray data and header information from a container file.
AnyMap getAuxiliary(int loc)
Retrieve auxiliary data for a given location.
AnyValue getComponent(const string &name) const
Retrieve a component of the SolutionArray by name.
vector< int > m_active
Vector of locations referencing active entries.
set< string > _stateProperties(const string &mode, bool alias=false)
Retrieve set containing list of properties defining state.
void readEntry(const string &fname, const string &name, const string &sub)
Restore SolutionArray data from a HDF container file.
void _resize(size_t size)
Service function used to resize SolutionArray.
void _initExtra(const string &name, const AnyValue &value)
Initialize extra SolutionArray component.
vector< string > componentNames() const
Retrieve list of component names.
shared_ptr< vector< double > > m_data
Work vector holding states.
shared_ptr< map< string, AnyValue > > m_extra
Auxiliary (extra) components; size of first dimension has to match m_dataSize.
bool m_shared
true if data are shared from another object
void setState(int loc, const vector< double > &state)
Set the state vector for a given location.
shared_ptr< map< int, string > > m_order
Mapping of auxiliary component names, where the index is used as the mapping key.
int apiNdim() const
Number of SolutionArray dimensions used by high-level API's.
void setComponent(const string &name, const AnyValue &data)
Set a component of the SolutionArray by name.
void normalize()
Normalize mass/mole fractions.
void save(const string &fname, const string &name="", const string &sub="", const string &desc="", bool overwrite=false, int compression=0, const string &basis="")
Save current SolutionArray contents to a data file.
void reset()
Reset all entries of the SolutionArray to the current Solution state.
void resize(int size)
Resize SolutionArray objects with a single dimension (default).
void _resizeExtra(const string &name, const AnyValue &value=AnyValue())
Resize extra SolutionArray component.
shared_ptr< ThermoPhase > thermo()
Retrieve associated ThermoPhase object.
void addExtra(const string &name, bool back=true)
Add auxiliary component to SolutionArray.
shared_ptr< Solution > phase()
Retrieve associated Solution object.
void updateState(int loc)
Update state at given location to state of associated Solution object.
vector< double > getState(int loc)
Retrieve the state vector for a given location.
void writeEntry(const string &fname, bool overwrite=false, const string &basis="")
Write SolutionArray data to a CSV file.
int size() const
Size of SolutionArray (number of entries).
bool hasComponent(const string &name, bool checkAlias=true) const
Check whether SolutionArray contains a component.
vector< long int > m_apiShape
Shape information used by high-level API's.
shared_ptr< Solution > m_sol
Solution object associated with state data.
A wrapper class handling storage to HDF.
pair< size_t, set< string > > contents(const string &id) const
Retrieve contents of file from a specified location.
void writeAttributes(const string &id, const AnyMap &meta)
Write attributes to a specified location.
void deleteGroup(const string &id)
Delete group.
AnyMap readAttributes(const string &id, bool recursive) const
Read attributes from a specified location.
AnyValue readData(const string &id, const string &name, size_t rows, size_t cols=npos) const
Read dataset from a specified location.
bool checkGroup(const string &id, bool permissive=false)
Check whether path location exists.
void setCompressionLevel(int level)
Set compression level (0..9)
void writeData(const string &id, const string &name, const AnyValue &data)
Write dataset to a specified location.
void tokenizePath(const string &in_val, vector< string > &v)
This function separates a string up into tokens according to the location of path separators.
string toLowerCopy(const string &input)
Convert to lower case.
U len(const T &container)
Get the size of a container, cast to a signed integer type.
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
const map< string, string > & _componentAliasMap()
Return mapping of component alias names to standardized component names.
offset
Offsets of solution components in the 1D solution array.
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...