Using Cantera as Chemkin with an imposed Temperature profile

248 views
Skip to first unread message

Corentin Grimaldi

unread,
Jul 1, 2021, 12:08:12 PM7/1/21
to Cantera Users' Group
Hello everyone !
I'm a PhD student in plasma physics in France and I started to use Cantera a few weeks ago, but with little success...
My goal is to reproduce the rapid cooling of a gas mixture and to track the mole fraction of the main species, to see if the mixture has the time to reach the chemical equilibrium or not. The mixture being at atmospheric pressure the whole time.

To do so, using Chemkin, I calculated the equilibrium mole fractions of the mixture at a temperature (eg 9000 K) as the initial conditions, imposed a temporal temperature profile (eg decreasing exponential to 6000 K) and ran the code with a specified kinetic model.
After that I calculated the equilibrium mole fraction at the final temperature (ex 6000 K) and compared the results with the final state obtained before.

I'm trying to reproduce these steps on Cantera.
I succeeded to import my input files (kinetic model and thermodynamic constants) but after that I fail to impose the temporal temperature profile and to obtain consistent results...

I think I'm doing something wrong, because even for a simpler case: equilibrium composition of 3000 K as initial conditions, temperature constant of 2500 K, the mixture does not reach the 2500 K equilibrium but converge to something else. See the example below using GRI30:
```
import numpy as np
import cantera as ct
import matplotlib.pyplot as plt

# Temperature initial and final
T_ini = 3000
T_end = 2500

gas = ct.Solution('gri30.yaml')

# Calculate the final state at equilibrium
gas.TPX = T_end, ct.one_atm, 'CO2:1'
gas.equilibrate('TP')
eq_data = gas.mole_fraction_dict()

# Set the initial state
gas.TPX = T_ini, ct.one_atm, 'CO2:1'
gas.equilibrate('TP')
reactor = ct.IdealGasConstPressureReactor(gas)
sim = ct.ReactorNet([reactor])

# Set the final temperature
gas.TPX = T_end, ct.one_atm, 'CO2:1'
reactor.syncState()
sim.reinitialize()

# Calculate the temporal evolution
time = np.linspace(1e-6, 1e1, int(1e4))
data = {specie : np.zeros(len(time)) for specie in eq_data.keys()}
n = 0
for t in time:
    t_sim = sim.advance(t)
    for specie in gas.mole_fraction_dict().keys():
        if specie in data.keys():
            data[specie][n] = gas.mole_fraction_dict()[specie]
    n += 1
    
# Calculate the ratio [N]/[N]eq_T_end
ratio = {}
for specie in eq_data.keys():
    ratio[specie] = data[specie]/eq_data[specie]
    
# %% Plot
plot_species = ['CO', 'CO2', 'O2']
color = ['k', 'b', 'r',  'c',  'g']

fig, [ax1, ax2] = plt.subplots(2, 1, sharex=True)
for i in range(len(plot_species)):
    ax2.plot(time, data[plot_species[i]], color[i], label=plot_species[i])
    ax2.plot(time, eq_data[plot_species[i]]*np.ones(len(time)), color[i]+'--', label=plot_species[i]+' Equilibrium', linewidth=2)
    ax1.plot(time, ratio[plot_species[i]], color[i], label=plot_species[i])
ax1.set_ylabel('[N]/[N]eq at {0}'.format(T_end))
ax2.set_ylabel('Mole Fraction')
ax2.set_xlabel('Time (s)')
ax1.legend()
ax2.legend()
```
So mainly, I have 2 questions:
- I do not understand why Cantera does not reach the same equilibrium since the kinetic backward rates are calculated using the same thermodynamic constants used to calculate the final composition, am I doing something wrong ?
- Do you know any way to impose a temporal profile in Cantera ?

Thank you very much in advance for your answers.
Corentin

Steven DeCaluwe

unread,
Jul 1, 2021, 5:17:50 PM7/1/21
to <cantera-users@googlegroups.com>
Hi Constantin,


1.  I notice that you set the chemical composition to 100% CO2, before integrating. So you are not actually using “ equilibrium composition of 3000 K as initial conditions” as claimed.  This doesn’t really change your question, though—now you are calculating the thermodynamic and kinetic equilibrium states from the exact same initial conditions, which you might reasonably expect to give the same results.

2. The reassign you get a discrepancy is because you have not disabled the energy equation, so the temperature is not fixed. See the reactor documentation, here:

If you replace 

reactor = ct.IdealGasConstPressureReactor(gas)
with
reactor = ct.IdealGasConstPressureReactor(contents=gas, energy='off')

You will see the two approaches give the same answer.

3. For an imposed T profile, I think you could add a lookup, at each time step?  Then set the gas temp using gas.TPY = T_lookup, ct.one_atm, None, followed by reactor.syncState() ?  Just a thought.

Best,
Steven


——————————————————
Steven C. DeCaluwe, Ph.D | Associate Professor of Mechanical Engineering
COLORADOSCHOOLOFMINES
Brown Building W410B
Golden, CO 80401

Twitter: @CORESresearch
He / Him / His





--
You received this message because you are subscribed to the Google Groups "Cantera Users' Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cantera-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cantera-users/0c16e49b-6a51-4246-bdfc-ea938f871f37n%40googlegroups.com.

Reply all
Reply to author
Forward
0 new messages