12#include "cantera/oneD/refine.h"
32 for (
size_t n = 0; n <
nDomains(); n++) {
40 for (
size_t dom=0; dom<
nDomains(); dom++) {
43 for (
size_t comp=0; comp<ncomp; comp++) {
55 "Index out of bounds: {} > {}", iloc,
m_state->size());
56 (*m_state)[iloc] =
value;
59double Sim1D::value(
size_t dom,
size_t comp,
size_t localPoint)
const
63 "Index out of bounds: {} > {}", iloc,
m_state->size());
71 "Index out of bounds: {} > {}", iloc,
m_state->size());
76 const vector<double>& pos,
const vector<double>& values)
78 if (pos.front() != 0.0 || pos.back() != 1.0) {
80 "`pos` vector must span the range [0, 1]. Got a vector spanning "
81 "[{}, {}] instead.", pos.front(), pos.back());
86 for (
size_t n = 0; n < d.
nPoints(); n++) {
88 double frac = (zpt - z0)/(z1 - z0);
94void Sim1D::save(
const string& fname,
const string& name,
const string& desc,
95 bool overwrite,
int compression,
const string& basis)
97 size_t dot = fname.find_last_of(
".");
99 if (extension ==
"csv") {
100 for (
auto dom :
m_dom) {
101 auto arr = dom->asArray(
m_state->data() + dom->loc());
102 if (dom->size() > 1) {
103 arr->writeEntry(fname, overwrite, basis);
111 "Species basis '{}' not implemented for HDF5 or YAML output.", basis);
113 if (extension ==
"h5" || extension ==
"hdf" || extension ==
"hdf5") {
115 for (
auto dom :
m_dom) {
116 auto arr = dom->asArray(
m_state->data() + dom->loc());
117 arr->writeEntry(fname, name, dom->id(), overwrite, compression);
121 if (extension ==
"yaml" || extension ==
"yml") {
124 if (std::ifstream(fname).good()) {
129 for (
auto dom :
m_dom) {
130 auto arr = dom->asArray(
m_state->data() + dom->loc());
131 arr->writeEntry(data, name, dom->id(), overwrite);
135 std::ofstream out(fname);
136 out << data.toYamlString();
140 throw CanteraError(
"Sim1D::save",
"Unsupported file format '{}'.", extension);
144 const string& desc,
bool overwrite,
int compression)
146 vector<double> res(
m_state->size(), -999);
150 vector<double> backup(*
m_state);
152 save(fname, name, desc, overwrite, compression);
159AnyMap legacyH5(shared_ptr<SolutionArray> arr,
const AnyMap& header={})
161 auto meta = arr->meta();
164 map<string, string> meta_pairs = {
165 {
"type",
"Domain1D_type"},
167 {
"emissivity-left",
"emissivity_left"},
168 {
"emissivity-right",
"emissivity_right"},
170 for (
const auto& [newName, oldName] : meta_pairs) {
171 if (meta.hasKey(oldName)) {
172 out[newName] = meta[oldName];
176 map<string, string> tol_pairs = {
177 {
"transient-abstol",
"transient_abstol"},
178 {
"steady-abstol",
"steady_abstol"},
179 {
"transient-reltol",
"transient_reltol"},
180 {
"steady-reltol",
"steady_reltol"},
182 for (
const auto& [newName, oldName] : tol_pairs) {
183 if (meta.hasKey(oldName)) {
184 out[
"tolerances"][newName] = meta[oldName];
188 if (meta.hasKey(
"phase")) {
189 out[
"phase"][
"name"] = meta[
"phase"][
"name"];
190 out[
"phase"][
"source"] = meta[
"phase"][
"source"];
193 if (arr->size() <= 1) {
197 map<string, string> header_pairs = {
198 {
"transport-model",
"transport_model"},
199 {
"radiation-enabled",
"radiation_enabled"},
200 {
"energy-enabled",
"energy_enabled"},
201 {
"Soret-enabled",
"soret_enabled"},
203 for (
const auto& [newName, oldName] : header_pairs) {
204 if (header.hasKey(oldName)) {
205 out[newName] = header[oldName];
209 map<string, string> refiner_pairs = {
215 {
"max-points",
"max_grid_points"},
217 for (
const auto& [newName, oldName] : refiner_pairs) {
218 if (header.hasKey(oldName)) {
219 out[
"refine-criteria"][newName] = header[oldName];
223 if (header.hasKey(
"fixed_temperature")) {
224 double temp = header.
getDouble(
"fixed_temperature", -1.);
225 auto profile = arr->getComponent(
"T").as<vector<double>>();
227 while (profile[ix] <= temp && ix < arr->size()) {
231 auto grid = arr->getComponent(
"grid").as<vector<double>>();
232 out[
"fixed-point"][
"location"] = grid[ix - 1];
233 out[
"fixed-point"][
"temperature"] = temp;
244 size_t dot = fname.find_last_of(
".");
246 if (extension ==
"xml") {
248 "Restoring from XML is no longer supported.");
251 if (extension ==
"h5" || extension ==
"hdf" || extension ==
"hdf5") {
252 map<string, shared_ptr<SolutionArray>> arrs;
255 for (
auto dom :
m_dom) {
258 arr->readEntry(fname, name, dom->id());
261 "Encountered exception when reading entry '{}' from '{}':\n{}",
264 dom->resize(dom->nComponents(), arr->size());
265 if (!header.
hasKey(
"generator")) {
266 arr->meta() = legacyH5(arr, header);
268 arrs[dom->id()] = arr;
272 for (
auto dom :
m_dom) {
274 dom->fromArray(*arrs[dom->id()],
m_state->data() + dom->loc());
277 "Encountered exception when restoring domain '{}' from HDF:\n{}",
282 }
else if (extension ==
"yaml" || extension ==
"yml") {
284 map<string, shared_ptr<SolutionArray>> arrs;
287 for (
auto dom :
m_dom) {
290 arr->readEntry(root, name, dom->id());
293 "Encountered exception when reading entry '{}' from '{}':\n{}",
296 dom->resize(dom->nComponents(), arr->size());
297 arrs[dom->id()] = arr;
301 for (
auto dom :
m_dom) {
303 dom->fromArray(*arrs[dom->id()],
m_state->data() + dom->loc());
306 "Encountered exception when restoring domain '{}' from YAML:\n{}",
313 "Unknown file extension '{}'; supported extensions include "
314 "'h5'/'hdf'/'hdf5' and 'yml'/'yaml'.", extension);
322 for (
size_t n = 0; n < np; n++) {
329 for (
size_t n = 0; n <
nDomains(); n++) {
332 +
" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
341 throw CanteraError(
"Sim1D::restoreTimeSteppingSolution",
342 "No successful time steps taken on this grid.");
351 "No successful steady state solution");
354 for (
size_t n = 0; n <
nDomains(); n++) {
362 for (
size_t n = 0; n <
nDomains(); n++) {
369 for (
size_t n = 0; n <
nDomains(); n++) {
383 while (new_points > 0) {
386 writelog(
"\nNewton steady-state solve succeeded.\n\n");
388 for (
size_t mm = 1; mm <
nDomains(); mm+=2) {
403 new_points =
refine(loglevel);
407 debuglog(
"grid refinement disabled.\n", loglevel);
411 if (new_points < 0) {
415 for (
auto dom :
m_dom) {
426 vector<double> znew, xnew;
427 vector<size_t> dsize;
432 for (
size_t n = 0; n <
nDomains(); n++) {
451 size_t nstart = znew.size();
452 for (
size_t m = 0; m < npnow; m++) {
455 znew.push_back(d.
z(m));
458 for (
size_t i = 0; i < comp; i++) {
459 xnew.push_back(
value(n, i, m));
467 double zmid = 0.5*(d.
z(m) + d.
z(m+1));
468 znew.push_back(zmid);
473 for (
size_t i = 0; i < comp; i++) {
474 double xmid = 0.5*(
value(n, i, m) +
value(n, i, m+1));
475 xnew.push_back(xmid);
481 writelog(
"refine: discarding point at {}\n", d.
z(m));
485 dsize.push_back(znew.size() - nstart);
492 size_t gridstart = 0, gridsize;
493 for (
size_t n = 0; n <
nDomains(); n++) {
499 gridstart += gridsize;
506 return added || -discarded;
511 std::filesystem::remove(
"debug_sim1d.yaml");
515 int loglevel,
int attempt_counter)
519 file_header = fmt::format(
"solution_{}_{}", attempt_counter, header_suffix);
520 save(
"debug_sim1d.yaml", file_header, message,
true);
523 file_header = fmt::format(
"residual_{}_{}", attempt_counter, header_suffix);
524 saveResidual(
"debug_sim1d.yaml", file_header, message,
true);
531 vector<double> znew, xnew;
533 double z1 = 0.0, z2 = 0.0;
534 vector<size_t> dsize;
536 for (
size_t n = 0; n <
nDomains(); n++) {
539 size_t mfixed =
npos;
544 size_t nstart = znew.size();
545 if (d_free && d_free->
isFree()) {
546 for (
size_t m = 0; m < npnow - 1; m++) {
547 bool fixedpt =
false;
551 double thresh = min(1., 1.e-1 * (t2 - t1));
554 if (fabs(t - t1) <= thresh) {
557 }
else if (fabs(t2 - t) <= thresh) {
560 }
else if ((t1 < t) && (t < t2)) {
562 zfixed = (z1 - z2) / (t1 - t2) * (t - t2) + z2;
575 for (
size_t m = 0; m < npnow; m++) {
577 znew.push_back(d.
z(m));
580 for (
size_t i = 0; i < comp; i++) {
581 xnew.push_back(
value(n, i, m));
585 znew.push_back(zfixed);
587 double interp_factor = (zfixed - z2) / (z1 - z2);
590 for (
size_t i = 0; i < comp; i++) {
591 double xmid = interp_factor*(
value(n, i, m) -
value(n, i, m+1)) +
value(n,i,m+1);
592 xnew.push_back(xmid);
596 dsize.push_back(znew.size() - nstart);
602 size_t gridstart = 0;
603 for (
size_t n = 0; n <
nDomains(); n++) {
605 size_t gridsize = dsize[n];
607 gridstart += gridsize;
620 double t_fixed = std::numeric_limits<double>::quiet_NaN();
621 for (
size_t n = 0; n <
nDomains(); n++) {
633 double z_fixed = std::numeric_limits<double>::quiet_NaN();
634 for (
size_t n = 0; n <
nDomains(); n++) {
646 bool two_point_domain_found =
false;
647 for (
size_t n = 0; n <
nDomains(); n++) {
662 two_point_domain_found =
true;
664 double current_val, next_val;
665 for (
size_t m = 0; m < np-1; m++) {
668 if ((current_val - temperature) * (next_val - temperature) < 0.0) {
672 if (std::abs(current_val - temperature) <
673 std::abs(next_val - temperature)) {
685 if (!two_point_domain_found) {
687 "No domain with two-point control enabled was found.");
690 "No control point with temperature {} was able to be found in the"
691 "flame's temperature range.", temperature);
697 bool two_point_domain_found =
false;
698 for (
size_t n = 0; n <
nDomains(); n++) {
713 two_point_domain_found =
true;
715 double current_val, next_val;
716 for (
size_t m = np-1; m > 0; m--) {
719 if ((current_val - temperature) * (next_val - temperature) < 0.0) {
723 if (std::abs(current_val - temperature) <
724 std::abs(next_val - temperature)) {
736 if (!two_point_domain_found) {
738 "No domain with two-point control enabled was found.");
741 "No control point with temperature {} was able to be found in the"
742 "flame's temperature range.", temperature);
748 double slope,
double curve,
double prune)
754 for (
size_t n = 0; n <
nDomains(); n++) {
768 "Must specify domain to get criteria from");
778 for (
size_t n = 0; n <
nDomains(); n++) {
791 for (
size_t n = 0; n <
nDomains(); n++) {
806 warn_deprecated(
"Sim1D::jacobian",
"To be removed after Cantera 3.2.");
817 for (
auto& D :
m_dom) {
818 D->forceFullUpdate(
true);
821 for (
auto& D :
m_dom) {
822 D->forceFullUpdate(
false);
825 auto multijac = dynamic_pointer_cast<MultiJac>(
m_jac);
827 throw CanteraError(
"Sim1D::solveAdjoint",
"Banded (MultiJac) required");
832 for (
size_t i = 0; i <
size(); i++) {
833 size_t j1 = (i > bw) ? i - bw : 0;
834 size_t j2 = (i + bw >=
size()) ?
size() - 1: i + bw;
835 for (
size_t j = j1; j <= j2; j++) {
836 Jt(j,i) = multijac->
value(i,j);
849shared_ptr<Sim1D>
newSim1D(vector<shared_ptr<Domain1D>>& domains)
851 return make_shared<Sim1D>(domains);
A map of string keys to values whose type can vary at runtime.
double getDouble(const string &key, double default_) const
If key exists, return it as a double, otherwise return default_.
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
static void clearCachedFile(const string &filename)
Remove the specified file from the input cache if it is present.
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
A class for banded matrices, involving matrix inversion processes.
int solve(const double *const b, double *const x)
Solve the matrix problem Ax = b.
double & value(size_t i, size_t j)
Return a changeable reference to element (i,j).
Base class for exceptions thrown by Cantera classes.
virtual string getMessage() const
Method overridden by derived classes to format the error message.
Base class for one-dimensional domains.
size_t nComponents() const
Number of components at each grid point.
virtual void _finalize(const double *x)
In some cases, a domain may need to set parameters that depend on the initial solution estimate.
void setupGrid(const vector< double > &grid)
Set up initial grid.
vector< double > & grid()
Access the array of grid coordinates [m].
double zmin() const
Get the coordinate [m] of the first (leftmost) grid point in this domain.
size_t nPoints() const
Number of grid points in this domain.
virtual string domainType() const
Domain type flag.
double z(size_t jlocal) const
Get the coordinate [m] of the point with local index jlocal
Refiner & refiner()
Return a reference to the grid refiner.
virtual void show(const double *x)
Print the solution.
virtual string componentName(size_t n) const
Name of component n. May be overloaded.
string type() const
String indicating the domain implemented.
double zmax() const
Get the coordinate [m] of the last (rightmost) grid point in this domain.
virtual void _getInitialSoln(double *x)
Writes some or all initial solution values into the global solution array, beginning at the location ...
size_t index(size_t n, size_t j) const
Returns the index of the solution vector, which corresponds to component n at grid point j.
virtual size_t loc(size_t j=0) const
Location of the start of the local solution vector in the global solution vector.
This class represents 1D flow domains that satisfy the one-dimensional similarity solution for chemic...
void setLeftControlPointTemperature(double temperature)
Sets the temperature of the left control point.
void setLeftControlPointCoordinate(double z_left)
Sets the coordinate of the left control point.
void setRightControlPointCoordinate(double z_right)
Sets the coordinate of the right control point.
bool twoPointControlEnabled() const
Returns the status of the two-point control.
void setRightControlPointTemperature(double temperature)
Sets the temperature of the right control point.
double m_tfixed
Temperature at the point used to fix the flame location.
double m_zfixed
Location of the point where temperature is fixed.
bool isFree() const
Retrieve flag indicating whether flow is freely propagating.
virtual double eval(double t) const
Evaluate the function.
Container class for multiple-domain 1D problems.
size_t start(size_t i) const
The index of the start of domain i in the solution vector.
void resize() override
Call to set the size of internal data structures after first defining the system or if the problem si...
void eval(size_t j, double *x, double *r, double rdt=-1.0, int count=1)
Evaluate the multi-domain residual function.
size_t nDomains() const
Number of domains.
std::tuple< string, size_t, string > component(size_t i) const
Return the domain, local point index, and component name for the i-th component of the global solutio...
Domain1D & domain(size_t i) const
Return a reference to domain i.
vector< shared_ptr< Domain1D > > m_dom
All domains comprising the system.
Refine Domain1D grids so that profiles satisfy adaptation tolerances.
bool newPointNeeded(size_t j)
Returns true if a new grid point is needed to the right of grid index j.
size_t maxPoints() const
Returns the maximum number of points allowed in the domain.
int nNewPoints()
Returns the number of new grid points that were needed.
void show()
Displays the results of the grid refinement analysis.
vector< double > getCriteria()
Get the grid refinement criteria.
void setMaxPoints(int npmax)
Set the maximum number of points allowed in the domain.
void setCriteria(double ratio=10.0, double slope=0.8, double curve=0.8, double prune=-0.1)
Set grid refinement criteria.
int analyze(size_t n, const double *z, const double *x)
Determine locations in the grid that need additional grid points and update the internal state of the...
bool keepPoint(size_t j)
Returns true if the grid point at index j should be kept.
void setGridMin(double gridmin)
Set the minimum allowable spacing between adjacent grid points [m].
void getInitialSoln()
Get the initial value of the system state from each domain in the simulation.
void restoreTimeSteppingSolution()
Set the current solution vector to the last successful time-stepping solution.
void resize() override
Call to set the size of internal data structures after first defining the system or if the problem si...
void saveResidual(const string &fname, const string &name, const string &desc, bool overwrite=false, int compression=0)
Save the residual of the current solution to a container file.
void setProfile(size_t dom, size_t comp, const vector< double > &pos, const vector< double > &values)
Specify a profile for one component of one domain.
double fixedTemperatureLocation()
Return location of the point where temperature is fixed.
vector< vector< double > > m_grid_last_ss
the grids for each domain after the last successful steady-state solve (stored before grid refinement...
void finalize()
Calls method _finalize in each domain.
void setValue(size_t dom, size_t comp, size_t localPoint, double value)
Set a single value in the solution vector.
int refine(int loglevel=0)
Refine the grid in all domains.
void show()
Show logging information on current solution for all domains.
double fixedTemperature()
Return temperature at the point used to fix the flame location.
void clearDebugFile() override
Deletes a debug_sim1d.yaml file if it exists.
vector< double > m_xlast_ss
the solution vector after the last successful steady-state solve (stored before grid refinement)
void setMaxGridPoints(int dom, int npoints)
Set the maximum number of grid points in the domain.
int setFixedTemperature(double t)
Add node for fixed temperature point of freely propagating flame.
void setInitialGuess(const string &component, vector< double > &locs, vector< double > &vals)
Set initial guess for one component for all domains.
void solve(int loglevel=0, bool refine_grid=true)
Performs the hybrid Newton steady/time-stepping solution.
void evalSSJacobian()
Evaluate the Jacobian in steady-state mode.
void solveAdjoint(const double *b, double *lambda)
Solve the equation .
AnyMap restore(const string &fname, const string &name)
Retrieve data and settings from a previously saved simulation.
Func1 * m_steady_callback
User-supplied function called after a successful steady-state solve.
void restoreSteadySolution()
Set the current solution vector and grid to the last successful steady- state solution.
size_t maxGridPoints(size_t dom)
Get the maximum number of grid points in this domain.
void setFlatProfile(size_t dom, size_t comp, double v)
Set component 'comp' of domain 'dom' to value 'v' at all points.
void writeDebugInfo(const string &header_suffix, const string &message, int loglevel, int attempt_counter) override
Write solver debugging information to a YAML file based on the specified log level.
void setRightControlPoint(double temperature)
Set the right control point location using the specified temperature.
double value(size_t dom, size_t comp, size_t localPoint) const
Get one entry in the solution vector.
double workValue(size_t dom, size_t comp, size_t localPoint) const
Get an entry in the work vector, which may contain either a new system state or the current residual ...
vector< double > getRefineCriteria(int dom)
Get the grid refinement criteria.
Sim1D()
Default constructor.
void setGridMin(int dom, double gridmin)
Set the minimum grid spacing in the specified domain(s).
void setRefineCriteria(int dom=-1, double ratio=10.0, double slope=0.8, double curve=0.8, double prune=-0.1)
Set grid refinement criteria.
void save(const string &fname, const string &name, const string &desc, bool overwrite=false, int compression=0, const string &basis="")
Save current simulation data to a container file or CSV format.
void setLeftControlPoint(double temperature)
Set the left control point location using the specified temperature.
static AnyMap readHeader(const string &fname, const string &name)
Read header information from a HDF container file.
static void writeHeader(const string &fname, const string &name, const string &desc, bool overwrite=false)
Write header data to a HDF container file.
static shared_ptr< SolutionArray > create(const shared_ptr< Solution > &sol, int size=0, const AnyMap &meta={})
Instantiate a new SolutionArray reference.
int solve(double *x0, double *x1, int loglevel)
Solve , where is the residual function.
vector< double > m_xnew
Work array used to hold the residual or the new solution.
size_t size() const
Total solution vector length;.
size_t bandwidth() const
Jacobian bandwidth.
shared_ptr< SystemJacobian > m_jac
Jacobian evaluator.
shared_ptr< vector< double > > m_state
Solution vector.
vector< int > m_mask
Transient mask.
void evalSSJacobian(double *x, double *rsd)
Evaluate the steady-state Jacobian, accessible via linearSolver()
int m_attempt_counter
Counter used to manage the number of states stored in the debug log file generated by writeDebugInfo(...
vector< double > m_xlast_ts
State vector after the last successful set of time steps.
Header for a file containing miscellaneous numerical functions.
string toLowerCopy(const string &input)
Convert to lower case.
MultiJac & jacobian()
Return a reference to the Jacobian evaluator of an OneDim object.
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
void debuglog(const string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
double linearInterp(double x, const vector< double > &xpts, const vector< double > &fpts)
Linearly interpolate a function defined on a discrete grid.
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"
shared_ptr< Sim1D > newSim1D(vector< shared_ptr< Domain1D > > &domains)
Create a Sim1D object with a list of domains.
@ c_offset_T
temperature [kelvin]
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Contains declarations for string manipulation functions within Cantera.