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