[1D/Python] Create BurnerIonFlame and add test
Create a base class (IonFlameBase) for both IonFreeFlame and BurnerIonFlame, and use the set_axisymmetric_flow() and set_free_flow() methods to select the flow type. Also combines FreeFlow and AxisymmetricStagnationFlow classes into class IdealGasFlow.
This commit is contained in:
parent
a5762ea6b6
commit
2527869536
7 changed files with 197 additions and 107 deletions
|
|
@ -149,10 +149,12 @@ public:
|
|||
|
||||
void setFreeFlow() {
|
||||
m_type = cFreeFlow;
|
||||
m_dovisc = false;
|
||||
}
|
||||
|
||||
void setAxisymmetricFlow() {
|
||||
m_type = cAxisymmetricStagnationFlow;
|
||||
m_dovisc = true;
|
||||
}
|
||||
|
||||
virtual std::string flowType() {
|
||||
|
|
|
|||
|
|
@ -687,7 +687,6 @@ cdef extern from "cantera/oneD/StFlow.h":
|
|||
cbool doEnergy(size_t)
|
||||
void enableSoret(cbool) except +translate_exception
|
||||
cbool withSoret()
|
||||
void setViscosityFlag(bool)
|
||||
void setFreeFlow()
|
||||
void setAxisymmetricFlow()
|
||||
|
||||
|
|
@ -1041,13 +1040,16 @@ cdef class ReactingSurface1D(Boundary1D):
|
|||
cdef class _FlowBase(Domain1D):
|
||||
cdef CxxStFlow* flow
|
||||
|
||||
cdef class FreeFlow(_FlowBase):
|
||||
cdef class IdealGasFlow(_FlowBase):
|
||||
pass
|
||||
|
||||
cdef class FreeFlow(IdealGasFlow):
|
||||
pass
|
||||
|
||||
cdef class IonFlow(_FlowBase):
|
||||
pass
|
||||
|
||||
cdef class AxisymmetricStagnationFlow(_FlowBase):
|
||||
cdef class AxisymmetricStagnationFlow(IdealGasFlow):
|
||||
pass
|
||||
|
||||
cdef class Sim1D:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
"""
|
||||
A burner-stabilized lean premixed hydrogen-oxygen flame at low pressure.
|
||||
"""
|
||||
|
||||
import cantera as ct
|
||||
import numpy as np
|
||||
|
||||
p = ct.one_atm
|
||||
tburner = 600.0
|
||||
reactants = 'CH4:1.0, O2:2.0, N2:7.52' # premixed gas composition
|
||||
width = 0.5 # m
|
||||
loglevel = 1 # amount of diagnostic output (0 to 5)
|
||||
|
||||
gas = ct.Solution('gri30_ion.cti')
|
||||
gas.TPX = tburner, p, reactants
|
||||
mdot = 0.15 * gas.density
|
||||
|
||||
f = ct.IonBurnerFlame(gas, width=width)
|
||||
f.burner.mdot = mdot
|
||||
f.set_refine_criteria(ratio=3.0, slope=0.05, curve=0.1)
|
||||
f.show_solution()
|
||||
|
||||
f.transport_model = 'Ion'
|
||||
f.solve(loglevel, auto=True)
|
||||
f.solve(loglevel=loglevel, stage=2, enable_energy=True)
|
||||
f.save('CH4_burner_flame.xml', 'mix', 'solution with mixture-averaged transport')
|
||||
|
||||
f.write_csv('CH4_burner_flame.csv', quiet=False)
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ gas = ct.Solution('gri30_ion.xml')
|
|||
gas.TPX = Tin, p, reactants
|
||||
|
||||
# Set up flame object
|
||||
f = ct.IonFlame(gas, width=width)
|
||||
f = ct.IonFreeFlame(gas, width=width)
|
||||
f.set_refine_criteria(ratio=3, slope=0.05, curve=0.1)
|
||||
f.show_solution()
|
||||
|
||||
|
|
@ -394,9 +394,9 @@ class FreeFlame(FlameBase):
|
|||
|
||||
def __init__(self, gas, grid=None, width=None):
|
||||
"""
|
||||
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``.
|
||||
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``.
|
||||
|
||||
:param grid:
|
||||
A list of points to be used as the initial grid. Not recommended
|
||||
|
|
@ -410,7 +410,8 @@ class FreeFlame(FlameBase):
|
|||
self.outlet = Outlet1D(name='products', phase=gas)
|
||||
if not hasattr(self, 'flame'):
|
||||
# Create flame domain if not already instantiated by a child class
|
||||
self.flame = FreeFlow(gas, name='flame')
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_free_flow()
|
||||
|
||||
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
|
||||
|
|
@ -561,29 +562,12 @@ class FreeFlame(FlameBase):
|
|||
return self.solve_adjoint(perturb, self.gas.n_reactions, dgdx) / Su0
|
||||
|
||||
|
||||
class IonFlame(FreeFlame):
|
||||
__slots__ = ('inlet', 'outlet', 'flame')
|
||||
|
||||
def __init__(self, gas, grid=None, width=None):
|
||||
if not hasattr(self, 'flame'):
|
||||
# Create flame domain if not already instantiated by a child class
|
||||
self.flame = IonFlow(gas, name='flame')
|
||||
|
||||
super(IonFlame, self).__init__(gas, grid, width)
|
||||
|
||||
def solve(self, loglevel=1, refine_grid=True, auto=False, stage=1, enable_energy=True):
|
||||
self.flame.set_solvingStage(stage)
|
||||
if stage == 1:
|
||||
super(IonFlame, self).solve(loglevel, refine_grid, auto)
|
||||
if stage == 2:
|
||||
self.poisson_enabled = True
|
||||
super(IonFlame, self).solve(loglevel, refine_grid, auto)
|
||||
class IonFlameBase(FlameBase):
|
||||
|
||||
def write_csv(self, filename, species='X', quiet=True):
|
||||
"""
|
||||
Write the velocity, temperature, density, electric potential,
|
||||
, electric field stregth, and species profiles to a CSV file.
|
||||
|
||||
:param filename:
|
||||
Output file name
|
||||
:param species:
|
||||
|
|
@ -641,6 +625,26 @@ class IonFlame(FreeFlame):
|
|||
Efield.append((phi[np-2] - phi[np-1]) / (z[np-1] - z[np-2]))
|
||||
return Efield
|
||||
|
||||
def solve(self, loglevel=1, refine_grid=True, auto=False, stage=1, enable_energy=True):
|
||||
self.flame.set_solvingStage(stage)
|
||||
if stage == 1:
|
||||
super(IonFlameBase, self).solve(loglevel, refine_grid, auto)
|
||||
if stage == 2:
|
||||
self.poisson_enabled = True
|
||||
super(IonFlameBase, self).solve(loglevel, refine_grid, auto)
|
||||
|
||||
|
||||
class IonFreeFlame(IonFlameBase, FreeFlame):
|
||||
__slots__ = ('inlet', 'outlet', 'flame')
|
||||
|
||||
def __init__(self, gas, grid=None, width=None):
|
||||
if not hasattr(self, 'flame'):
|
||||
# Create flame domain if not already instantiated by a child class
|
||||
self.flame = IonFlow(gas, name='flame')
|
||||
self.flame.set_free_flow()
|
||||
|
||||
super(IonFreeFlame, self).__init__(gas, grid, width)
|
||||
|
||||
|
||||
class BurnerFlame(FlameBase):
|
||||
"""A burner-stabilized flat flame."""
|
||||
|
|
@ -659,14 +663,17 @@ class BurnerFlame(FlameBase):
|
|||
Defines a grid on the interval [0, width] with internal points
|
||||
determined automatically by the solver.
|
||||
|
||||
A domain of class `AxisymmetricStagnationFlow` 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``.
|
||||
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``.
|
||||
"""
|
||||
self.burner = Inlet1D(name='burner', phase=gas)
|
||||
self.outlet = Outlet1D(name='outlet', phase=gas)
|
||||
self.flame = AxisymmetricStagnationFlow(gas, name='flame')
|
||||
if not hasattr(self, 'flame'):
|
||||
# Create flame domain if not already instantiated by a child class
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
if width is not None:
|
||||
grid = np.array([0.0, 0.1, 0.2, 0.3, 0.5, 0.7, 1.0]) * width
|
||||
|
|
@ -765,6 +772,19 @@ class BurnerFlame(FlameBase):
|
|||
self.set_steady_callback(original_callback)
|
||||
|
||||
|
||||
class IonBurnerFlame(IonFlameBase, BurnerFlame):
|
||||
"""A burner-stabilized flat flame with ionized gas."""
|
||||
__slots__ = ('burner', 'flame', 'outlet')
|
||||
|
||||
def __init__(self, gas, grid=None, width=None):
|
||||
if not hasattr(self, 'flame'):
|
||||
# Create flame domain if not already instantiated by a child class
|
||||
self.flame = IonFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
super(IonBurnerFlame, self).__init__(gas, grid, width)
|
||||
|
||||
|
||||
class CounterflowDiffusionFlame(FlameBase):
|
||||
""" A counterflow diffusion flame """
|
||||
__slots__ = ('fuel_inlet', 'flame', 'oxidizer_inlet')
|
||||
|
|
@ -782,10 +802,10 @@ class CounterflowDiffusionFlame(FlameBase):
|
|||
Defines a grid on the interval [0, width] with internal points
|
||||
determined automatically by the solver.
|
||||
|
||||
A domain of class `AxisymmetricStagnationFlow` 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``.
|
||||
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``.
|
||||
"""
|
||||
self.fuel_inlet = Inlet1D(name='fuel_inlet', phase=gas)
|
||||
self.fuel_inlet.T = gas.T
|
||||
|
|
@ -793,7 +813,8 @@ class CounterflowDiffusionFlame(FlameBase):
|
|||
self.oxidizer_inlet = Inlet1D(name='oxidizer_inlet', phase=gas)
|
||||
self.oxidizer_inlet.T = gas.T
|
||||
|
||||
self.flame = AxisymmetricStagnationFlow(gas, name='flame')
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
if width is not None:
|
||||
grid = np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0]) * width
|
||||
|
|
@ -1062,12 +1083,14 @@ class ImpingingJet(FlameBase):
|
|||
:param surface:
|
||||
A Kinetics object used to compute any surface reactions.
|
||||
|
||||
A domain of class `AxisymmetricStagnationFlow` named ``flame`` will be
|
||||
created to represent the flow. The three domains comprising the stack
|
||||
are stored as ``self.inlet``, ``self.flame``, and ``self.surface``.
|
||||
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``.
|
||||
"""
|
||||
self.inlet = Inlet1D(name='inlet', phase=gas)
|
||||
self.flame = AxisymmetricStagnationFlow(gas, name='flame')
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
if width is not None:
|
||||
grid = np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0]) * width
|
||||
|
|
@ -1138,10 +1161,10 @@ class CounterflowPremixedFlame(FlameBase):
|
|||
Defines a grid on the interval [0, width] with internal points
|
||||
determined automatically by the solver.
|
||||
|
||||
A domain of class `AxisymmetricStagnationFlow` 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``.
|
||||
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``.
|
||||
"""
|
||||
self.reactants = Inlet1D(name='reactants', phase=gas)
|
||||
self.reactants.T = gas.T
|
||||
|
|
@ -1149,7 +1172,8 @@ class CounterflowPremixedFlame(FlameBase):
|
|||
self.products = Inlet1D(name='products', phase=gas)
|
||||
self.products.T = gas.T
|
||||
|
||||
self.flame = AxisymmetricStagnationFlow(gas, name='flame')
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
if width is not None:
|
||||
# Create grid points aligned with initial guess profile
|
||||
|
|
@ -1231,15 +1255,16 @@ class CounterflowTwinPremixedFlame(FlameBase):
|
|||
Defines a grid on the interval [0, width] with internal points
|
||||
determined automatically by the solver.
|
||||
|
||||
A domain of class `AxisymmetricStagnationFlow` 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``.
|
||||
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``.
|
||||
"""
|
||||
self.reactants = Inlet1D(name='reactants', phase=gas)
|
||||
self.reactants.T = gas.T
|
||||
|
||||
self.flame = AxisymmetricStagnationFlow(gas, name='flame')
|
||||
self.flame = IdealGasFlow(gas, name='flame')
|
||||
self.flame.set_axisymmetric_flow()
|
||||
|
||||
#The right boundary is a symmetry plane
|
||||
self.products = SymmetryPlane1D(name='products', phase=gas)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
import interrupts
|
||||
import warnings
|
||||
|
||||
# Need a pure-python class to store weakrefs to
|
||||
class _WeakrefProxy(object):
|
||||
|
|
@ -467,13 +468,12 @@ cdef class _FlowBase(Domain1D):
|
|||
def __set__(self, do_radiation):
|
||||
self.flow.enableRadiation(<cbool>do_radiation)
|
||||
|
||||
def set_viscosityFlag(self, dovisc):
|
||||
self.flow.setViscosityFlag(dovisc)
|
||||
|
||||
def set_freeFlow(self):
|
||||
def set_free_flow(self):
|
||||
""" Set flow type to free flow."""
|
||||
self.flow.setFreeFlow()
|
||||
|
||||
def set_axisymmetricFlow(self):
|
||||
def set_axisymmetric_flow(self):
|
||||
""" Set flow type to axisymmetric stagnation flow."""
|
||||
self.flow.setAxisymmetricFlow()
|
||||
|
||||
|
||||
|
|
@ -483,48 +483,12 @@ cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except *:
|
|||
return <CxxIdealGasPhase*>(phase.thermo)
|
||||
|
||||
|
||||
cdef class FreeFlow(_FlowBase):
|
||||
def __cinit__(self, _SolutionBase thermo, *args, **kwargs):
|
||||
gas = getIdealGasPhase(thermo)
|
||||
self.flow = new CxxStFlow(gas, thermo.n_species, 2)
|
||||
self.set_freeFlow()
|
||||
self.set_viscosityFlag(False)
|
||||
|
||||
|
||||
cdef class IonFlow(_FlowBase):
|
||||
cdef class IdealGasFlow(_FlowBase):
|
||||
"""
|
||||
An ion flow domain.
|
||||
An ideal gas flow domain. Functions set_free_flow and set_axisymmetric_flow
|
||||
can be used to set different type of flow.
|
||||
|
||||
In an ion flow dommain, the electric drift is added to the diffusion flux
|
||||
"""
|
||||
def __cinit__(self, _SolutionBase thermo, *args, **kwargs):
|
||||
gas = getIdealGasPhase(thermo)
|
||||
self.flow = <CxxStFlow*>(new CxxIonFlow(gas, thermo.n_species, 2))
|
||||
self.set_freeFlow()
|
||||
self.set_viscosityFlag(False)
|
||||
|
||||
def set_solvingStage(self, stage):
|
||||
(<CxxIonFlow*>self.flow).setSolvingStage(stage)
|
||||
|
||||
def set_electricPotential(self, v_inlet, v_outlet):
|
||||
(<CxxIonFlow*>self.flow).setElectricPotential(v_inlet, v_outlet)
|
||||
|
||||
property poisson_enabled:
|
||||
""" Determines whether or not to solve the energy equation."""
|
||||
def __get__(self):
|
||||
return (<CxxIonFlow*>self.flow).doPoisson(0)
|
||||
def __set__(self, enable):
|
||||
if enable:
|
||||
(<CxxIonFlow*>self.flow).solvePoissonEqn()
|
||||
else:
|
||||
(<CxxIonFlow*>self.flow).fixElectricPotential()
|
||||
|
||||
|
||||
cdef class AxisymmetricStagnationFlow(_FlowBase):
|
||||
"""
|
||||
An axisymmetric flow domain.
|
||||
|
||||
In an axisymmetric flow domain, the equations solved are the similarity
|
||||
For the type of axisymmetric flow, the equations solved are the similarity
|
||||
equations for the flow in a finite-height gap of infinite radial extent.
|
||||
The solution variables are:
|
||||
|
||||
|
|
@ -552,8 +516,51 @@ cdef class AxisymmetricStagnationFlow(_FlowBase):
|
|||
def __cinit__(self, _SolutionBase thermo, *args, **kwargs):
|
||||
gas = getIdealGasPhase(thermo)
|
||||
self.flow = new CxxStFlow(gas, thermo.n_species, 2)
|
||||
self.set_axisymmetricFlow()
|
||||
self.set_viscosityFlag(True)
|
||||
|
||||
|
||||
cdef class FreeFlow(IdealGasFlow):
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn("Class FreeFlow is deprecated and will be removed after"
|
||||
" Cantera 2.4. Use class IdealGasFlow instead and call the"
|
||||
" set_free_flow() method.")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.set_free_flow()
|
||||
|
||||
|
||||
cdef class AxisymmetricStagnationFlow(IdealGasFlow):
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn("Class AxisymmetricStagnationFlow is deprecated and will"
|
||||
" be removed after Cantera 2.4. Use class IdealGasFlow instead and"
|
||||
" call the set_axisymmetric_flow() method.")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.set_free_flow()
|
||||
|
||||
|
||||
cdef class IonFlow(_FlowBase):
|
||||
"""
|
||||
An ion flow domain.
|
||||
|
||||
In an ion flow dommain, the electric drift is added to the diffusion flux
|
||||
"""
|
||||
def __cinit__(self, _SolutionBase thermo, *args, **kwargs):
|
||||
gas = getIdealGasPhase(thermo)
|
||||
self.flow = <CxxStFlow*>(new CxxIonFlow(gas, thermo.n_species, 2))
|
||||
|
||||
def set_solvingStage(self, stage):
|
||||
(<CxxIonFlow*>self.flow).setSolvingStage(stage)
|
||||
|
||||
def set_electricPotential(self, v_inlet, v_outlet):
|
||||
(<CxxIonFlow*>self.flow).setElectricPotential(v_inlet, v_outlet)
|
||||
|
||||
property poisson_enabled:
|
||||
""" Determines whether or not to solve the energy equation."""
|
||||
def __get__(self):
|
||||
return (<CxxIonFlow*>self.flow).doPoisson(0)
|
||||
def __set__(self, enable):
|
||||
if enable:
|
||||
(<CxxIonFlow*>self.flow).solvePoissonEqn()
|
||||
else:
|
||||
(<CxxIonFlow*>self.flow).fixElectricPotential()
|
||||
|
||||
|
||||
cdef class Sim1D:
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ class TestOnedim(utilities.CanteraTest):
|
|||
def test_instantiate(self):
|
||||
gas = ct.Solution('h2o2.xml')
|
||||
|
||||
flame = ct.FreeFlow(gas)
|
||||
flame = ct.IdealGasFlow(gas)
|
||||
|
||||
def test_badInstantiate(self):
|
||||
solid = ct.Solution('diamond.xml', 'diamond')
|
||||
with self.assertRaises(TypeError):
|
||||
flame = ct.FreeFlow(solid)
|
||||
flame = ct.IdealGasFlow(solid)
|
||||
|
||||
def test_instantiateSurface(self):
|
||||
gas = ct.Solution('diamond.xml', 'gas')
|
||||
|
|
@ -28,7 +28,7 @@ class TestOnedim(utilities.CanteraTest):
|
|||
gas1 = ct.Solution('h2o2.xml')
|
||||
gas2 = ct.Solution('h2o2.xml')
|
||||
inlet = ct.Inlet1D(name='something', phase=gas1)
|
||||
flame = ct.FreeFlow(gas1)
|
||||
flame = ct.IdealGasFlow(gas1)
|
||||
sim = ct.Sim1D((inlet, flame))
|
||||
|
||||
self.assertEqual(inlet.name, 'something')
|
||||
|
|
@ -53,7 +53,7 @@ class TestOnedim(utilities.CanteraTest):
|
|||
|
||||
def test_grid_check(self):
|
||||
gas = ct.Solution('h2o2.xml')
|
||||
flame = ct.FreeFlow(gas)
|
||||
flame = ct.IdealGasFlow(gas)
|
||||
|
||||
with self.assertRaises(ct.CanteraError):
|
||||
flame.grid = [0, 0.1, 0.1, 0.2]
|
||||
|
|
@ -64,21 +64,21 @@ class TestOnedim(utilities.CanteraTest):
|
|||
def test_unpicklable(self):
|
||||
import pickle
|
||||
gas = ct.Solution('h2o2.xml')
|
||||
flame = ct.FreeFlow(gas)
|
||||
flame = ct.IdealGasFlow(gas)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
pickle.dumps(flame)
|
||||
|
||||
def test_uncopyable(self):
|
||||
import copy
|
||||
gas = ct.Solution('h2o2.xml')
|
||||
flame = ct.FreeFlow(gas)
|
||||
flame = ct.IdealGasFlow(gas)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
copy.copy(flame)
|
||||
|
||||
def test_invalid_property(self):
|
||||
gas1 = ct.Solution('h2o2.xml')
|
||||
inlet = ct.Inlet1D(name='something', phase=gas1)
|
||||
flame = ct.FreeFlow(gas1)
|
||||
flame = ct.IdealGasFlow(gas1)
|
||||
sim = ct.Sim1D((inlet, flame))
|
||||
|
||||
for x in (inlet, flame, sim):
|
||||
|
|
@ -90,7 +90,7 @@ class TestOnedim(utilities.CanteraTest):
|
|||
def test_tolerances(self):
|
||||
gas = ct.Solution('h2o2.xml')
|
||||
left = ct.Inlet1D(gas)
|
||||
flame = ct.FreeFlow(gas)
|
||||
flame = ct.IdealGasFlow(gas)
|
||||
right = ct.Inlet1D(gas)
|
||||
# Some things don't work until the domains have been added to a Sim1D
|
||||
sim = ct.Sim1D((left, flame, right))
|
||||
|
|
@ -938,7 +938,7 @@ class TestTwinFlame(utilities.CanteraTest):
|
|||
self.solve(phi=0.4, T=300, width=0.05, P=0.1)
|
||||
|
||||
|
||||
class TestIonFlame(utilities.CanteraTest):
|
||||
class TestIonFreeFlame(utilities.CanteraTest):
|
||||
def test_ion_profile(self):
|
||||
reactants = 'CH4:0.216, O2:2'
|
||||
p = ct.one_atm
|
||||
|
|
@ -948,7 +948,7 @@ class TestIonFlame(utilities.CanteraTest):
|
|||
# IdealGasMix object used to compute mixture properties
|
||||
self.gas = ct.Solution('ch4_ion.cti')
|
||||
self.gas.TPX = Tin, p, reactants
|
||||
self.sim = ct.IonFlame(self.gas, width=width)
|
||||
self.sim = ct.IonFreeFlame(self.gas, width=width)
|
||||
self.sim.set_refine_criteria(ratio=4, slope=0.8, curve=1.0)
|
||||
# Ionized species may require tighter absolute tolerances
|
||||
self.sim.flame.set_steady_tolerances(Y=(1e-4, 1e-12))
|
||||
|
|
@ -962,3 +962,28 @@ class TestIonFlame(utilities.CanteraTest):
|
|||
|
||||
# Regression test
|
||||
self.assertNear(max(self.sim.E), 132.1922, 1e-3)
|
||||
|
||||
|
||||
class TestIonBurnerFlame(utilities.CanteraTest):
|
||||
def test_ion_profile(self):
|
||||
reactants = 'CH4:1.0, O2:2.0, N2:7.52'
|
||||
p = ct.one_atm
|
||||
Tburner = 400
|
||||
width = 0.03
|
||||
|
||||
# IdealGasMix object used to compute mixture properties
|
||||
self.gas = ct.Solution('ch4_ion.cti')
|
||||
self.gas.TPX = Tburner, p, reactants
|
||||
self.sim = ct.IonBurnerFlame(self.gas, width=width)
|
||||
self.sim.set_refine_criteria(ratio=4, slope=0.8, curve=1.0)
|
||||
self.sim.burner.mdot = self.gas.density * 0.15
|
||||
self.sim.transport_model = 'Ion'
|
||||
|
||||
# stage one
|
||||
self.sim.solve(loglevel=0, auto=True)
|
||||
|
||||
#stage two
|
||||
self.sim.solve(loglevel=0, stage=2, enable_energy=True)
|
||||
|
||||
# Regression test
|
||||
self.assertNear(max(self.sim.E), 469.7287, 1e-3)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue