Cantera  3.2.0a4
Loading...
Searching...
No Matches
Reactor.cpp
Go to the documentation of this file.
1//! @file Reactor.cpp A zero-dimensional reactor
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
16
17#include <boost/math/tools/roots.hpp>
18
19using namespace std;
20namespace bmt = boost::math::tools;
21
22namespace Cantera
23{
24
25// TODO: After Cantera 3.2, this method can be replaced by delegating to
26// Reactor::Reactor(sol, true, name)
27Reactor::Reactor(shared_ptr<Solution> sol, const string& name)
28 : ReactorBase(sol, name)
29{
30 m_kin = m_solution->kinetics().get();
31 if (m_kin->nReactions() == 0) {
32 setChemistry(false);
33 } else {
34 setChemistry(true);
35 }
36 m_vol = 1.0; // By default, the volume is set to 1.0 m^3.
37}
38
39Reactor::Reactor(shared_ptr<Solution> sol, bool clone, const string& name)
40 : ReactorBase(sol, clone, name)
41{
42 m_kin = m_solution->kinetics().get();
43 if (m_kin->nReactions() == 0) {
44 setChemistry(false);
45 } else {
46 setChemistry(true);
47 }
48 m_vol = 1.0; // By default, the volume is set to 1.0 m^3.
49}
50
51void Reactor::setDerivativeSettings(AnyMap& settings)
52{
53 m_kin->setDerivativeSettings(settings);
54 // translate settings to surfaces
55 for (auto S : m_surfaces) {
56 S->kinetics()->setDerivativeSettings(settings);
57 }
58}
59
60void Reactor::setKinetics(Kinetics& kin)
61{
62 warn_deprecated("Reactor::setKinetics",
63 "After Cantera 3.2, a change of reactor contents after instantiation "
64 "will be disabled.");
65 m_kin = &kin;
66 if (m_kin->nReactions() == 0) {
67 setChemistry(false);
68 } else {
69 setChemistry(true);
70 }
71}
72
73void Reactor::getState(double* y)
74{
75 if (m_thermo == 0) {
76 throw CanteraError("Reactor::getState",
77 "Error: reactor is empty.");
78 }
79 m_thermo->restoreState(m_state);
80
81 // set the first component to the total mass
82 m_mass = m_thermo->density() * m_vol;
83 y[0] = m_mass;
84
85 // set the second component to the total volume
86 y[1] = m_vol;
87
88 // set the third component to the total internal energy
89 y[2] = m_thermo->intEnergy_mass() * m_mass;
90
91 // set components y+3 ... y+K+2 to the mass fractions of each species
92 m_thermo->getMassFractions(y+3);
93
94 // set the remaining components to the surface species
95 // coverages on the walls
96 getSurfaceInitialConditions(y + m_nsp + 3);
97}
98
99void Reactor::getSurfaceInitialConditions(double* y)
100{
101 size_t loc = 0;
102 for (auto& S : m_surfaces) {
103 S->getCoverages(y + loc);
104 loc += S->thermo()->nSpecies();
105 }
106}
107
108void Reactor::initialize(double t0)
109{
110 if (!m_thermo || (m_chem && !m_kin)) {
111 throw CanteraError("Reactor::initialize", "Reactor contents not set"
112 " for reactor '" + m_name + "'.");
113 }
114 m_thermo->restoreState(m_state);
115 m_sdot.resize(m_nsp, 0.0);
116 m_wdot.resize(m_nsp, 0.0);
117 updateConnected(true);
118
119 for (size_t n = 0; n < m_wall.size(); n++) {
120 WallBase* W = m_wall[n];
121 W->initialize();
122 }
123
124 m_nv = m_nsp + 3;
125 m_nv_surf = 0;
126 size_t maxnt = 0;
127 for (auto& S : m_surfaces) {
128 m_nv_surf += S->thermo()->nSpecies();
129 size_t nt = S->kinetics()->nTotalSpecies();
130 maxnt = std::max(maxnt, nt);
131 }
132 m_nv += m_nv_surf;
133 m_work.resize(maxnt);
134}
135
136size_t Reactor::nSensParams() const
137{
138 size_t ns = m_sensParams.size();
139 for (auto& S : m_surfaces) {
140 ns += S->nSensParams();
141 }
142 return ns;
143}
144
145void Reactor::updateState(double* y)
146{
147 // The components of y are [0] the total mass, [1] the total volume,
148 // [2] the total internal energy, [3...K+3] are the mass fractions of each
149 // species, and [K+3...] are the coverages of surface species on each wall.
150 m_mass = y[0];
151 m_vol = y[1];
152 m_thermo->setMassFractions_NoNorm(y+3);
153
154 if (m_energy) {
155 double U = y[2];
156 // Residual function: error in internal energy as a function of T
157 auto u_err = [this, U](double T) {
158 m_thermo->setState_TD(T, m_mass / m_vol);
159 return m_thermo->intEnergy_mass() * m_mass - U;
160 };
161
162 double T = m_thermo->temperature();
163 boost::uintmax_t maxiter = 100;
164 pair<double, double> TT;
165 try {
166 TT = bmt::bracket_and_solve_root(
167 u_err, T, 1.2, true, bmt::eps_tolerance<double>(48), maxiter);
168 } catch (std::exception&) {
169 // Try full-range bisection if bracketing fails (for example, near
170 // temperature limits for the phase's equation of state)
171 try {
172 TT = bmt::bisect(u_err, m_thermo->minTemp(), m_thermo->maxTemp(),
173 bmt::eps_tolerance<double>(48), maxiter);
174 } catch (std::exception& err2) {
175 // Set m_thermo back to a reasonable state if root finding fails
176 m_thermo->setState_TD(T, m_mass / m_vol);
177 throw CanteraError("Reactor::updateState",
178 "{}\nat U = {}, rho = {}", err2.what(), U, m_mass / m_vol);
179 }
180 }
181 if (fabs(TT.first - TT.second) > 1e-7*TT.first) {
182 throw CanteraError("Reactor::updateState", "root finding failed");
183 }
184 m_thermo->setState_TD(TT.second, m_mass / m_vol);
185 } else {
186 m_thermo->setDensity(m_mass/m_vol);
187 }
188
189 updateConnected(true);
190 updateSurfaceState(y + m_nsp + 3);
191}
192
193void Reactor::updateSurfaceState(double* y)
194{
195 size_t loc = 0;
196 for (auto& S : m_surfaces) {
197 S->setCoverages(y+loc);
198 loc += S->thermo()->nSpecies();
199 }
200}
201
202void Reactor::updateConnected(bool updatePressure) {
203 // save parameters needed by other connected reactors
204 m_enthalpy = m_thermo->enthalpy_mass();
205 if (updatePressure) {
206 m_pressure = m_thermo->pressure();
207 }
208 try {
209 m_intEnergy = m_thermo->intEnergy_mass();
210 } catch (NotImplementedError&) {
211 m_intEnergy = NAN;
212 }
213 m_thermo->saveState(m_state);
214
215 // Update the mass flow rate of connected flow devices
216 double time = 0.0;
217 if (m_net != nullptr) {
218 time = (timeIsIndependent()) ? m_net->time() : m_net->distance();
219 }
220 for (size_t i = 0; i < m_outlet.size(); i++) {
221 m_outlet[i]->setSimTime(time);
222 m_outlet[i]->updateMassFlowRate(time);
223 }
224 for (size_t i = 0; i < m_inlet.size(); i++) {
225 m_inlet[i]->setSimTime(time);
226 m_inlet[i]->updateMassFlowRate(time);
227 }
228 for (size_t i = 0; i < m_wall.size(); i++) {
229 m_wall[i]->setSimTime(time);
230 }
231}
232
233void Reactor::eval(double time, double* LHS, double* RHS)
234{
235 double& dmdt = RHS[0];
236 double* mdYdt = RHS + 3; // mass * dY/dt
237
238 evalWalls(time);
239 m_thermo->restoreState(m_state);
240 const vector<double>& mw = m_thermo->molecularWeights();
241 const double* Y = m_thermo->massFractions();
242
243 evalSurfaces(LHS + m_nsp + 3, RHS + m_nsp + 3, m_sdot.data());
244 // mass added to gas phase from surface reactions
245 double mdot_surf = dot(m_sdot.begin(), m_sdot.end(), mw.begin());
246 dmdt = mdot_surf;
247
248 // volume equation
249 RHS[1] = m_vdot;
250
251 if (m_chem) {
252 m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot"
253 }
254
255 for (size_t k = 0; k < m_nsp; k++) {
256 // production in gas phase and from surfaces
257 mdYdt[k] = (m_wdot[k] * m_vol + m_sdot[k]) * mw[k];
258 // dilution by net surface mass flux
259 mdYdt[k] -= Y[k] * mdot_surf;
260 LHS[k+3] = m_mass;
261 }
262
263 // Energy equation.
264 // @f[
265 // \dot U = -P\dot V + A \dot q + \dot m_{in} h_{in} - \dot m_{out} h.
266 // @f]
267 if (m_energy) {
268 RHS[2] = - m_thermo->pressure() * m_vdot + m_Qdot;
269 } else {
270 RHS[2] = 0.0;
271 }
272
273 // add terms for outlets
274 for (auto outlet : m_outlet) {
275 double mdot = outlet->massFlowRate();
276 dmdt -= mdot; // mass flow out of system
277 if (m_energy) {
278 RHS[2] -= mdot * m_enthalpy;
279 }
280 }
281
282 // add terms for inlets
283 for (auto inlet : m_inlet) {
284 double mdot = inlet->massFlowRate();
285 dmdt += mdot; // mass flow into system
286 for (size_t n = 0; n < m_nsp; n++) {
287 double mdot_spec = inlet->outletSpeciesMassFlowRate(n);
288 // flow of species into system and dilution by other species
289 mdYdt[n] += (mdot_spec - mdot * Y[n]);
290 }
291 if (m_energy) {
292 RHS[2] += mdot * inlet->enthalpy_mass();
293 }
294 }
295}
296
297void Reactor::evalWalls(double t)
298{
299 // time is currently unused
300 m_vdot = 0.0;
301 m_Qdot = 0.0;
302 for (size_t i = 0; i < m_wall.size(); i++) {
303 int f = 2 * m_lr[i] - 1;
304 m_vdot -= f * m_wall[i]->expansionRate();
305 m_Qdot += f * m_wall[i]->heatRate();
306 }
307}
308
309void Reactor::evalSurfaces(double* LHS, double* RHS, double* sdot)
310{
311 fill(sdot, sdot + m_nsp, 0.0);
312 size_t loc = 0; // offset into ydot
313
314 for (auto S : m_surfaces) {
315 Kinetics* kin = S->kinetics();
316 SurfPhase* surf = S->thermo();
317
318 double rs0 = 1.0/surf->siteDensity();
319 size_t nk = surf->nSpecies();
320 double sum = 0.0;
321 S->restoreState();
322 kin->getNetProductionRates(&m_work[0]);
323 for (size_t k = 1; k < nk; k++) {
324 RHS[loc + k] = m_work[k] * rs0 * surf->size(k);
325 sum -= RHS[loc + k];
326 }
327 RHS[loc] = sum;
328 loc += nk;
329
330 size_t bulkloc = kin->kineticsSpeciesIndex(m_thermo->speciesName(0));
331 double wallarea = S->area();
332 for (size_t k = 0; k < m_nsp; k++) {
333 sdot[k] += m_work[bulkloc + k] * wallarea;
334 }
335 }
336}
337
338vector<size_t> Reactor::steadyConstraints() const
339{
340 if (!energyEnabled()) {
341 throw CanteraError("Reactor::steadyConstraints", "Steady state solver cannot"
342 " be used with {0} when energy equation is disabled."
343 "\nConsider using IdealGas{0} instead.\n"
344 "See https://github.com/Cantera/enhancements/issues/234", type());
345 }
346 if (nSurfs() != 0) {
347 throw CanteraError("Reactor::steadyConstraints", "Steady state solver cannot"
348 " currently be used when reactor surfaces are present.\n"
349 "See https://github.com/Cantera/enhancements/issues/234.");
350 }
351 return {1}; // volume
352}
353
354Eigen::SparseMatrix<double> Reactor::finiteDifferenceJacobian()
355{
356 if (m_nv == 0) {
357 throw CanteraError("Reactor::finiteDifferenceJacobian",
358 "Reactor must be initialized first.");
359 }
360 // clear former jacobian elements
361 m_jac_trips.clear();
362
363 Eigen::ArrayXd yCurrent(m_nv);
364 getState(yCurrent.data());
365 double time = (m_net != nullptr) ? m_net->time() : 0.0;
366
367 Eigen::ArrayXd yPerturbed = yCurrent;
368 Eigen::ArrayXd lhsPerturbed(m_nv), lhsCurrent(m_nv);
369 Eigen::ArrayXd rhsPerturbed(m_nv), rhsCurrent(m_nv);
370 lhsCurrent = 1.0;
371 rhsCurrent = 0.0;
372 updateState(yCurrent.data());
373 eval(time, lhsCurrent.data(), rhsCurrent.data());
374
375 double rel_perturb = std::sqrt(std::numeric_limits<double>::epsilon());
376 double atol = (m_net != nullptr) ? m_net->atol() : 1e-15;
377
378 for (size_t j = 0; j < m_nv; j++) {
379 yPerturbed = yCurrent;
380 double delta_y = std::max(std::abs(yCurrent[j]), 1000 * atol) * rel_perturb;
381 yPerturbed[j] += delta_y;
382
383 updateState(yPerturbed.data());
384 lhsPerturbed = 1.0;
385 rhsPerturbed = 0.0;
386 eval(time, lhsPerturbed.data(), rhsPerturbed.data());
387
388 // d ydot_i/dy_j
389 for (size_t i = 0; i < m_nv; i++) {
390 double ydotPerturbed = rhsPerturbed[i] / lhsPerturbed[i];
391 double ydotCurrent = rhsCurrent[i] / lhsCurrent[i];
392 if (ydotCurrent != ydotPerturbed) {
393 m_jac_trips.emplace_back(
394 static_cast<int>(i), static_cast<int>(j),
395 (ydotPerturbed - ydotCurrent) / delta_y);
396 }
397 }
398 }
399 updateState(yCurrent.data());
400
401 Eigen::SparseMatrix<double> jac(m_nv, m_nv);
402 jac.setFromTriplets(m_jac_trips.begin(), m_jac_trips.end());
403 return jac;
404}
405
406
407void Reactor::evalSurfaces(double* RHS, double* sdot)
408{
409 fill(sdot, sdot + m_nsp, 0.0);
410 size_t loc = 0; // offset into ydot
411
412 for (auto S : m_surfaces) {
413 Kinetics* kin = S->kinetics();
414 SurfPhase* surf = S->thermo();
415
416 double rs0 = 1.0/surf->siteDensity();
417 size_t nk = surf->nSpecies();
418 double sum = 0.0;
419 S->restoreState();
420 kin->getNetProductionRates(&m_work[0]);
421 for (size_t k = 1; k < nk; k++) {
422 RHS[loc + k] = m_work[k] * rs0 * surf->size(k);
423 sum -= RHS[loc + k];
424 }
425 RHS[loc] = sum;
426 loc += nk;
427
428 size_t bulkloc = kin->kineticsSpeciesIndex(m_thermo->speciesName(0));
429 double wallarea = S->area();
430 for (size_t k = 0; k < m_nsp; k++) {
431 sdot[k] += m_work[bulkloc + k] * wallarea;
432 }
433 }
434}
435
436void Reactor::addSensitivityReaction(size_t rxn)
437{
438 if (!m_chem || rxn >= m_kin->nReactions()) {
439 throw CanteraError("Reactor::addSensitivityReaction",
440 "Reaction number out of range ({})", rxn);
441 }
442
443 size_t p = network().registerSensitivityParameter(
444 name()+": "+m_kin->reaction(rxn)->equation(), 1.0, 1.0);
445 m_sensParams.emplace_back(
446 SensitivityParameter{rxn, p, 1.0, SensParameterType::reaction});
447}
448
449void Reactor::addSensitivitySpeciesEnthalpy(size_t k)
450{
451 if (k >= m_thermo->nSpecies()) {
452 throw CanteraError("Reactor::addSensitivitySpeciesEnthalpy",
453 "Species index out of range ({})", k);
454 }
455
456 size_t p = network().registerSensitivityParameter(
457 name() + ": " + m_thermo->speciesName(k) + " enthalpy",
458 0.0, GasConstant * 298.15);
459 m_sensParams.emplace_back(
460 SensitivityParameter{k, p, m_thermo->Hf298SS(k),
461 SensParameterType::enthalpy});
462}
463
464size_t Reactor::speciesIndex(const string& nm) const
465{
466 // check for a gas species name
467 size_t k = m_thermo->speciesIndex(nm);
468 if (k != npos) {
469 return k;
470 }
471
472 // check for a wall species
473 size_t offset = m_nsp;
474 for (auto& S : m_surfaces) {
475 ThermoPhase* th = S->thermo();
476 k = th->speciesIndex(nm);
477 if (k != npos) {
478 return k + offset;
479 } else {
480 offset += th->nSpecies();
481 }
482 }
483 return npos;
484}
485
486size_t Reactor::componentIndex(const string& nm) const
487{
488 size_t k = speciesIndex(nm);
489 if (k != npos) {
490 return k + 3;
491 } else if (nm == "mass") {
492 return 0;
493 } else if (nm == "volume") {
494 return 1;
495 } else if (nm == "int_energy") {
496 return 2;
497 } else {
498 return npos;
499 }
500}
501
502string Reactor::componentName(size_t k) {
503 if (k == 0) {
504 return "mass";
505 } else if (k == 1) {
506 return "volume";
507 } else if (k == 2) {
508 return "int_energy";
509 } else if (k >= 3 && k < neq()) {
510 k -= 3;
511 if (k < m_thermo->nSpecies()) {
512 return m_thermo->speciesName(k);
513 } else {
514 k -= m_thermo->nSpecies();
515 }
516 for (auto& S : m_surfaces) {
517 ThermoPhase* th = S->thermo();
518 if (k < th->nSpecies()) {
519 return th->speciesName(k);
520 } else {
521 k -= th->nSpecies();
522 }
523 }
524 }
525 throw CanteraError("Reactor::componentName", "Index is out of bounds.");
526}
527
528double Reactor::upperBound(size_t k) const {
529 if (k == 0) {
530 return BigNumber; // mass
531 } else if (k == 1) {
532 return BigNumber; // volume
533 } else if (k == 2) {
534 return BigNumber; // internal energy
535 } else if (k >= 3 && k < m_nv) {
536 return 1.0; // species mass fraction or surface coverage
537 } else {
538 throw CanteraError("Reactor::upperBound", "Index {} is out of bounds.", k);
539 }
540}
541
542double Reactor::lowerBound(size_t k) const {
543 if (k == 0) {
544 return 0; // mass
545 } else if (k == 1) {
546 return 0; // volume
547 } else if (k == 2) {
548 return -BigNumber; // internal energy
549 } else if (k >= 3 && k < m_nv) {
550 return -Tiny; // species mass fraction or surface coverage
551 } else {
552 throw CanteraError("Reactor::lowerBound", "Index {} is out of bounds.", k);
553 }
554}
555
556void Reactor::resetBadValues(double* y) {
557 for (size_t k = 3; k < m_nv; k++) {
558 y[k] = std::max(y[k], 0.0);
559 }
560}
561
562void Reactor::applySensitivity(double* params)
563{
564 if (!params) {
565 return;
566 }
567 for (auto& p : m_sensParams) {
568 if (p.type == SensParameterType::reaction) {
569 p.value = m_kin->multiplier(p.local);
570 m_kin->setMultiplier(p.local, p.value*params[p.global]);
571 } else if (p.type == SensParameterType::enthalpy) {
572 m_thermo->modifyOneHf298SS(p.local, p.value + params[p.global]);
573 }
574 }
575 for (auto& S : m_surfaces) {
576 S->setSensitivityParameters(params);
577 }
578 m_thermo->invalidateCache();
579 if (m_kin) {
580 m_kin->invalidateCache();
581 }
582}
583
584void Reactor::resetSensitivity(double* params)
585{
586 if (!params) {
587 return;
588 }
589 for (auto& p : m_sensParams) {
590 if (p.type == SensParameterType::reaction) {
591 m_kin->setMultiplier(p.local, p.value);
592 } else if (p.type == SensParameterType::enthalpy) {
593 m_thermo->resetHf298(p.local);
594 }
595 }
596 for (auto& S : m_surfaces) {
597 S->resetSensitivityParameters();
598 }
599 m_thermo->invalidateCache();
600 if (m_kin) {
601 m_kin->invalidateCache();
602 }
603}
604
605void Reactor::setAdvanceLimits(const double *limits)
606{
607 if (m_thermo == 0) {
608 throw CanteraError("Reactor::setAdvanceLimits",
609 "Error: reactor is empty.");
610 }
611 m_advancelimits.assign(limits, limits + m_nv);
612
613 // resize to zero length if no limits are set
614 if (std::none_of(m_advancelimits.begin(), m_advancelimits.end(),
615 [](double val){return val>0;})) {
616 m_advancelimits.resize(0);
617 }
618}
619
620bool Reactor::getAdvanceLimits(double *limits) const
621{
622 bool has_limit = hasAdvanceLimits();
623 if (has_limit) {
624 std::copy(m_advancelimits.begin(), m_advancelimits.end(), limits);
625 } else {
626 std::fill(limits, limits + m_nv, -1.0);
627 }
628 return has_limit;
629}
630
631void Reactor::setAdvanceLimit(const string& nm, const double limit)
632{
633 size_t k = componentIndex(nm);
634 if (k == npos) {
635 throw CanteraError("Reactor::setAdvanceLimit", "No component named '{}'", nm);
636 }
637
638 if (m_thermo == 0) {
639 throw CanteraError("Reactor::setAdvanceLimit",
640 "Error: reactor is empty.");
641 }
642 if (m_nv == 0) {
643 if (m_net == 0) {
644 throw CanteraError("Reactor::setAdvanceLimit",
645 "Cannot set limit on a reactor that is not "
646 "assigned to a ReactorNet object.");
647 } else {
648 m_net->initialize();
649 }
650 } else if (k > m_nv) {
651 throw CanteraError("Reactor::setAdvanceLimit",
652 "Index out of bounds.");
653 }
654 m_advancelimits.resize(m_nv, -1.0);
655 m_advancelimits[k] = limit;
656
657 // resize to zero length if no limits are set
658 if (std::none_of(m_advancelimits.begin(), m_advancelimits.end(),
659 [](double val){return val>0;})) {
660 m_advancelimits.resize(0);
661 }
662}
663
664}
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Header file for class ReactorSurface.
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase,...
Header file for base class WallBase.
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
Base class for exceptions thrown by Cantera classes.
Public interface for kinetics managers.
Definition Kinetics.h:126
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition Kinetics.h:282
virtual void getNetProductionRates(double *wdot)
Species net production rates [kmol/m^3/s or kmol/m^2/s].
Definition Kinetics.cpp:428
An error indicating that an unimplemented function has been called.
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:232
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:142
size_t speciesIndex(const string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:129
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
Definition SurfPhase.h:98
double size(size_t k) const
Returns the number of sites occupied by one molecule of species k.
Definition SurfPhase.h:221
double siteDensity() const
Returns the site density.
Definition SurfPhase.h:216
Base class for a phase with thermodynamic properties.
Base class for 'walls' (walls, pistons, etc.) connecting reactors.
Definition Wall.h:23
virtual void initialize()
Called just before the start of integration.
Definition Wall.h:68
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:120
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
const double Tiny
Small number to compare differences of mole fractions against.
Definition ct_defs.h:173
offset
Offsets of solution components in the 1D solution array.
Definition Flow1D.h:25
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
const double BigNumber
largest number to compare to inf.
Definition ct_defs.h:160
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...