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