def test_sofc(self): gas_a, anode_bulk, oxide_a = ct.import_phases( 'sofc.cti', ['gas', 'metal', 'oxide_bulk']) self.assertNear(gas_a.P, ct.one_atm) self.assertNear(anode_bulk['electron'].X, 1.0) self.assertNear(oxide_a.density, 700)
def setUp(self): self.phases = ct.import_phases('KOH.xml', [ 'K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma' ]) self.mix = ct.Mixture(self.phases)
def test_sofc(self): gas_a, anode_bulk, oxide_a = ct.import_phases( "../../interfaces/cython/cantera/examples/surface_chemistry/sofc.cti", ["gas", "metal", "oxide_bulk"] ) self.assertNear(gas_a.P, ct.one_atm) self.assertNear(anode_bulk["electron"].X, 1.0) self.assertNear(oxide_a.density, 700)
def test_sofc(self): gas_a, anode_bulk, oxide_a = ct.import_phases( '../../interfaces/cython/cantera/examples/surface_chemistry/sofc.cti', ['gas', 'metal', 'oxide_bulk']) self.assertNear(gas_a.P, ct.one_atm) self.assertNear(anode_bulk['electron'].X, 1.0) self.assertNear(oxide_a.density, 700)
def test_sofc(self): mech = 'sofc-test.xml' T = 1073.15 # T in K P = ct.one_atm TPB_length_per_area = 1.0e7 # TPB length per unit area [1/m] def newton_solve(f, xstart, C=0.0): """ Solve f(x) = C by Newton iteration. """ x0 = xstart dx = 1.0e-6 n = 0 while True: n += 1 f0 = f(x0) - C x0 -= f0/(f(x0 + dx) - C - f0)*dx if n > 1000: raise Exception('No convergence in Newton solve') if abs(f0) < 0.00001: return x0 # Anode-side phases gas_a, anode_bulk, oxide_a = ct.import_phases(mech, ['gas', 'metal', 'oxide_bulk',]) anode_surf = ct.Interface(mech, 'metal_surface', [gas_a]) oxide_surf_a = ct.Interface(mech, 'oxide_surface', [gas_a, oxide_a]) tpb_a = ct.Interface(mech, 'tpb', [anode_bulk, anode_surf, oxide_surf_a]) # Cathode-side phases gas_c, cathode_bulk, oxide_c = ct.import_phases(mech, ['gas', 'metal', 'oxide_bulk']) cathode_surf = ct.Interface(mech, 'metal_surface', [gas_c]) oxide_surf_c = ct.Interface(mech, 'oxide_surface', [gas_c, oxide_c]) tpb_c = ct.Interface(mech, 'tpb', [cathode_bulk, cathode_surf, oxide_surf_c]) def anode_curr(E): anode_bulk.electric_potential = E w = tpb_a.net_production_rates return ct.faraday * w[0] * TPB_length_per_area def cathode_curr(E): cathode_bulk.electric_potential = E + oxide_c.electric_potential w = tpb_c.net_production_rates return -ct.faraday * w[0] * TPB_length_per_area # initialization gas_a.TPX = T, P, 'H2:0.97, H2O:0.03' gas_a.equilibrate('TP') gas_c.TPX = T, P, 'O2:1.0, H2O:0.001' gas_c.equilibrate('TP') for p in [anode_bulk, anode_surf, oxide_surf_a, oxide_a, cathode_bulk, cathode_surf, oxide_surf_c, oxide_c, tpb_a, tpb_c]: p.TP = T, P for s in [anode_surf, oxide_surf_a, cathode_surf, oxide_surf_c]: s.advance_coverages(50.0) # These values are just a regression test with no theoretical basis self.assertArrayNear(anode_surf.coverages, [6.18736755e-01, 3.81123779e-01, 8.63037850e-05, 2.59274708e-06, 5.05702339e-05]) self.assertArrayNear(oxide_surf_a.coverages, [4.99435780e-02, 9.48927983e-01, 1.12840577e-03, 3.35936530e-08]) self.assertArrayNear(cathode_surf.coverages, [1.48180380e-07, 7.57234727e-14, 9.99999827e-01, 2.49235513e-08, 4.03296469e-13]) self.assertArrayNear(oxide_surf_c.coverages, [4.99896947e-02, 9.49804199e-01, 2.06104969e-04, 1.11970271e-09]) Ea0 = newton_solve(anode_curr, xstart=-0.51) Ec0 = newton_solve(cathode_curr, xstart=0.51) data = [] # vary the anode overpotential, from cathodic to anodic polarization for Ea in np.linspace(Ea0 - 0.25, Ea0 + 0.25, 20): anode_bulk.electric_potential = Ea curr = anode_curr(Ea) delta_V = curr * 5.0e-5 / 2.0 phi_oxide_c = -delta_V oxide_c.electric_potential = phi_oxide_c oxide_surf_c.electric_potential = phi_oxide_c Ec = newton_solve(cathode_curr, xstart=Ec0+0.1, C=curr) cathode_bulk.electric_potential = phi_oxide_c + Ec data.append([Ea - Ea0, 0.1*curr, Ec - Ec0, delta_V, cathode_bulk.electric_potential - anode_bulk.electric_potential]) self.compare(data, '../data/sofc-test.csv')
This example computes the growth rate of a diamond film according to a simplified version of a particular published growth mechanism (see file diamond.cti for details). Only the surface coverage equations are solved here; the gas composition is fixed. (For an example of coupled gas- phase and surface, see catalytic_combustion.py.) Atomic hydrogen plays an important role in diamond CVD, and this example computes the growth rate and surface coverages as a function of [H] at the surface for fixed temperature and [CH3]. """ import csv import cantera as ct print('\n****** CVD Diamond Example ******\n') # import the models for the gas and bulk diamond g, dbulk = ct.import_phases('diamond.cti', ['gas', 'diamond']) # import the model for the diamond (100) surface d = ct.Interface('diamond.cti', 'diamond_100', [g, dbulk]) ns = d.n_species mw = dbulk.molecular_weights[0] t = 1200.0 x = g.X p = 20.0 * ct.one_atm / 760.0 # 20 Torr g.TP = t, p ih = g.species_index('H') xh0 = x[ih]
model that will consider one species in the SEI, one species in the electrolyte, and track temperature, concentration, and electrical potential of the species in a discretized grid employing a finite volume method. """ # %% Modules imported import numpy as np from matplotlib import pyplot as plt import cantera as ct from sei_1d_inputs import * """----------Geometry calcs----------""" dx = x / N_x # USER INPUT length of step in x direction dy = y / N_y # USER INPUT length of step in y direction """----------Create Cantera objects----------""" CE, elyte, sei, sei_conductor, WE = ct.import_phases(ctifile, \ [CE_phase, elyte_phase, sei_phase, sei_conductorphase, WE_phase]) WE_elyte = ct.Interface(ctifile, WE_elyte_surfphase, [WE, elyte, sei]) WE_sei = ct.Interface(ctifile, WE_sei_surfphase, \ [WE, sei, sei_conductor]) sei_elyte = ct.Interface(ctifile, sei_elyte_surfphase, \ [sei, elyte, sei_conductor]) CE_elyte = ct.Interface(ctifile, CE_surfphase, [CE, elyte]) print('\n Cantera phases created. \n') """----------Set phase properties for cantera objects----------""" TP_o = T_0, P_0 elyte.TP = TP_o sei.TP = TP_o WE.TP = TP_o CE.TP = TP_o WE_elyte.TP = TP_o
step = 0.1*step/abs(step) x0 += step emax = 0.00001 # 0.01 mV tolerance if abs(f0) < emax and n > 8: return x0 f0 = f(x0) - C n += 1 raise Exception('no root!') ##################################################################### # Anode-side phases ##################################################################### # import the anode-side bulk phases gas_a, anode_bulk, oxide_a = ct.import_phases('sofc.cti', ['gas', 'metal', 'oxide_bulk',]) # import the surfaces on the anode side anode_surf = ct.Interface('sofc.cti', 'metal_surface', [gas_a]) oxide_surf_a = ct.Interface('sofc.cti', 'oxide_surface', [gas_a, oxide_a]) # import the anode-side triple phase boundary tpb_a = ct.Interface('sofc.cti', 'tpb', [anode_bulk, anode_surf, oxide_surf_a]) anode_surf.name = 'anode surface' oxide_surf_a.name = 'anode-side oxide surface' # this function is defined to use with NewtonSolver to invert the current- # voltage function. NewtonSolver requires a function of one variable, so the # other objects are accessed through the global namespace.
def test_diamond(self): gas, solid = ct.import_phases('diamond.cti', ['gas','diamond']) face = ct.Interface('diamond.cti', 'diamond_100', [gas, solid]) self.assertNear(face.site_density, 3e-8)
An equilibrium example with charged species in the gas phase and multiple condensed phases. Requires: cantera >= 2.5.0, matplotlib >= 2.0 Keywords: equilibrium, multiphase, plasma, saving output """ import cantera as ct import csv # create objects representing the gas phase and the condensed phases. The gas # is a mixture of multiple species, and the condensed phases are all modeled # as incompressible stoichiometric substances. See file KOH.yaml for more # information. phases = ct.import_phases('KOH.yaml', [ 'K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma' ]) # create the Mixture object from the list of phases mix = ct.Mixture(phases) equil_data = [] # loop over temperature for n in range(100): t = 350.0 + 50.0 * n print('T = {0}'.format(t)) mix.T = t mix.P = ct.one_atm mix.species_moles = "K:1.03, H2:2.12, O2:0.9" # set the mixture to a state of chemical equilibrium holding
import numpy as np import pandas as pd from matplotlib import pyplot as plt from SEI_prelim_functions import df_2spec2var from SEI_prelim_functions import IC_fun import cantera as ct from assimulo.solvers import IDA from assimulo.problem import Implicit_Problem cantera_file = 'W_anode_chem.cti' elyte_name = 'electrolyte' SEI_name = 'SEI' anode_name = 'tungsten' anode_elyte_surf = 'tungsten_electrolyte_surf' elyte, SEI, anode = ct.import_phases(cantera_file, \ [elyte_name, SEI_name, anode_name]) anode_elyte = ct.Interface(cantera_file, anode_elyte_surf, [anode, elyte, SEI]) # %% Define grid variables """----------Define grid dimensions----------""" # A (2,10) grid will be indexed as shown below with each node having the # number of tracked variables stored for it. The solution vector will be # a row vector progressing through each tracked variable for each cell, then # progressing in increasing column number for increasing row number. # # |--> electrolyte # | # |-----------------------------------------------------------|
def setUpClass(cls): cls.phases = ct.import_phases('KOH.xml', [ 'K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma' ])
def __init__(self, config_file, prep_capex=0, prep_opex=0, prep_revenue=0, prep_npv=0): """Constructor. """ self.confDict = utilities.read_config(config_file) solventxHome = self.confDict["solventxHome"] reeComps = self.confDict['compositions'] self.xmlData = self.confDict['xmlData'] self.modulesData = self.confDict['modules'] self.xml = os.path.join( solventxHome, self.xmlData['xml'], self.xmlData['phase'] + '_' + ''.join(self.modulesData["input"]) + '.xml') # Set required data self.phase_names = self.confDict["phasenames"] # from xml input file self.phase = ct.import_phases(self.xml, self.phase_names) # Derived and/or reusable system parameters self.column = self.coltypes # Column name self.solv = self.confDict[ "solvents"] # solvent list -.i.e., electrolyte, extractant and organic diluent # ree by modules self.ree = self.modulesData[ "input"] #self.REEs[self.moduleID] # (rare earth) metal list # Cantera indices self.mix = ct.Mixture(self.phase) self.aq = self.mix.phase_index(self.phase_names[0]) self.org = self.mix.phase_index(self.phase_names[1]) self.ns = self.mix.n_species self.naq = self.mix.phase(self.aq).n_species self.norg = self.mix.phase(self.org).n_species self.HA_Index = self.mix.species_index( self.org, '(HA)2(org)') # index of extractant in canera species list self.Hp_Index = self.mix.species_index( self.aq, 'H+') # index of H+ in cantera species list self.Cl_Index = self.mix.species_index( self.aq, 'Cl-') # index of Cl in cantera species list self.canteranames = self.mix.species_names self.fixed_species = ['H2O(L)', 'OH-', 'Cl-', 'dodecane'] self.canteravars = [ ij for ij in self.canteranames if ij not in self.fixed_species ] # 'Cl-', self.nsy = len(self.canteravars) self.naqy = len([ ij for ij in self.mix.species_names[:self.naq] if ij not in self.fixed_species ]) self.norgy = len([ ij for ij in self.mix.species_names[self.naq:] if ij not in self.fixed_species ]) self.mwre,\ self.mwslv = self.get_mw() # g/mol self.rhoslv = [1000, 960, 750] # [g/L] self.upper = [reeComps[i]['upper'] for i in self.ree] self.lower = [reeComps[i]['lower'] for i in self.ree] ree_mass = [ np.random.uniform(i, j) for i, j in zip(self.lower, self.upper) ] self.get_conc(ree_mass) self.purity_spec = .99 # not needed? self.recov_spec = .99 # not needed? self.revenue = [0, 0, 0] self.Ns = [0, 0, 0] self.nsp = pd.DataFrame() # feed streams (aq and org) for each column self.nsp0 = pd.DataFrame() # feed streams (aq and org) for each column self.y = {} # all compositions self.Ns = {}
def setUpClass(cls): cls.phases = ct.import_phases('KOH.xml', ['K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma'])
def test_diamond(self): gas, solid = ct.import_phases("diamond.cti", ["gas", "diamond"]) face = ct.Interface("diamond.cti", "diamond_100", [gas, solid]) self.assertNear(face.site_density, 3e-8)
def test_sofc(self): mech = 'sofc-test.xml' T = 1073.15 # T in K P = ct.one_atm TPB_length_per_area = 1.0e7 # TPB length per unit area [1/m] def newton_solve(f, xstart, C=0.0): """ Solve f(x) = C by Newton iteration. """ x0 = xstart dx = 1.0e-6 while True: f0 = f(x0) - C x0 -= f0 / (f(x0 + dx) - C - f0) * dx if abs(f0) < 0.00001: return x0 # Anode-side phases gas_a, anode_bulk, oxide_a = ct.import_phases(mech, [ 'gas', 'metal', 'oxide_bulk', ]) anode_surf = ct.Interface(mech, 'metal_surface', [gas_a]) oxide_surf_a = ct.Interface(mech, 'oxide_surface', [gas_a, oxide_a]) tpb_a = ct.Interface(mech, 'tpb', [anode_bulk, anode_surf, oxide_surf_a]) # Cathode-side phases gas_c, cathode_bulk, oxide_c = ct.import_phases( mech, ['gas', 'metal', 'oxide_bulk']) cathode_surf = ct.Interface(mech, 'metal_surface', [gas_c]) oxide_surf_c = ct.Interface(mech, 'oxide_surface', [gas_c, oxide_c]) tpb_c = ct.Interface(mech, 'tpb', [cathode_bulk, cathode_surf, oxide_surf_c]) def anode_curr(E): anode_bulk.electric_potential = E w = tpb_a.net_production_rates return ct.faraday * w[0] * TPB_length_per_area def cathode_curr(E): cathode_bulk.electric_potential = E + oxide_c.electric_potential w = tpb_c.net_production_rates return -ct.faraday * w[0] * TPB_length_per_area # initialization gas_a.TPX = T, P, 'H2:0.97, H2O:0.03' gas_a.equilibrate('TP') gas_c.TPX = T, P, 'O2:1.0, H2O:0.001' gas_c.equilibrate('TP') for p in [ anode_bulk, anode_surf, oxide_surf_a, oxide_a, cathode_bulk, cathode_surf, oxide_surf_c, oxide_c, tpb_a, tpb_c ]: p.TP = T, P for s in [anode_surf, oxide_surf_a, cathode_surf, oxide_surf_c]: s.advance_coverages(50.0) # These values are just a regression test with no theoretical basis self.assertArrayNear(anode_surf.coverages, [ 6.18736755e-01, 3.81123779e-01, 8.63037850e-05, 2.59274708e-06, 5.05702339e-05 ]) self.assertArrayNear( oxide_surf_a.coverages, [4.99435780e-02, 9.48927983e-01, 1.12840577e-03, 3.35936530e-08]) self.assertArrayNear(cathode_surf.coverages, [ 1.48180380e-07, 7.57234727e-14, 9.99999827e-01, 2.49235513e-08, 4.03296469e-13 ]) self.assertArrayNear( oxide_surf_c.coverages, [4.99896947e-02, 9.49804199e-01, 2.06104969e-04, 1.11970271e-09]) Ea0 = newton_solve(anode_curr, xstart=-0.51) Ec0 = newton_solve(cathode_curr, xstart=0.51) data = [] # vary the anode overpotential, from cathodic to anodic polarization for Ea in np.linspace(Ea0 - 0.25, Ea0 + 0.25, 20): anode_bulk.electric_potential = Ea curr = anode_curr(Ea) delta_V = curr * 5.0e-5 / 2.0 phi_oxide_c = -delta_V oxide_c.electric_potential = phi_oxide_c oxide_surf_c.electric_potential = phi_oxide_c Ec = newton_solve(cathode_curr, xstart=Ec0 + 0.1, C=curr) cathode_bulk.electric_potential = phi_oxide_c + Ec data.append([ Ea - Ea0, 0.1 * curr, Ec - Ec0, delta_V, cathode_bulk.electric_potential - anode_bulk.electric_potential ]) self.compare(data, '../data/sofc-test.csv')
def setUp(self): self.phases = ct.import_phases('KOH.xml', ['K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma']) self.mix = ct.Mixture(self.phases)
def test_diamond(self): gas, solid = ct.import_phases('diamond.cti', ['gas', 'diamond']) face = ct.Interface('diamond.cti', 'diamond_100', [gas, solid]) self.assertNear(face.site_density, 3e-8)
""" An equilibrium example with charged species in the gas phase and multiple condensed phases. """ import cantera as ct import csv # create objects representing the gas phase and the condensed phases. The gas # is a mixture of multiple species, and the condensed phases are all modeled # as incompressible stoichiometric substances. See file KOH.cti for more # information. phases = ct.import_phases('KOH.cti', ['K_solid', 'K_liquid', 'KOH_a', 'KOH_b', 'KOH_liquid', 'K2O2_solid', 'K2O_solid', 'KO2_solid', 'ice', 'liquid_water', 'KOH_plasma']) # create the Mixture object from the list of phases mix = ct.Mixture(phases) csvfile = open('equil_koh.csv', 'w') writer = csv.writer(csvfile) writer.writerow(['T'] + mix.species_names) # loop over temperature for n in range(100): t = 350.0 + 50.0*n print('T = {0}'.format(t)) mix.T = t mix.P = ct.one_atm mix.species_moles = "K:1.03, H2:2.12, O2:0.9"