Cantera  3.2.0a4
Loading...
Searching...
No Matches
Sim1D.cpp
Go to the documentation of this file.
1/**
2 * @file Sim1D.cpp
3 */
4
5// This file is part of Cantera. See License.txt in the top-level directory or
6// at https://cantera.org/license.txt for license and copyright information.
7
10#include "cantera/oneD/Flow1D.h"
12#include "cantera/oneD/refine.h"
17#include <limits>
18#include <fstream>
19
20using namespace std;
21
22namespace Cantera
23{
24
25Sim1D::Sim1D(vector<shared_ptr<Domain1D>>& domains) :
26 OneDim(domains),
27 m_steady_callback(0)
28{
29 // resize the internal solution vector and the work array, and perform
30 // domain-specific initialization of the solution vector.
31 resize();
32 for (size_t n = 0; n < nDomains(); n++) {
33 domain(n)._getInitialSoln(m_state->data() + start(n));
34 }
35}
36
37void Sim1D::setInitialGuess(const string& component, vector<double>& locs,
38 vector<double>& vals)
39{
40 warn_deprecated("Sim1D::setInitialGuess", "To be removed after Cantera 3.2. "
41 "Replaceable by Domain1D::setProfile.");
42 for (size_t dom=0; dom<nDomains(); dom++) {
43 Domain1D& d = domain(dom);
44 size_t ncomp = d.nComponents();
45 for (size_t comp=0; comp<ncomp; comp++) {
46 if (d.componentName(comp)==component) {
47 setProfile(dom,comp,locs,vals);
48 }
49 }
50 }
51}
52
53void Sim1D::_setValue(size_t dom, size_t comp, size_t localPoint, double value)
54{
55 size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
56 AssertThrowMsg(iloc < m_state->size(), "Sim1D::setValue",
57 "Index out of bounds: {} > {}", iloc, m_state->size());
58 (*m_state)[iloc] = value;
59}
60
61double Sim1D::_value(size_t dom, size_t comp, size_t localPoint) const
62{
63 size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
64 AssertThrowMsg(iloc < m_state->size(), "Sim1D::value",
65 "Index out of bounds: {} > {}", iloc, m_state->size());
66 return (*m_state)[iloc];
67}
68
69double Sim1D::_workValue(size_t dom, size_t comp, size_t localPoint) const
70{
71 size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
72 AssertThrowMsg(iloc < m_state->size(), "Sim1D::workValue",
73 "Index out of bounds: {} > {}", iloc, m_state->size());
74 return m_xnew[iloc];
75}
76
77void Sim1D::setProfile(size_t dom, size_t comp,
78 const vector<double>& pos, const vector<double>& values)
79{
80 warn_deprecated("Sim1D::setProfile", "To be removed after Cantera 3.2. "
81 "Replaceable by Domain1D::setProfile.");
82 if (pos.front() != 0.0 || pos.back() != 1.0) {
83 throw CanteraError("Sim1D::setProfile",
84 "`pos` vector must span the range [0, 1]. Got a vector spanning "
85 "[{}, {}] instead.", pos.front(), pos.back());
86 }
87 Domain1D& d = domain(dom);
88 double z0 = d.zmin();
89 double z1 = d.zmax();
90 for (size_t n = 0; n < d.nPoints(); n++) {
91 double zpt = d.z(n);
92 double frac = (zpt - z0)/(z1 - z0);
93 double v = linearInterp(frac, pos, values);
94 _setValue(dom, comp, n, v);
95 }
96}
97
98void Sim1D::save(const string& fname, const string& name, const string& desc,
99 bool overwrite, int compression, const string& basis)
100{
101 size_t dot = fname.find_last_of(".");
102 string extension = (dot != npos) ? toLowerCopy(fname.substr(dot+1)) : "";
103 if (extension == "csv") {
104 for (auto dom : m_dom) {
105 auto arr = dom->toArray();
106 if (dom->size() > 1) {
107 arr->writeEntry(fname, overwrite, basis);
108 break;
109 }
110 }
111 return;
112 }
113 if (basis != "") {
114 warn_user("Sim1D::save",
115 "Species basis '{}' not implemented for HDF5 or YAML output.", basis);
116 }
117 if (extension == "h5" || extension == "hdf" || extension == "hdf5") {
118 SolutionArray::writeHeader(fname, name, desc, overwrite);
119 for (auto dom : m_dom) {
120 auto arr = dom->toArray();
121 arr->writeEntry(fname, name, dom->id(), overwrite, compression);
122 }
123 return;
124 }
125 if (extension == "yaml" || extension == "yml") {
126 // Check for an existing file and load it if present
127 AnyMap data;
128 if (std::ifstream(fname).good()) {
129 data = AnyMap::fromYamlFile(fname);
130 }
131 SolutionArray::writeHeader(data, name, desc, overwrite);
132
133 for (auto dom : m_dom) {
134 auto arr = dom->toArray();
135 arr->writeEntry(data, name, dom->id(), overwrite);
136 }
137
138 // Write the output file and remove the now-outdated cached file
139 std::ofstream out(fname);
140 out << data.toYamlString();
142 return;
143 }
144 throw CanteraError("Sim1D::save", "Unsupported file format '{}'.", extension);
145}
146
147void Sim1D::saveResidual(const string& fname, const string& name,
148 const string& desc, bool overwrite, int compression)
149{
150 vector<double> res(m_state->size(), -999);
151 OneDim::eval(npos, m_state->data(), &res[0], 0.0);
152 // Temporarily put the residual into m_state, since this is the vector that the
153 // save() function reads.
154 vector<double> backup(*m_state);
155 *m_state = res;
156 save(fname, name, desc, overwrite, compression);
157 *m_state = backup;
158}
159
160namespace { // restrict scope of helper function to local translation unit
161
162//! convert data format used by Python h5py export (Cantera < 3.0)
163AnyMap legacyH5(shared_ptr<SolutionArray> arr, const AnyMap& header={})
164{
165 auto meta = arr->meta();
166 AnyMap out;
167
168 map<string, string> meta_pairs = {
169 {"type", "Domain1D_type"},
170 {"name", "name"},
171 {"emissivity-left", "emissivity_left"},
172 {"emissivity-right", "emissivity_right"},
173 };
174 for (const auto& [newName, oldName] : meta_pairs) {
175 if (meta.hasKey(oldName)) {
176 out[newName] = meta[oldName];
177 }
178 }
179
180 map<string, string> tol_pairs = {
181 {"transient-abstol", "transient_abstol"},
182 {"steady-abstol", "steady_abstol"},
183 {"transient-reltol", "transient_reltol"},
184 {"steady-reltol", "steady_reltol"},
185 };
186 for (const auto& [newName, oldName] : tol_pairs) {
187 if (meta.hasKey(oldName)) {
188 out["tolerances"][newName] = meta[oldName];
189 }
190 }
191
192 if (meta.hasKey("phase")) {
193 out["phase"]["name"] = meta["phase"]["name"];
194 out["phase"]["source"] = meta["phase"]["source"];
195 }
196
197 if (arr->size() <= 1) {
198 return out;
199 }
200
201 map<string, string> header_pairs = {
202 {"transport-model", "transport_model"},
203 {"radiation-enabled", "radiation_enabled"},
204 {"energy-enabled", "energy_enabled"},
205 {"Soret-enabled", "soret_enabled"},
206 };
207 for (const auto& [newName, oldName] : header_pairs) {
208 if (header.hasKey(oldName)) {
209 out[newName] = header[oldName];
210 }
211 }
212
213 map<string, string> refiner_pairs = {
214 {"ratio", "ratio"},
215 {"slope", "slope"},
216 {"curve", "curve"},
217 {"prune", "prune"},
218 // {"grid-min", "???"}, // missing
219 {"max-points", "max_grid_points"},
220 };
221 for (const auto& [newName, oldName] : refiner_pairs) {
222 if (header.hasKey(oldName)) {
223 out["refine-criteria"][newName] = header[oldName];
224 }
225 }
226
227 if (header.hasKey("fixed_temperature")) {
228 double temp = header.getDouble("fixed_temperature", -1.);
229 auto profile = arr->getComponent("T").as<vector<double>>();
230 int ix = 0;
231 while (profile[ix] <= temp && ix < arr->size()) {
232 ix++;
233 }
234 if (ix != 0) {
235 auto grid = arr->getComponent("grid").as<vector<double>>();
236 out["fixed-point"]["location"] = grid[ix - 1];
237 out["fixed-point"]["temperature"] = temp;
238 }
239 }
240
241 return out;
242}
243
244} // end unnamed namespace
245
246AnyMap Sim1D::restore(const string& fname, const string& name)
247{
248 size_t dot = fname.find_last_of(".");
249 string extension = (dot != npos) ? toLowerCopy(fname.substr(dot+1)) : "";
250 if (extension == "xml") {
251 throw CanteraError("Sim1D::restore",
252 "Restoring from XML is no longer supported.");
253 }
254 AnyMap header;
255 if (extension == "h5" || extension == "hdf" || extension == "hdf5") {
256 map<string, shared_ptr<SolutionArray>> arrs;
257 header = SolutionArray::readHeader(fname, name);
258
259 for (auto dom : m_dom) {
260 auto arr = SolutionArray::create(dom->solution());
261 try {
262 arr->readEntry(fname, name, dom->id());
263 } catch (CanteraError& err) {
264 throw CanteraError("Sim1D::restore",
265 "Encountered exception when reading entry '{}' from '{}':\n{}",
266 name, fname, err.getMessage());
267 }
268 dom->resize(dom->nComponents(), arr->size());
269 if (!header.hasKey("generator")) {
270 arr->meta() = legacyH5(arr, header);
271 }
272 arrs[dom->id()] = arr;
273 }
274 resize();
275 m_xlast_ts.clear();
276 for (auto dom : m_dom) {
277 try {
278 dom->fromArray(arrs[dom->id()]);
279 } catch (CanteraError& err) {
280 throw CanteraError("Sim1D::restore",
281 "Encountered exception when restoring domain '{}' from HDF:\n{}",
282 dom->id(), err.getMessage());
283 }
284 }
285 finalize();
286 } else if (extension == "yaml" || extension == "yml") {
287 AnyMap root = AnyMap::fromYamlFile(fname);
288 map<string, shared_ptr<SolutionArray>> arrs;
289 header = SolutionArray::readHeader(root, name);
290
291 for (auto dom : m_dom) {
292 auto arr = SolutionArray::create(dom->solution());
293 try {
294 arr->readEntry(root, name, dom->id());
295 } catch (CanteraError& err) {
296 throw CanteraError("Sim1D::restore",
297 "Encountered exception when reading entry '{}' from '{}':\n{}",
298 name, fname, err.getMessage());
299 }
300 dom->resize(dom->nComponents(), arr->size());
301 arrs[dom->id()] = arr;
302 }
303 resize();
304 m_xlast_ts.clear();
305 for (auto dom : m_dom) {
306 try {
307 dom->fromArray(arrs[dom->id()]);
308 } catch (CanteraError& err) {
309 throw CanteraError("Sim1D::restore",
310 "Encountered exception when restoring domain '{}' from YAML:\n{}",
311 dom->id(), err.getMessage());
312 }
313 }
314 finalize();
315 } else {
316 throw CanteraError("Sim1D::restore",
317 "Unknown file extension '{}'; supported extensions include "
318 "'h5'/'hdf'/'hdf5' and 'yml'/'yaml'.", extension);
319 }
320 return header;
321}
322
323void Sim1D::_restore(const string& fname, const string& name)
324{
325 restore(fname, name);
326}
327
328void Sim1D::setFlatProfile(size_t dom, size_t comp, double v)
329{
330 warn_deprecated("Sim1D::setFlatProfile", "To be removed after Cantera 3.2. "
331 "Replaceable by Domain1D::setProfile.");
332 size_t np = domain(dom).nPoints();
333 for (size_t n = 0; n < np; n++) {
334 _setValue(dom, comp, n, v);
335 }
336}
337
339{
340 for (size_t n = 0; n < nDomains(); n++) {
341 if (domain(n).type() != "empty") {
342 writelog("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "+domain(n).id()
343 +" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
344 domain(n).show(m_state->data() + start(n));
345 }
346 }
347}
348
350{
351 if (m_xlast_ts.empty()) {
352 throw CanteraError("Sim1D::restoreTimeSteppingSolution",
353 "No successful time steps taken on this grid.");
354 }
356}
357
359{
360 if (m_xlast_ss.empty()) {
361 throw CanteraError("Sim1D::restoreSteadySolution",
362 "No successful steady state solution");
363 }
365 for (size_t n = 0; n < nDomains(); n++) {
366 vector<double>& z = m_grid_last_ss[n];
367 domain(n).setupGrid(z.size(), z.data());
368 }
369}
370
372{
373 for (size_t n = 0; n < nDomains(); n++) {
374 domain(n)._getInitialSoln(m_state->data() + start(n));
375 }
376}
377
379{
380 for (size_t n = 0; n < nDomains(); n++) {
381 domain(n)._finalize(m_state->data() + start(n));
382 }
383}
384
385void Sim1D::solve(int loglevel, bool refine_grid)
386{
387 int new_points = 1;
389 finalize();
390 if (loglevel > 6) {
392 }
393
394 while (new_points > 0) {
395 SteadyStateSystem::solve(loglevel);
396 if (loglevel > 0) {
397 writelog("\nNewton steady-state solve succeeded.\n\n");
398 writelog("Problem solved on [");
399 for (size_t mm = 1; mm < nDomains(); mm+=2) {
400 writelog("{}", domain(mm).nPoints());
401 if (mm + 2 < nDomains()) {
402 writelog(", ");
403 }
404 }
405 writelog("] point grid(s).\n");
406 if (loglevel > 3) {
407 show();
408 }
409 }
410 if (m_steady_callback) {
412 }
413 if (refine_grid) {
414 new_points = refine(loglevel);
415 writeDebugInfo("Regridding", "After regridding", loglevel,
417 } else {
418 debuglog("grid refinement disabled.\n", loglevel);
419 new_points = 0;
420 }
421 }
422 if (new_points < 0) {
423 // If the solver finished after removing grid points, do one final evaluation
424 // of the governing equations to update internal arrays in each domain that may
425 // be used for data saved in output files.
426 for (auto dom : m_dom) {
427 dom->eval(npos, m_state->data() + dom->loc(), m_xnew.data() + dom->loc(),
428 m_mask.data());
429 }
430 }
431}
432
433int Sim1D::refine(int loglevel)
434{
435 int added = 0;
436 int discarded = 0;
437 vector<double> znew, xnew;
438 vector<size_t> dsize;
439
441 m_grid_last_ss.clear();
442
443 for (size_t n = 0; n < nDomains(); n++) {
444 Domain1D& d = domain(n);
445 Refiner& r = d.refiner();
446
447 // Save the old grid corresponding to the converged solution
448 m_grid_last_ss.push_back(d.grid());
449
450 // determine where new points are needed
451 r.analyze(d.grid().size(), d.grid().data(), m_state->data() + start(n));
452
453 if (loglevel > 0) {
454 r.show();
455 }
456
457 added += r.nNewPoints();
458 size_t comp = d.nComponents();
459
460 // loop over points in the current grid
461 size_t npnow = d.nPoints();
462 size_t nstart = znew.size();
463 for (size_t m = 0; m < npnow; m++) {
464 if (r.keepPoint(m)) {
465 // add the current grid point to the new grid
466 znew.push_back(d.z(m));
467
468 // do the same for the solution at this point
469 for (size_t i = 0; i < comp; i++) {
470 xnew.push_back(_value(n, i, m));
471 }
472
473 // now check whether a new point is needed in the interval to
474 // the right of point m, and if so, add entries to znew and xnew
475 // for this new point
476 if (r.newPointNeeded(m) && m + 1 < npnow) {
477 // add new point at midpoint
478 double zmid = 0.5*(d.z(m) + d.z(m+1));
479 znew.push_back(zmid);
480 added++;
481
482 // for each component, linearly interpolate the solution to this
483 // point
484 for (size_t i = 0; i < comp; i++) {
485 double xmid = 0.5*(_value(n, i, m) + _value(n, i, m+1));
486 xnew.push_back(xmid);
487 }
488 }
489 } else {
490 discarded++;
491 if (loglevel > 0) {
492 writelog("refine: discarding point at {}\n", d.z(m));
493 }
494 }
495 }
496 dsize.push_back(znew.size() - nstart);
497 }
498
499 // At this point, the new grid znew and the new solution vector xnew have
500 // been constructed, but the domains themselves have not yet been modified.
501 // Now update each domain with the new grid.
502
503 size_t gridstart = 0, gridsize;
504 for (size_t n = 0; n < nDomains(); n++) {
505 Domain1D& d = domain(n);
506 gridsize = dsize[n];
507 if (gridsize != 0) {
508 d.setupGrid(gridsize, &znew[gridstart]);
509 }
510 gridstart += gridsize;
511 }
512
513 // Replace the current solution vector with the new one
514 *m_state = xnew;
515 resize();
516 finalize();
517 return added || -discarded;
518}
519
521{
522 std::filesystem::remove("debug_sim1d.yaml");
523}
524
525void Sim1D::writeDebugInfo(const string& header_suffix, const string& message,
526 int loglevel, int attempt_counter)
527{
528 string file_header;
529 if (loglevel > 6) {
530 file_header = fmt::format("solution_{}_{}", attempt_counter, header_suffix);
531 save("debug_sim1d.yaml", file_header, message, true);
532 }
533 if (loglevel > 7) {
534 file_header = fmt::format("residual_{}_{}", attempt_counter, header_suffix);
535 saveResidual("debug_sim1d.yaml", file_header, message, true);
536 }
537}
538
540{
541 int np = 0;
542 vector<double> znew, xnew;
543 double zfixed = 0.0;
544 double z1 = 0.0, z2 = 0.0;
545 vector<size_t> dsize;
546
547 for (size_t n = 0; n < nDomains(); n++) {
548 Domain1D& d = domain(n);
549 size_t comp = d.nComponents();
550 size_t mfixed = npos;
551
552 // loop over current grid to determine where new point is needed
553 Flow1D* d_free = dynamic_cast<Flow1D*>(&domain(n));
554 size_t npnow = d.nPoints();
555 size_t nstart = znew.size();
556 if (d_free && d_free->isFree()) {
557 for (size_t m = 0; m < npnow - 1; m++) {
558 bool fixedpt = false;
559 double t1 = _value(n, c_offset_T, m);
560 double t2 = _value(n, c_offset_T, m + 1);
561 // threshold to avoid adding new point too close to existing point
562 double thresh = min(1., 1.e-1 * (t2 - t1));
563 z1 = d.z(m);
564 z2 = d.z(m + 1);
565 if (fabs(t - t1) <= thresh) {
566 zfixed = z1;
567 fixedpt = true;
568 } else if (fabs(t2 - t) <= thresh) {
569 zfixed = z2;
570 fixedpt = true;
571 } else if ((t1 < t) && (t < t2)) {
572 mfixed = m;
573 zfixed = (z1 - z2) / (t1 - t2) * (t - t2) + z2;
574 fixedpt = true;
575 }
576
577 if (fixedpt) {
578 d_free->m_zfixed = zfixed;
579 d_free->m_tfixed = t;
580 break;
581 }
582 }
583 }
584
585 // copy solution domain and push back values
586 for (size_t m = 0; m < npnow; m++) {
587 // add the current grid point to the new grid
588 znew.push_back(d.z(m));
589
590 // do the same for the solution at this point
591 for (size_t i = 0; i < comp; i++) {
592 xnew.push_back(_value(n, i, m));
593 }
594 if (m == mfixed) {
595 // add new point at zfixed (mfixed is not npos)
596 znew.push_back(zfixed);
597 np++;
598 double interp_factor = (zfixed - z2) / (z1 - z2);
599 // for each component, linearly interpolate
600 // the solution to this point
601 for (size_t i = 0; i < comp; i++) {
602 double xmid = interp_factor*(
603 _value(n, i, m) - _value(n, i, m+1)) + _value(n,i,m+1);
604 xnew.push_back(xmid);
605 }
606 }
607 }
608 dsize.push_back(znew.size() - nstart);
609 }
610
611 // At this point, the new grid znew and the new solution vector xnew have
612 // been constructed, but the domains themselves have not yet been modified.
613 // Now update each domain with the new grid.
614 size_t gridstart = 0;
615 for (size_t n = 0; n < nDomains(); n++) {
616 Domain1D& d = domain(n);
617 size_t gridsize = dsize[n];
618 d.setupGrid(gridsize, &znew[gridstart]);
619 gridstart += gridsize;
620 }
621
622 // Replace the current solution vector with the new one
623 *m_state = xnew;
624
625 resize();
626 finalize();
627 return np;
628}
629
631{
632 double t_fixed = std::numeric_limits<double>::quiet_NaN();
633 for (size_t n = 0; n < nDomains(); n++) {
634 Flow1D* d = dynamic_cast<Flow1D*>(&domain(n));
635 if (d && d->isFree() && d->m_tfixed > 0) {
636 t_fixed = d->m_tfixed;
637 break;
638 }
639 }
640 return t_fixed;
641}
642
644{
645 double z_fixed = std::numeric_limits<double>::quiet_NaN();
646 for (size_t n = 0; n < nDomains(); n++) {
647 Flow1D* d = dynamic_cast<Flow1D*>(&domain(n));
648 if (d && d->isFree() && d->m_tfixed > 0) {
649 z_fixed = d->m_zfixed;
650 break;
651 }
652 }
653 return z_fixed;
654}
655
656void Sim1D::setLeftControlPoint(double temperature)
657{
658 bool two_point_domain_found = false;
659 for (size_t n = 0; n < nDomains(); n++) {
660 Domain1D& d = domain(n);
661
662 // Skip if the domain type doesn't match
663 if (d.domainType() != "axisymmetric-flow") {
664 continue;
665 }
666
667 Flow1D& d_axis = dynamic_cast<Flow1D&>(domain(n));
668 size_t np = d_axis.nPoints();
669
670 // Skip if two-point control is not enabled
671 if (!d_axis.twoPointControlEnabled()) {
672 continue;
673 }
674 two_point_domain_found = true;
675
676 double current_val, next_val;
677 for (size_t m = 0; m < np-1; m++) {
678 current_val = _value(n,c_offset_T,m);
679 next_val = _value(n,c_offset_T,m+1);
680 if ((current_val - temperature) * (next_val - temperature) < 0.0) {
681 // Pick the coordinate of the point with the temperature closest
682 // to the desired temperature
683 size_t index = 0;
684 if (std::abs(current_val - temperature) <
685 std::abs(next_val - temperature)) {
686 index = m;
687 } else {
688 index = m+1;
689 }
690 d_axis.setLeftControlPointCoordinate(d_axis.z(index));
692 return;
693 }
694 }
695 }
696
697 if (!two_point_domain_found) {
698 throw CanteraError("Sim1D::setLeftControlPoint",
699 "No domain with two-point control enabled was found.");
700 } else {
701 throw CanteraError("Sim1D::setLeftControlPoint",
702 "No control point with temperature {} was able to be found in the"
703 "flame's temperature range.", temperature);
704 }
705}
706
707void Sim1D::setRightControlPoint(double temperature)
708{
709 bool two_point_domain_found = false;
710 for (size_t n = 0; n < nDomains(); n++) {
711 Domain1D& d = domain(n);
712
713 // Skip if the domain type doesn't match
714 if (d.domainType() != "axisymmetric-flow") {
715 continue;
716 }
717
718 Flow1D& d_axis = dynamic_cast<Flow1D&>(domain(n));
719 size_t np = d_axis.nPoints();
720
721 // Skip if two-point control is not enabled
722 if (!d_axis.twoPointControlEnabled()) {
723 continue;
724 }
725 two_point_domain_found = true;
726
727 double current_val, next_val;
728 for (size_t m = np-1; m > 0; m--) {
729 current_val = _value(n,c_offset_T,m);
730 next_val = _value(n,c_offset_T,m-1);
731 if ((current_val - temperature) * (next_val - temperature) < 0.0) {
732 // Pick the coordinate of the point with the temperature closest
733 // to the desired temperature
734 size_t index = 0;
735 if (std::abs(current_val - temperature) <
736 std::abs(next_val - temperature)) {
737 index = m;
738 } else {
739 index = m-1;
740 }
741 d_axis.setRightControlPointCoordinate(d_axis.z(index));
743 return;
744 }
745 }
746 }
747
748 if (!two_point_domain_found) {
749 throw CanteraError("Sim1D::setRightControlPoint",
750 "No domain with two-point control enabled was found.");
751 } else {
752 throw CanteraError("Sim1D::setRightControlPoint",
753 "No control point with temperature {} was able to be found in the"
754 "flame's temperature range.", temperature);
755 }
756
757}
758
759void Sim1D::setRefineCriteria(int dom, double ratio,
760 double slope, double curve, double prune)
761{
762 if (dom >= 0) {
763 Refiner& r = domain(dom).refiner();
764 r.setCriteria(ratio, slope, curve, prune);
765 } else {
766 for (size_t n = 0; n < nDomains(); n++) {
767 Refiner& r = domain(n).refiner();
768 r.setCriteria(ratio, slope, curve, prune);
769 }
770 }
771}
772
773vector<double> Sim1D::getRefineCriteria(int dom)
774{
775 if (dom >= 0) {
776 Refiner& r = domain(dom).refiner();
777 return r.getCriteria();
778 } else {
779 throw CanteraError("Sim1D::getRefineCriteria",
780 "Must specify domain to get criteria from");
781 }
782}
783
784void Sim1D::setGridMin(int dom, double gridmin)
785{
786 if (dom >= 0) {
787 Refiner& r = domain(dom).refiner();
788 r.setGridMin(gridmin);
789 } else {
790 for (size_t n = 0; n < nDomains(); n++) {
791 Refiner& r = domain(n).refiner();
792 r.setGridMin(gridmin);
793 }
794 }
795}
796
797void Sim1D::setMaxGridPoints(int dom, int npoints)
798{
799 if (dom >= 0) {
800 Refiner& r = domain(dom).refiner();
801 r.setMaxPoints(npoints);
802 } else {
803 for (size_t n = 0; n < nDomains(); n++) {
804 Refiner& r = domain(n).refiner();
805 r.setMaxPoints(npoints);
806 }
807 }
808}
809
810size_t Sim1D::maxGridPoints(size_t dom)
811{
812 Refiner& r = domain(dom).refiner();
813 return r.maxPoints();
814}
815
816double Sim1D::jacobian(int i, int j)
817{
818 warn_deprecated("Sim1D::jacobian", "To be removed after Cantera 3.2.");
819 return OneDim::jacobian().value(i,j);
820}
821
823{
824 OneDim::evalSSJacobian(m_state->data(), m_xnew.data());
825}
826
827void Sim1D::solveAdjoint(const double* b, double* lambda)
828{
829 for (auto& D : m_dom) {
830 D->forceFullUpdate(true);
831 }
833 for (auto& D : m_dom) {
834 D->forceFullUpdate(false);
835 }
836
837 auto multijac = dynamic_pointer_cast<MultiJac>(m_jac);
838 if (!multijac) {
839 throw CanteraError("Sim1D::solveAdjoint", "Banded (MultiJac) required");
840 }
841 // Form J^T
842 size_t bw = bandwidth();
843 BandMatrix Jt(size(), bw, bw);
844 for (size_t i = 0; i < size(); i++) {
845 size_t j1 = (i > bw) ? i - bw : 0;
846 size_t j2 = (i + bw >= size()) ? size() - 1: i + bw;
847 for (size_t j = j1; j <= j2; j++) {
848 Jt(j,i) = multijac->value(i,j);
849 }
850 }
851
852 Jt.solve(b, lambda);
853}
854
856{
858 m_xnew.resize(size(), 0.0);
859}
860
861shared_ptr<Sim1D> newSim1D(vector<shared_ptr<Domain1D>>& domains)
862{
863 return make_shared<Sim1D>(domains);
864}
865
866}
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
double getDouble(const string &key, double default_) const
If key exists, return it as a double, otherwise return default_.
Definition AnyMap.cpp:1580
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
static void clearCachedFile(const string &filename)
Remove the specified file from the input cache if it is present.
Definition AnyMap.cpp:1816
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition AnyMap.cpp:1841
A class for banded matrices, involving matrix inversion processes.
Definition BandMatrix.h:37
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.
Definition Domain1D.h:29
size_t nComponents() const
Number of components at each grid point.
Definition Domain1D.h:148
virtual void _finalize(const double *x)
In some cases, a domain may need to set parameters that depend on the initial solution estimate.
Definition Domain1D.h:725
void setupGrid(const vector< double > &grid)
Set up initial grid.
Definition Domain1D.cpp:212
vector< double > & grid()
Access the array of grid coordinates [m].
Definition Domain1D.h:682
double zmin() const
Get the coordinate [m] of the first (leftmost) grid point in this domain.
Definition Domain1D.h:664
size_t nPoints() const
Number of grid points in this domain.
Definition Domain1D.h:176
virtual string domainType() const
Domain type flag.
Definition Domain1D.h:45
double z(size_t jlocal) const
Get the coordinate [m] of the point with local index jlocal
Definition Domain1D.h:659
Refiner & refiner()
Return a reference to the grid refiner.
Definition Domain1D.h:143
virtual void show(const double *x)
Print the solution.
Definition Domain1D.cpp:237
virtual string componentName(size_t n) const
Name of component n. May be overloaded.
Definition Domain1D.cpp:67
string type() const
String indicating the domain implemented.
Definition Domain1D.h:50
double zmax() const
Get the coordinate [m] of the last (rightmost) grid point in this domain.
Definition Domain1D.h:669
virtual void _getInitialSoln(double *x)
Writes some or all initial solution values into the global solution array, beginning at the location ...
Definition Domain1D.cpp:287
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.
Definition Domain1D.h:368
virtual size_t loc(size_t j=0) const
Location of the start of the local solution vector in the global solution vector.
Definition Domain1D.h:585
This class represents 1D flow domains that satisfy the one-dimensional similarity solution for chemic...
Definition Flow1D.h:47
void setLeftControlPointTemperature(double temperature)
Sets the temperature of the left control point.
Definition Flow1D.cpp:1367
void setLeftControlPointCoordinate(double z_left)
Sets the coordinate of the left control point.
Definition Flow1D.cpp:1382
void setRightControlPointCoordinate(double z_right)
Sets the coordinate of the right control point.
Definition Flow1D.cpp:1437
bool twoPointControlEnabled() const
Returns the status of the two-point control.
Definition Flow1D.h:347
void setRightControlPointTemperature(double temperature)
Sets the temperature of the right control point.
Definition Flow1D.cpp:1422
double m_tfixed
Temperature at the point used to fix the flame location.
Definition Flow1D.h:1023
double m_zfixed
Location of the point where temperature is fixed.
Definition Flow1D.h:1020
bool isFree() const
Retrieve flag indicating whether flow is freely propagating.
Definition Flow1D.h:379
virtual double eval(double t) const
Evaluate the function.
Definition Func1.cpp:28
Container class for multiple-domain 1D problems.
Definition OneDim.h:27
size_t start(size_t i) const
The index of the start of domain i in the solution vector.
Definition OneDim.h:104
void resize() override
Call to set the size of internal data structures after first defining the system or if the problem si...
Definition OneDim.cpp:186
void eval(size_t j, double *x, double *r, double rdt=-1.0, int count=1)
Evaluate the multi-domain residual function.
Definition OneDim.cpp:251
size_t nDomains() const
Number of domains.
Definition OneDim.h:73
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...
Definition OneDim.cpp:39
Domain1D & domain(size_t i) const
Return a reference to domain i.
Definition OneDim.h:78
vector< shared_ptr< Domain1D > > m_dom
All domains comprising the system.
Definition OneDim.h:259
Refine Domain1D grids so that profiles satisfy adaptation tolerances.
Definition refine.h:17
bool newPointNeeded(size_t j)
Returns true if a new grid point is needed to the right of grid index j.
Definition refine.h:130
size_t maxPoints() const
Returns the maximum number of points allowed in the domain.
Definition refine.h:81
int nNewPoints()
Returns the number of new grid points that were needed.
Definition refine.h:109
void show()
Displays the results of the grid refinement analysis.
Definition refine.cpp:216
vector< double > getCriteria()
Get the grid refinement criteria.
Definition refine.h:60
void setMaxPoints(int npmax)
Set the maximum number of points allowed in the domain.
Definition refine.h:76
void setCriteria(double ratio=10.0, double slope=0.8, double curve=0.8, double prune=-0.1)
Set grid refinement criteria.
Definition refine.cpp:21
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...
Definition refine.cpp:43
bool keepPoint(size_t j)
Returns true if the grid point at index j should be kept.
Definition refine.h:139
void setGridMin(double gridmin)
Set the minimum allowable spacing between adjacent grid points [m].
Definition refine.h:86
void getInitialSoln()
Get the initial value of the system state from each domain in the simulation.
Definition Sim1D.cpp:371
void restoreTimeSteppingSolution()
Set the current solution vector to the last successful time-stepping solution.
Definition Sim1D.cpp:349
void resize() override
Call to set the size of internal data structures after first defining the system or if the problem si...
Definition Sim1D.cpp:855
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.
Definition Sim1D.cpp:147
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.
Definition Sim1D.cpp:77
double fixedTemperatureLocation()
Return location of the point where temperature is fixed.
Definition Sim1D.cpp:643
vector< vector< double > > m_grid_last_ss
the grids for each domain after the last successful steady-state solve (stored before grid refinement...
Definition Sim1D.h:432
double _value(size_t dom, size_t comp, size_t localPoint) const
Get one entry in the solution vector.
Definition Sim1D.cpp:61
void finalize()
Calls method _finalize in each domain.
Definition Sim1D.cpp:378
int refine(int loglevel=0)
Refine the grid in all domains.
Definition Sim1D.cpp:433
void show()
Show logging information on current solution for all domains.
Definition Sim1D.cpp:338
double fixedTemperature()
Return temperature at the point used to fix the flame location.
Definition Sim1D.cpp:630
void clearDebugFile() override
Deletes a debug_sim1d.yaml file if it exists.
Definition Sim1D.cpp:520
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 ...
Definition Sim1D.cpp:69
vector< double > m_xlast_ss
the solution vector after the last successful steady-state solve (stored before grid refinement)
Definition Sim1D.h:428
void _restore(const string &fname, const string &name)
Retrieve data from a previously saved simulation.
Definition Sim1D.cpp:323
void setMaxGridPoints(int dom, int npoints)
Set the maximum number of grid points in the domain.
Definition Sim1D.cpp:797
int setFixedTemperature(double t)
Add node for fixed temperature point of freely propagating flame.
Definition Sim1D.cpp:539
void setInitialGuess(const string &component, vector< double > &locs, vector< double > &vals)
Set initial guess for one component for all domains.
Definition Sim1D.cpp:37
void solve(int loglevel=0, bool refine_grid=true)
Performs the hybrid Newton steady/time-stepping solution.
Definition Sim1D.cpp:385
void evalSSJacobian()
Evaluate the Jacobian in steady-state mode.
Definition Sim1D.cpp:822
void solveAdjoint(const double *b, double *lambda)
Solve the equation .
Definition Sim1D.cpp:827
AnyMap restore(const string &fname, const string &name)
Retrieve data and settings from a previously saved simulation.
Definition Sim1D.cpp:246
Func1 * m_steady_callback
User-supplied function called after a successful steady-state solve.
Definition Sim1D.h:435
void restoreSteadySolution()
Set the current solution vector and grid to the last successful steady- state solution.
Definition Sim1D.cpp:358
size_t maxGridPoints(size_t dom)
Get the maximum number of grid points in this domain.
Definition Sim1D.cpp:810
void setFlatProfile(size_t dom, size_t comp, double v)
Set component 'comp' of domain 'dom' to value 'v' at all points.
Definition Sim1D.cpp:328
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.
Definition Sim1D.cpp:525
void setRightControlPoint(double temperature)
Set the right control point location using the specified temperature.
Definition Sim1D.cpp:707
double value(size_t dom, size_t comp, size_t localPoint) const
Get one entry in the solution vector.
Definition Sim1D.h:82
vector< double > getRefineCriteria(int dom)
Get the grid refinement criteria.
Definition Sim1D.cpp:773
Sim1D()
Default constructor.
Definition Sim1D.h:29
void setGridMin(int dom, double gridmin)
Set the minimum grid spacing in the specified domain(s).
Definition Sim1D.cpp:784
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.
Definition Sim1D.cpp:759
void _setValue(size_t dom, size_t comp, size_t localPoint, double value)
Set a single value in the solution vector.
Definition Sim1D.cpp:53
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.
Definition Sim1D.cpp:98
void setLeftControlPoint(double temperature)
Set the left control point location using the specified temperature.
Definition Sim1D.cpp:656
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.
Definition OneDim.cpp:126
#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.
Definition global.h:159
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:176
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
double linearInterp(double x, const vector< double > &xpts, const vector< double > &fpts)
Linearly interpolate a function defined on a discrete grid.
Definition funcs.cpp:13
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Definition global.h:268
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180
shared_ptr< Sim1D > newSim1D(vector< shared_ptr< Domain1D > > &domains)
Create a Sim1D object with a list of domains.
Definition Sim1D.cpp:861
@ c_offset_T
temperature [kelvin]
Definition Flow1D.h:28
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997
Contains declarations for string manipulation functions within Cantera.