Fipy and Cantera/Diffusion 1D: Difference between revisions
From charlesreid1
No edit summary |
No edit summary |
||
| Line 6: | Line 6: | ||
<math> | <math> | ||
\dfrac{\partial | \dfrac{\partial X_i}{\partial t} = \nabla \cdot \left( D_i \nabla X_i \right) | ||
</math> | </math> | ||
subject to boundary conditions: | |||
< | <math> | ||
X_i ( x=0 ) = 1 | |||
X_i ( x=1 ) = 0 | |||
</math> | |||
The mixture being used is argon in oxygen. Although the diffusion coefficient is a very weak function of composition, and therefore the assumption | |||
<math> | |||
D_i \neq D_i(X_i) | |||
</math> | |||
would normally apply, this example illustrates the sweep solution technique (in which the diffusion coefficient is a function of the composition) anyway. | |||
=The Script= | |||
Begin with import statements: | |||
<source lang="python"> | |||
from fipy import * | |||
from numpy import * | |||
import Cantera | |||
import matplotlib.pylab as plt | |||
</source> | |||
Next, create a plot, which we'll use to visualize our results: | |||
<source> | |||
fig = plt.figure() | fig = plt.figure() | ||
ax = fig.add_subplot(111) | ax = fig.add_subplot(111) | ||
ax.set_title('Ar') | ax.set_title('Ar') | ||
</source> | |||
Computing the diffusion coefficient using Cantera proceeds as follows: | |||
* Pass in a Fipy CellVariable object | |||
* Create a CellVariable to contain diffusion coefficient values | |||
* Looping over each cell: | |||
** Translate the value of the Fipy CellVariable at a given cell into a thermochemical state for a Cantera phase object (we want to use a single Cantera phase object, so we don't have to keep loading our CTI/XML mechanism file into memory) | |||
** Compute the value of the diffusion coefficient | |||
** Populate the diffusion CellVariable | |||
* Return the diffusion CellVariable | |||
We'll define this in a function, which we can then pass when specifying the diffusion coefficient for the Fipy equation. | |||
<source> | |||
###################################### | ###################################### | ||
# Diffusion coefficient function | # Diffusion coefficient function | ||
| Line 65: | Line 72: | ||
return D | return D | ||
</source> | |||
We also want to define a single Cantera phase, which we'll use in the <code>get_diffusion_coeff()</code> function: | |||
<source> | |||
###################################### | ###################################### | ||
# Gas object | # Gas object | ||
| Line 83: | Line 93: | ||
ari = a.speciesIndex(arlab) | ari = a.speciesIndex(arlab) | ||
o2i = a.speciesIndex(o2lab) | o2i = a.speciesIndex(o2lab) | ||
</pre> | |||
Now we define Fipy equations/grid: | |||
<pre> | |||
# First, define the mesh | # First, define the mesh | ||
nx = 100 | nx = 100 | ||
| Line 105: | Line 119: | ||
print "Nsteps =",steps | print "Nsteps =",steps | ||
t = timestepDuration * steps | t = timestepDuration * steps | ||
# Now define your sweep variables | # Now define your sweep variables | ||
arvar = [CellVariable(name=arlab, mesh=mesh, value=arRight, hasOld=1)] | |||
</source> | |||
At this point, we can define the Fipy equation that we're solving, which is, as given above, | |||
<math> | |||
\dfrac{\partial X_i}{\partial t} = \nabla \cdot \left( D \nabla X_i \right) | |||
</math> | |||
and the diffusion coefficient is a function of <math>X_i</math>. This is subject to the boundary conditions set above (1 on the left side of the domain, 0 on the right side of the domain). | |||
<source> | |||
# Define the equation being solved | # Define the equation being solved | ||
eq = TransientTerm() == DiffusionTerm(coeff=get_diffusion_coeff(arvar[0])) | eq = TransientTerm() == DiffusionTerm(coeff=get_diffusion_coeff(arvar[0])) | ||
| Line 116: | Line 140: | ||
arvar[0].constrain(arLeft, mesh.facesLeft) | arvar[0].constrain(arLeft, mesh.facesLeft) | ||
arvar[0].constrain(arRight, mesh.facesRight) | arvar[0].constrain(arRight, mesh.facesRight) | ||
</source> | |||
Now we timestep through the solutions, and plot the solution every 50 timesteps. At each timestep, we are performing 5 sweeps (that is, we're performing 5 iterations per timestep). Again, our diffusion coefficient is not a strong function of composition, because Ar and O2 are so similar in shape/properties, so even 5 sweeps is probably unnecessary. Again, this is purely for illustrative purposes. | |||
<source> | |||
# Timestep through solutions | # Timestep through solutions | ||
arvar[0].setValue(arRight) | arvar[0].setValue(arRight) | ||
| Line 133: | Line 161: | ||
plt.show() | plt.show() | ||
plt.draw() | plt.draw() | ||
</ | </source> | ||
=Result= | |||
This will result in the following plot: | |||
[[Image:OneVarCanteraVariableD.png]] | |||
=Download The Script= | |||
Download the script here: [[File:OneVarCanteraVariableD.py]] | |||
=References= | |||
Fipy documentation covering 1D diffusion problems: http://www.ctcms.nist.gov/fipy/examples/diffusion/generated/examples.diffusion.mesh1D.html | |||
[[Category:Cantera]] | [[Category:Cantera]] | ||
[[Category:Fipy]] | [[Category:Fipy]] | ||
Revision as of 23:58, 19 December 2013
Overview
This example illustrates how to solve a simple, time-dependent 1D diffusion problem using Fipy with diffusion coefficeints computed by Cantera.
The equation being solved is:
$ \dfrac{\partial X_i}{\partial t} = \nabla \cdot \left( D_i \nabla X_i \right) $
subject to boundary conditions:
$ X_i ( x=0 ) = 1 X_i ( x=1 ) = 0 $
The mixture being used is argon in oxygen. Although the diffusion coefficient is a very weak function of composition, and therefore the assumption
$ D_i \neq D_i(X_i) $
would normally apply, this example illustrates the sweep solution technique (in which the diffusion coefficient is a function of the composition) anyway.
The Script
Begin with import statements:
from fipy import *
from numpy import *
import Cantera
import matplotlib.pylab as plt
Next, create a plot, which we'll use to visualize our results:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('Ar')Computing the diffusion coefficient using Cantera proceeds as follows:
- Pass in a Fipy CellVariable object
- Create a CellVariable to contain diffusion coefficient values
- Looping over each cell:
- Translate the value of the Fipy CellVariable at a given cell into a thermochemical state for a Cantera phase object (we want to use a single Cantera phase object, so we don't have to keep loading our CTI/XML mechanism file into memory)
- Compute the value of the diffusion coefficient
- Populate the diffusion CellVariable
- Return the diffusion CellVariable
We'll define this in a function, which we can then pass when specifying the diffusion coefficient for the Fipy equation.
######################################
# Diffusion coefficient function
def get_diffusion_coeff( phi ):
D = CellVariable(name="DiffusionCoeff",mesh=mesh)
for i in range(phi.shape[0]):
var = phi.value[i]
X0 = "AR:%0.8f, O2:%0.8f"%(var,1-var)
a.set(X=X0)
# mixture-averaged diffusion coefficients
Dcoeff = a.mixDiffCoeffs()[ari]
D.put(i,Dcoeff)
return DWe also want to define a single Cantera phase, which we'll use in the get_diffusion_coeff() function:
######################################
# Gas object
#
# This object will be used to evaluate all thermodynamic, kinetic,
# and transport properties
#
rxnmech = 'h2o2.cti' # reaction mechanism file
mix = 'ohmech' # gas mixture model
comp = 'O2:1.0, AR:1.0' # gas composition
a = Cantera.IdealGasMix(rxnmech, mix)
a.set(T = 298.15, P = Cantera.OneAtm, X = comp)
arlab = 'AR'
o2lab = 'O2'
ari = a.speciesIndex(arlab)
o2i = a.speciesIndex(o2lab)
</pre>
Now we define Fipy equations/grid:
<pre>
# First, define the mesh
nx = 100
dx = 0.01
L = nx * dx
xs = linspace(0,L,nx)
mesh = Grid1D(nx=nx,dx=dx)
# Define boundary values
arLeft = 1.
arRight = 0.
# Define timestep-related parameters
# Courant stability constraint for timestep
D0 = 1.0e-5
safetyFactor = 0.9
timestepDuration = safetyFactor * dx**2 / (2 * D0)
# Simulation duration
steps = 500
print "Nsteps =",steps
t = timestepDuration * steps
# Now define your sweep variables
arvar = [CellVariable(name=arlab, mesh=mesh, value=arRight, hasOld=1)]At this point, we can define the Fipy equation that we're solving, which is, as given above,
$ \dfrac{\partial X_i}{\partial t} = \nabla \cdot \left( D \nabla X_i \right) $
and the diffusion coefficient is a function of $ X_i $. This is subject to the boundary conditions set above (1 on the left side of the domain, 0 on the right side of the domain).
# Define the equation being solved
eq = TransientTerm() == DiffusionTerm(coeff=get_diffusion_coeff(arvar[0]))
# Set the boundary conditions
arvar[0].constrain(arLeft, mesh.facesLeft)
arvar[0].constrain(arRight, mesh.facesRight)Now we timestep through the solutions, and plot the solution every 50 timesteps. At each timestep, we are performing 5 sweeps (that is, we're performing 5 iterations per timestep). Again, our diffusion coefficient is not a strong function of composition, because Ar and O2 are so similar in shape/properties, so even 5 sweeps is probably unnecessary. Again, this is purely for illustrative purposes.
# Timestep through solutions
arvar[0].setValue(arRight)
for step in range(steps):
# only move forward in time once per time step
arvar[0].updateOld()
# but "sweep" many times per time step
for sweep in range(5):
res = eq.sweep(var=arvar[0],
dt=timestepDuration)
if step%50==0:
ax.plot(xs,arvar[0].value)
ax.hold(True)
plt.show()
plt.draw()Result
This will result in the following plot:
Download The Script
Download the script here: File:OneVarCanteraVariableD.py
References
Fipy documentation covering 1D diffusion problems: http://www.ctcms.nist.gov/fipy/examples/diffusion/generated/examples.diffusion.mesh1D.html
