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