Skip to content

Commit

Permalink
[Doc] Revise science docs based on review suggestions
Browse files Browse the repository at this point in the history
Co-authored-by: Bryan Weber <bryan.w.weber@gmail.com>
  • Loading branch information
speth and bryanwweber committed Jan 9, 2024
1 parent c5b0200 commit 7aa65e5
Show file tree
Hide file tree
Showing 19 changed files with 355 additions and 233 deletions.
66 changes: 32 additions & 34 deletions doc/sphinx/develop/reactor-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,10 @@ First, let's take a look at what happens when creating a reactor network by sett
up an isolated reactor in Python.

```python
# import the Cantera Python module
import cantera as ct

# create a gas mixture using the GRI-Mech 3.0 mechanism
gas = ct.Solution("gri30.yaml")

# set gas to an interesting state
gas.TPX = 1000.0, ct.one_atm, "H2:2,O2:1,N2:4"

# create a reactor containing the gas
reac = ct.IdealGasReactor(gas)

# Add the reactor to a new ReactorNet simulator
sim = ct.ReactorNet([reac])
```

Expand All @@ -43,12 +34,12 @@ The {ct}`Integrator` class is Cantera's interface for ODE/DAE system integrators
it defines a set of *virtual methods* that derived classes (the actual system
integrators) provide implementations for.

The {ct}`newIntegrator` factory method creates and returns an {ct}`Integrator` object of
the specified type. Calling `newIntegrator("CVODE")` creates a new
The {ct}`newIntegrator` factory function creates and returns an {ct}`Integrator` object
of the specified type. Calling `newIntegrator("CVODE")` creates a new
{ct}`CVodesIntegrator` object for integrating an ODE system, while calling
`newIntegrator("IDA")` creates a new {ct}`IdasIntegrator` object for integrating a DAE
system. The appropriate integrator type is determined by the {ct}`ReactorNet` class
based on the types of the installed reactors -- a {ct}`FlowReactor` defines a DAE system
based on the types of the installed reactors. A {ct}`FlowReactor` defines a DAE system
and uses the IDAS integrator, while the other reactor types define ODE systems and use
the CVODES integrator. In this guide, the implementation of {ct}`CVodesIntegrator` is
described; {ct}`IdasIntegrator` works in a similar way, although the IDAS function names
Expand All @@ -58,15 +49,15 @@ are different.

Because SUNDIALS is written in C, the {ct}`CVodesIntegrator` C++ wrapper is used to
access the `CVODES` solver and make the appropriate calls such as those to the
integrator function `CVode()`. For details on CVODES API, see the
integrator function `CVode`. For details on CVODES API, see the
[CVODES User Guide](https://sundials.readthedocs.io/en/latest/cvodes/Introduction_link.html).

## Calling the `ReactorNet.advance()` Method
## Calling the `ReactorNet.advance` Method

After configuring a reactor network and its components in Cantera, a call to the
{py:meth}`ReactorNet.advance` method can be used to obtain the state of the network at a
specified time. The initial condition information is passed off to the {ct}`Integrator`
when calling `advance()`. Transient physical and chemical interactions are simulated by
when calling `advance`. Transient physical and chemical interactions are simulated by
integrating the network's system of ODE governing equations through time.

```python
Expand All @@ -88,17 +79,23 @@ special cases and errors, the implementation of {ct}`CVodesIntegrator::integrate
:end-before: " CVodesIntegrator::"
```

The arguments taken by the `CVode()` method are:
- `m_cvode_mem`, a pointer to the block of memory that was allocated and configured
during initialization.
The arguments taken by the SUNDIALS
[`CVode()`](https://sundials.readthedocs.io/en/latest/cvode/Usage/index.html#cvode-solver-function)
function are:

- {ct}`CVodesIntegrator::m_cvode_mem`, a pointer to the block of memory that was
allocated and configured during initialization.
- `tout` is the desired integrator output time. CVODES will not necessarily reach this
time, but it is used in the selection of the initial step size.
- After execution, `m_y` will contain the computed solution vector, and will later be
used to update the {ct}`ReactorNet` to its time-integrated state.
- After execution, `m_tInteg` will contain the time reached by the integrator.
time when operating in "one step" mode, but it is used in the selection of the initial
step size.
- After execution, {ct}`CVodesIntegrator::m_y` will contain the computed solution
vector, and will later be used to update the {ct}`ReactorNet` to its time-integrated
state.
- After execution, {ct}`CVodesIntegrator::m_tInteg` will contain the time reached by the
integrator.
- The `CV_ONE_STEP` option tells the solver to take a single internal step.

The return value of the `CVode()` method is assigned to the `flag` object. `CVode()`
The return value of the `CVode()` function is assigned to the `flag` variable. `CVode()`
returns the constant `CV_SUCCESS` to indicate success an error code if integration was
unsuccessful.

Expand All @@ -107,7 +104,7 @@ unsuccessful.
How does `CVODES` know what ODE system it should be solving?

In the example above, the ODE system was actually already specified using `CVodeInit()`,
one of the methods automatically invoked during the {ct}`ReactorNet::initialize` method.
one of the functions automatically invoked by the {ct}`ReactorNet::initialize` method.
CVODES requires a C function with a specific signature that defines the ODE system by
computing the right-hand side of the ODE system $dy/dt$ for a given value of the
independent variable, $t$, and the state vector $y$. For more information about ODE
Expand All @@ -119,18 +116,18 @@ this C function by pairing with {ct}`FuncEval`, an abstract base class for ODE a
right-hand-side function evaluators. Classes derived from {ct}`FuncEval` implement the
evaluation of the provided ODE system.

An ODE right-hand-side evaluator is always needed in the ODE solution process (it's the
only way to describe the system!), and for that reason a {ct}`FuncEval` object is a
required parameter when initializing any type of {ct}`Integrator`.
An ODE right-hand-side evaluator is always needed in the ODE solution process to provide
the definition of the system, and for that reason a {ct}`FuncEval` object is a required
parameter when initializing any type of {ct}`Integrator`.

{ct}`ReactorNet` handles this requirement by inheriting the {ct}`FuncEval` class,
meaning that it provides the implementation for the ODE function and actually specifies
itself (using the [`this`](https://en.cppreference.com/w/cpp/language/this) pointer)
itself using the [`this`](https://en.cppreference.com/w/cpp/language/this) pointer
when calling {ct}`Integrator::initialize` in {ct}`ReactorNet::initialize`.

To be a valid {ct}`FuncEval` object, a {ct}`ReactorNet` needs to provide implementations
for several of {ct}`FuncEval`'s virtual functions, particularly the actual ODE
right-hand-side computation function, {ct}`FuncEval::eval`:
for several of {ct}`FuncEval`'s virtual methods, particularly the actual ODE
right-hand-side computation method, {ct}`FuncEval::eval`:

```C++
virtual void eval(double t, double* y, double* ydot, double* p);
Expand Down Expand Up @@ -171,15 +168,16 @@ $$
\mathrm{LHS}_i \frac{dy_i}{dt} = \mathrm{RHS}_i
$$

where the {ct}`Reactor::eval` method (or the `eval` method of any class derived from
{ct}`Reactor`) calculates the values for the LHS and RHS vectors, whose values default
to 1 and 0, respectively, by implementing a function with the signature:
where the {ct}`Reactor::eval` method or the `eval()` method of any class derived from
{ct}`Reactor` calculates the values for the LHS (left-hand side) and RHS (right-hand
side) vectors, whose values default to 1 and 0, respectively, by implementing a method
with the signature:

```c++
void eval(double time, double* LHS, double* RHS);
```
These values are then assembled into the global `ydot` vector by `ReactorNet::eval`:
These values are then assembled into the global `ydot` vector by `ReactorNet::eval()`:
```{literalinclude} ../../../../src/zeroD/ReactorNet.cpp
:start-at: "void ReactorNet::eval("
Expand Down
13 changes: 7 additions & 6 deletions doc/sphinx/reference/kinetics/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Chemical Reactions

Calculation of reaction rates in Cantera is done in two steps. First, a *forward rate
constant* is calculated, which is typically a function of temperature, but can also
depend on other properties of the mixture state such as pressure and composition. This
rate constant is then used along with the reactant and product concentrations to
determine the forward and reverse rates of reactions, as well as other quantities such
as the net rate of production for each species.
Calculation of reaction rates in Cantera is done in two steps. First, a [*forward rate
constant*](https://en.wikipedia.org/wiki/Reaction_rate_constant) is calculated, which is
typically a function of temperature, but can also depend on other properties of the
mixture state such as pressure and composition. This rate constant is then used along
with the reactant and product concentrations to determine the forward and reverse rates
of reactions, as well as other quantities such as the net rate of production for each
species.

[](reaction-rates)
: This page describes how forward and reverse reaction rates and other quantities are
Expand Down
44 changes: 23 additions & 21 deletions doc/sphinx/reference/kinetics/rate-constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ calculating the forward rate constant $k_f$ for a reaction.
(sec-arrhenius-rate)=
## Arrhenius Rate Expressions

An Arrhenius rate is described by the modified Arrhenius function:
An Arrhenius rate is described by the
[modified Arrhenius function](https://en.wikipedia.org/wiki/Arrhenius_equation#Modified_Arrhenius_equation):

$$ k_f = A T^b e^{-E_a / RT} $$

Expand All @@ -23,24 +24,23 @@ field.
(sec-falloff-rate)=
## Falloff Reactions

A falloff reaction is one that has a rate that is first-order in $[\mathrm{M}]$ at low
pressure, like a [three-body reaction](sec-three-body-reaction), but becomes zero-order
in $[\mathrm{M}]$ as $[\mathrm{M}]$ increases. Dissociation/association reactions of
polyatomic molecules often exhibit this behavior.
A falloff reaction is one that has a rate that is first-order in the total concentration
of third-body colliders $\def\MM{[\mathrm{M}]} \MM$ at low pressure, like a
[three-body reaction](sec-three-body-reaction), but becomes zero-order in $\MM$ as $\MM$
increases. Dissociation/association reactions of polyatomic molecules often exhibit this
behavior.

The simplest expression for the rate coefficient for a falloff reaction is the Lindemann
form {cite:p}`lindemann1922`:

$$
k_f(T, [{\mathrm{M}}]) = \frac{k_0[{ \mathrm{M}}]}{1 + \frac{k_0{ [\mathrm{M}]}}{k_\infty}}
$$
$$ k_f(T, \MM) = \frac{k_0 \MM}{1 + \frac{k_0 \MM}{k_\infty}} $$

In the low-pressure limit, this approaches $k_0{[\mathrm{M}]}$, and in the high-pressure
limit it approaches $k_\infty$.
In the low-pressure limit, this approaches $k_0 \MM$, and in the high-pressure limit it
approaches $k_\infty$.

Defining the non-dimensional reduced pressure:

$$ P_r = \frac{k_0 [\mathrm{M}]}{k_\infty} $$
$$ P_r = \frac{k_0 \MM}{k_\infty} $$

The rate constant may be written as

Expand Down Expand Up @@ -112,8 +112,8 @@ A Tsang falloff function may be specified in the YAML format using the

This falloff function is based on the one originally due to {cite:t}`stewart1989`, which
required three parameters $a$, $b$, and $c$. {cite:t}`kee1989` generalized this function
slightly by adding two more parameters $d$ and $e$. (The original form corresponds to $d
= 1$ and $e = 0$.) Cantera supports the extended 5-parameter form, given by:
slightly by adding two more parameters $d$ and $e$. The original form corresponds to
$d = 1$ and $e = 0$. Cantera supports the extended 5-parameter form, given by:

$$ F(T, P_r) = d \bigl[a \exp(-b/T) + \exp(-T/c)\bigr]^{1/(1+\log_{10}^2 P_r )} T^e $$

Expand Down Expand Up @@ -204,8 +204,10 @@ $$
\phi_t(\tilde{T}) \phi_p(\tilde{P})
$$

where $\alpha_{tp}$ are the constants defining the rate, $\phi_n(x)$ is the Chebyshev
polynomial of the first kind of degree $n$ evaluated at $x$, and
where $N_T$ is the order of the polynomial in the temperature dimension, $N_P$ is the
order of the polynomial in the pressure dimension, $\alpha_{tp}$ are the constants
defining the rate, $\phi_n(x)$ is the Chebyshev polynomial of the first kind of degree
$n$ evaluated at $x$, and

$$
\tilde{T} \equiv \frac{2T^{-1} - T_\mathrm{min}^{-1} - T_\mathrm{max}^{-1}}
Expand Down Expand Up @@ -268,15 +270,15 @@ Arrhenius expression

$$ k_f = A T^b e^{-E_a / RT}. $$

```{versionadded} 2.6
```

```{admonition} YAML Usage
:class: tip
Blowers Masel reactions can be defined in the YAML format using the
[Blowers-Masel](sec-yaml-Blowers-Masel-rate) reaction `type`.
```

```{versionadded} 2.6
```

(sec-surface-rate)=
## Surface Reactions

Expand Down Expand Up @@ -367,13 +369,13 @@ temperature, $b$ is the electron temperature exponent, $E_{a,g}$ is the activati
energy for gas, $E_{a,e}$ is the activation energy for electron and $R$ is the gas
constant.

```{versionadded} 2.6
```

:::{admonition} YAML Usage
:class: tip

Two-temperature plasma reactions can be defined in the YAML format by specifying
[`two-temperature-plasma`](sec-yaml-two-temperature-plasma) as the reaction `type` and
providing the two activation energies as part of the `rate-constant`.
:::

```{versionadded} 2.6
```
26 changes: 20 additions & 6 deletions doc/sphinx/reference/kinetics/reaction-rates.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The forward reaction rate is then calculated as:
$$ R_f = [\mathrm{A}] [\mathrm{B}] k_f $$

where $k_f$ is the forward rate constant, calculated using one of the available rate
parameterizations such as [modified Arrhenius](sec-arrhenius-rate) form.
parameterizations such as the [modified Arrhenius](sec-arrhenius-rate) form.

```{admonition} YAML Usage
:class: tip
Expand All @@ -37,8 +37,9 @@ $$ \mathrm{A + B + M \rightleftharpoons AB + M} $$
Here $\mathrm{M}$ is an unspecified collision partner that carries away excess energy to
stabilize the $\mathrm{AB}$ molecule (forward direction) or supplies energy to break the
$\mathrm{AB}$ bond (reverse direction). In addition to the generic collision partner
$\mathrm{M}$, it is also possible to explicitly specify a colliding species. In this
case, the reaction type is automatically inferred by Cantera.
$\mathrm{M}$, it is also possible to explicitly specify a colliding species. In both
cases, the reaction type can be automatically inferred by Cantera and does not need to
be explicitly specified by the user.

Different species may be more or less effective in acting as the collision partner. A
species that is much lighter than $\mathrm{A}$ and $\mathrm{B}$ may not be able to
Expand Down Expand Up @@ -74,13 +75,14 @@ $$
\mathrm{A + B + C \rightleftharpoons AB + C \quad (R2)}
$$

where the third-body efficiency for C in the first reaction is set to zero.
where the third-body efficiency for C in the first reaction should be explicitly set to
zero.

```{admonition} YAML Usage
:class: tip
A three-body reaction may be defined in the YAML format using the
[`three-body`](sec-yaml-three-body) reaction `type`, or identified automatically if no
`type` is specified by the presence of the generic third body M or a specific
[`three-body`](sec-yaml-three-body) reaction `type` or, if no `type` is specified,
identified automatically by the presence of the generic third body M or a specific
non-reactive species (for example, C in R2 above).
```

Expand Down Expand Up @@ -121,3 +123,15 @@ Note that you can change reaction orders only for irreversible reactions.
Normally, reaction orders are required to be positive. However, in some cases negative
reaction orders are found to be better fits for experimental data. In these cases, the
default behavior may be overridden in the input file.

````{admonition} YAML Usage
:class: tip
To include explicit orders for the reaction above, it can be written in the YAML format as:
```yaml
- equation: C8H18 + 12.5 O2 => 8 CO2 + 9 H2O
units: {length: cm, quantity: mol, activation-energy: kcal/mol}
rate-constant: {A: 4.5e+11, b: 0.0, Ea: 30.0}
orders: {C8H18: 0.25, O2: 1.5}
```
````
27 changes: 21 additions & 6 deletions doc/sphinx/reference/onedim/governing-equations.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ $$

where the following variables are used:

- $z$ is the axial coordinate
- $r$ is the radial coordinate
- $\rho$ is the density
- $u$ is the axial velocity
- $v$ is the radial velocity
Expand All @@ -57,14 +59,22 @@ where the following variables are used:

The tangential velocity $w$ has been assumed to be zero. The model is applicable to both
ideal and non-ideal fluids, which follow ideal-gas or real-gas (Redlich-Kwong and
Peng-Robinson) equations of state. The real-gas support for the flame models has been
newly implemented as a part of Cantera 3.0.
Peng-Robinson) equations of state.

To help in the solution of the discretized problem, it is convenient to write a
```{versionadded} 3.0
Support for real gases in the flame models was introduced in Cantera 3.0.
```

To help in the solution of the discretized problem, it is useful to write a
differential equation for the scalar $\Lambda$:

$$ \frac{d\Lambda}{dz} = 0 $$

When discretized, the Jacobian terms introduced by this equation match the block
diagonal structure produced by the other governing equations, rather than creating a
column of entries that would cause fill-in when factorizing as part of the Newton
solver.

## Diffusive Fluxes

The species diffusive mass fluxes $j_k$ are computed according to either a
Expand Down Expand Up @@ -92,16 +102,21 @@ j_k = \frac{\rho W_k}{\overline{W}^2} \sum_i W_i D_{ki} \frac{\partial X_i}{\par
$$

where $D_{ki}$ is the multicomponent diffusion coefficient and $D_k^T$ is the Soret
diffusion coefficient (used only if calculation of this term is specifically enabled).
diffusion coefficient. Inclusion of the Soret calculation must be explicitly enabled
when setting up the simulation, on top of specifying a multicomponent transport model,
for example by using the {ct}`StFlow::enableSoret` method (C++) or setting the
{py:attr}`~cantera.FlameBase.soret_enabled` property (Python).

## Boundary Conditions

### Inlet boundary

For a boundary located at a point $z_0$ where there is an inflow, values are supplied
for the temperature $T_0$, the species mass fractions $Y_{k,0}$ the scaled radial
velocity $V_0$, and the mass flow rate $\dot{m}_0$ (except in the case of the
freely-propagating flame).
velocity $V_0$, and the mass flow rate $\dot{m}_0$. In the case of the
freely-propagating flame, the mass flow rate is not an input but is determined
indirectly by holding the temperature fixed at an intermediate location within the
domain; see [](discretization) for details.

The following equations are solved at the point $z = z_0$:

Expand Down
4 changes: 2 additions & 2 deletions doc/sphinx/reference/onedim/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ within a 1D flow domain, with the differences between the models being represent
differences in the boundary conditions applied.

[](governing-equations)
: Here we describe the governing equations and the various boundary conditions which can be
applied.
: This page describes the governing equations and the various boundary conditions that
can be applied.

[](discretization)
: This page describes the finite difference schemes used to discretize the 1D governing
Expand Down
Loading

0 comments on commit 7aa65e5

Please sign in to comment.