Skip to content

Commit

Permalink
[Python] Reintroduce FreeFlow and AxisymmetricFlow
Browse files Browse the repository at this point in the history
  • Loading branch information
ischoegl authored and speth committed Mar 18, 2023
1 parent a91970b commit a0f7c40
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 41 deletions.
55 changes: 54 additions & 1 deletion interfaces/cython/cantera/_onedim.pyx
Expand Up @@ -16,7 +16,7 @@ class _WeakrefProxy:
pass

cdef class Domain1D:
_domain_type = "None"
_domain_type = "none"
def __cinit__(self, _SolutionBase phase not None, *args, **kwargs):
self.domain = NULL

Expand Down Expand Up @@ -673,6 +673,49 @@ cdef class _FlowBase(Domain1D):
return pystr(self.flow.flowType())


cdef class FreeFlow(_FlowBase):
r"""A free flow domain. The equations solved are standard equations for adiabatic
one-dimensional flow. The solution variables are:
*velocity*
axial velocity
*T*
temperature
*Y_k*
species mass fractions
"""
_domain_type = "free-flow"


cdef class AxisymmetricFlow(_FlowBase):
r"""
An axisymmetric flow domain. The equations solved are the similarity equations for
the flow in a finite-height gap of infinite radial extent. The solution variables
are:
*velocity*
axial velocity
*spread_rate*
radial velocity divided by radius
*T*
temperature
*lambda*
:math:`(1/r)(dP/dr)`
*Y_k*
species mass fractions
It may be shown that if the boundary conditions on these variables are independent
of radius, then a similarity solution to the exact governing equations exists in
which these variables are all independent of radius. This solution holds only in
the low-Mach-number limit, in which case :math:`(dP/dz) = 0`, and :math:`lambda` is
a constant. (Lambda is treated as a spatially-varying solution variable for
numerical reasons, but in the final solution it is always independent of :math:`z`.)
As implemented here, the governing equations assume an ideal gas mixture. Arbitrary
chemistry is allowed, as well as arbitrary variation of the transport properties.
"""
_domain_type = "axisymmetric-flow"


cdef class IdealGasFlow(_FlowBase):
"""
An ideal gas flow domain. Functions `set_free_flow` and
Expand Down Expand Up @@ -702,9 +745,19 @@ cdef class IdealGasFlow(_FlowBase):
it is always independent of z.) As implemented here, the governing
equations assume an ideal gas mixture. Arbitrary chemistry is allowed, as
well as arbitrary variation of the transport properties.
.. deprecated:: 3.0
Class to be removed after Cantera 3.0; replaced by `FreeFlow` and
s`AxisymmetricFlow`.
"""
_domain_type = "gas-flow"

def __init__(self, *args, **kwargs):
warnings.warn("Class to be removed after Cantera 3.0; use 'FreeFlow' "
"or AxisymmetricFlow' instead.", DeprecationWarning)
super().__init__(*args, **kwargs)


cdef class IonFlow(_FlowBase):
"""
Expand Down
71 changes: 31 additions & 40 deletions interfaces/cython/cantera/onedim.py
Expand Up @@ -56,7 +56,7 @@ def other_components(self, domain=None):
if isinstance(dom, Inlet1D):
return tuple([e for e in self._other
if e not in {'grid', 'lambda', 'eField'}])
elif isinstance(dom, (IdealGasFlow, IonFlow)):
elif isinstance(dom, (FreeFlow, AxisymmetricFlow, IdealGasFlow, IonFlow)):
return self._other
else:
return ()
Expand Down Expand Up @@ -764,9 +764,9 @@ class FreeFlame(FlameBase):

def __init__(self, gas, grid=None, width=None):
"""
A domain of type IdealGasFlow named 'flame' will be created to represent
the flame and set to free flow. The three domains comprising the stack
are stored as ``self.inlet``, ``self.flame``, and ``self.outlet``.
A domain of type `FreeFlow` named 'flame' will be created to represent
the flame. The three domains comprising the stack are stored as ``self.inlet``,
``self.flame``, and ``self.outlet``.
:param grid:
A list of points to be used as the initial grid. Not recommended
Expand All @@ -785,9 +785,8 @@ def __init__(self, gas, grid=None, width=None):

if not hasattr(self, 'flame'):
# Create flame domain if not already instantiated by a child class
#: `IdealGasFlow` domain representing the flame
self.flame = IdealGasFlow(gas, name='flame')
self.flame.set_free_flow()
#: `FreeFlow` domain representing the flame
self.flame = FreeFlow(gas, name='flame')

if width is not None:
grid = np.array([0.0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0]) * width
Expand Down Expand Up @@ -1008,10 +1007,9 @@ def __init__(self, gas, grid=None, width=None):
Defines a grid on the interval [0, width] with internal points
determined automatically by the solver.
A domain of class `IdealGasFlow` named ``flame`` will be created to
represent the flame and set to axisymmetric stagnation flow. The three
domains comprising the stack are stored as ``self.burner``,
``self.flame``, and ``self.outlet``.
A domain of class `AxisymmetricFlow` named ``flame`` will be created to
represent the flame. The three domains comprising the stack are stored as
``self.burner``, ``self.flame``, and ``self.outlet``.
"""
#: `Inlet1D` at the left of the domain representing the burner surface through
#: which reactants flow
Expand All @@ -1022,9 +1020,8 @@ def __init__(self, gas, grid=None, width=None):

if not hasattr(self, 'flame'):
# Create flame domain if not already instantiated by a child class
#: `IdealGasFlow` domain representing the flame
self.flame = IdealGasFlow(gas, name='flame')
self.flame.set_axisymmetric_flow()
#: `AxisymmetricFlow` domain representing the flame
self.flame = AxisymmetricFlow(gas, name='flame')

if width is not None:
grid = np.array([0.0, 0.1, 0.2, 0.3, 0.5, 0.7, 1.0]) * width
Expand Down Expand Up @@ -1159,10 +1156,9 @@ def __init__(self, gas, grid=None, width=None):
Defines a grid on the interval [0, width] with internal points
determined automatically by the solver.
A domain of class `IdealGasFlow` named ``flame`` will be created to
represent the flame and set to axisymmetric stagnation flow. The three
domains comprising the stack are stored as ``self.fuel_inlet``,
``self.flame``, and ``self.oxidizer_inlet``.
A domain of class `AxisymmetricFlow` named ``flame`` will be created to
represent the flame. The three domains comprising the stack are stored as
``self.fuel_inlet``, ``self.flame``, and ``self.oxidizer_inlet``.
"""

#: `Inlet1D` at the left of the domain representing the fuel mixture
Expand All @@ -1173,9 +1169,8 @@ def __init__(self, gas, grid=None, width=None):
self.oxidizer_inlet = Inlet1D(name='oxidizer_inlet', phase=gas)
self.oxidizer_inlet.T = gas.T

#: `IdealGasFlow` domain representing the flame
self.flame = IdealGasFlow(gas, name='flame')
self.flame.set_axisymmetric_flow()
#: `AxisymmetricFlow` domain representing the flame
self.flame = AxisymmetricFlow(gas, name='flame')

if width is not None:
grid = np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0]) * width
Expand Down Expand Up @@ -1483,17 +1478,16 @@ def __init__(self, gas, grid=None, width=None, surface=None):
:param surface:
A Kinetics object used to compute any surface reactions.
A domain of class `IdealGasFlow` named ``flame`` will be created to
represent the flame and set to axisymmetric stagnation flow. The three
domains comprising the stack are stored as ``self.inlet``,
``self.flame``, and ``self.surface``.
A domain of class `AxisymmetricFlow` named ``flame`` will be created to
represent the flame. The three domains comprising the stack are stored as
``self.inlet``, ``self.flame``, and ``self.surface``.
"""

#: `Inlet1D` at the left of the domain representing the incoming reactants
self.inlet = Inlet1D(name='inlet', phase=gas)

#: `IdealGasFlow` domain representing the flame
self.flame = IdealGasFlow(gas, name='flame')
#: `AxisymmetricFlow` domain representing the flame
self.flame = AxisymmetricFlow(gas, name='flame')
self.flame.set_axisymmetric_flow()

if width is not None:
Expand Down Expand Up @@ -1570,10 +1564,9 @@ def __init__(self, gas, grid=None, width=None):
Defines a grid on the interval [0, width] with internal points
determined automatically by the solver.
A domain of class `IdealGasFlow` named ``flame`` will be created to
represent the flame and set to axisymmetric stagnation flow. The three
domains comprising the stack are stored as ``self.reactants``,
``self.flame``, and ``self.products``.
A domain of class `AxisymmetricFlow` named ``flame`` will be created to
represent the flame. The three domains comprising the stack are stored as
``self.reactants``, ``self.flame``, and ``self.products``.
"""

#: `Inlet1D` at the left of the domain representing premixed reactants
Expand All @@ -1584,9 +1577,8 @@ def __init__(self, gas, grid=None, width=None):
self.products = Inlet1D(name='products', phase=gas)
self.products.T = gas.T

#: `IdealGasFlow` domain representing the flame
self.flame = IdealGasFlow(gas, name='flame')
self.flame.set_axisymmetric_flow()
#: `AxisymmetricFlow` domain representing the flame
self.flame = AxisymmetricFlow(gas, name='flame')

if width is not None:
# Create grid points aligned with initial guess profile
Expand Down Expand Up @@ -1674,16 +1666,15 @@ def __init__(self, gas, grid=None, width=None):
Defines a grid on the interval [0, width] with internal points
determined automatically by the solver.
A domain of class `IdealGasFlow` named ``flame`` will be created to
represent the flame and set to axisymmetric stagnation flow. The three
domains comprising the stack are stored as ``self.reactants``,
``self.flame``, and ``self.products``.
A domain of class `AxisymmetricFlow` named ``flame`` will be created to
represent the flame. The three domains comprising the stack are stored as
``self.reactants``, ``self.flame``, and ``self.products``.
"""
self.reactants = Inlet1D(name='reactants', phase=gas)
self.reactants.T = gas.T

self.flame = IdealGasFlow(gas, name='flame')
self.flame.set_axisymmetric_flow()
#: `AxisymmetricFlow` domain representing the flame
self.flame = AxisymmetricFlow(gas, name='flame')

#The right boundary is a symmetry plane
self.products = SymmetryPlane1D(name='products', phase=gas)
Expand Down

0 comments on commit a0f7c40

Please sign in to comment.