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