Exemple #1
0
    def setup(self, T0, P0, mdot_fuel, mdot_ox):

        self.gas = ct.Solution('gri30.xml')

        # fuel inlet
        self.gas.TPX = T0, P0, "CH4:1.0"
        self.fuel_in = ct.Reservoir(self.gas)

        # oxidizer inlet
        self.gas.TPX = T0, P0, "N2:3.76, O2:1.0"
        self.oxidizer_in = ct.Reservoir(self.gas)

        # reactor, initially filled with N2
        self.gas.TPX = T0, P0, "N2:1.0"
        self.combustor = ct.IdealGasReactor(self.gas)
        self.combustor.volume = 1.0

        # outlet
        self.exhaust = ct.Reservoir(self.gas)

        # connect the reactor to the reservoirs
        self.fuel_mfc = ct.MassFlowController(self.fuel_in, self.combustor)
        self.fuel_mfc.set_mass_flow_rate(mdot_fuel)
        self.oxidizer_mfc = ct.MassFlowController(self.oxidizer_in, self.combustor)
        self.oxidizer_mfc.set_mass_flow_rate(mdot_ox)
        self.valve = ct.Valve(self.combustor, self.exhaust)
        self.valve.set_valve_coeff(1.0)

        self.net = ct.ReactorNet()
        self.net.add_reactor(self.combustor)
        self.net.max_err_test_fails = 10
Exemple #2
0
    def connectReactors(self):
        """Use this function to connect exhaust reactors."""

        #Connecting fuel res -> combustor
        def inflow(
                t
        ):  # inflow is a variable mass flow rate base on residence time
            return self.reactors[0].mass / self.residenceTime(t)

        self.inflow = inflow
        self.controllers = ct.MassFlowController(
            self.fuelReservoir, self.reactors[0],
            mdot=self.inflow),  #Fuel Air Mixture MFC
        #Connecting combustor -> exhaust
        self.controllers += ct.MassFlowController(
            self.reactors[0], self.reactors[1],
            mdot=self.inflow),  #Exhaust MFC
        #Connecting exhausts -> adj exhaust
        exStart = 1  #starting index of exhaust reactors
        for f, row in enumerate(self.connects[:-1], exStart):
            sink = np.sum(
                row
            )  #number of places the mass flow goes from one reactor to another
            if sink != 0:  #Connects non-terminal exhaust reactors
                for t, value in enumerate(row[:-1], start=exStart):
                    if value:
                        #Using a closure to create mass flow function
                        def mdot(t, fcn=None):
                            return (self.reactors[fcn.ridx].mass /
                                    self.residenceTime(t)) / fcn.sink

                        mdot.__defaults__ = (mdot, )
                        mdot.sink = sink  #number of places the mass flow goes from one reactor to another
                        mdot.ridx = np.copy(f)
                        #Create controller
                        self.controllers += ct.MassFlowController(
                            self.reactors[f], self.reactors[t],
                            mdot=mdot),  #Exhaust MFCS
            else:  #This else statement connects all terminal exhaust reactors to exhaust reservoir
                #Using a closure to create mass flow function
                def mdot(t, fcn=None):
                    return (self.reactors[fcn.ridx].mass /
                            self.residenceTime(t))

                mdot.__defaults__ = (mdot, )
                mdot.sink = sink  #number of places the mass flow goes from one reactor to another
                mdot.ridx = np.copy(f)
                #Create controller
                self.controllers += ct.MassFlowController(
                    self.reactors[f], self.exhaustReservoir,
                    mdot=mdot),  #Exhaust MFCS

        #entrainment controllers
        for t, value in enumerate(self.connects[-1], exStart):
            if value:
                self.controllers += ct.MassFlowController(
                    self.atmosReservoir,
                    self.reactors[t],
                    mdot=self.entrainment),  #Exhaust MFCS
Exemple #3
0
    def create_reactors(self, add_Q=False, add_mdot=False, add_surf=False):
        self.gas = ct.Solution('gri30.xml')
        self.gas.TPX = 900, 25*ct.one_atm, 'CO:0.5, H2O:0.2'

        self.gas1 = ct.Solution('gri30.xml')
        self.gas1.ID = 'gas'
        self.gas2 = ct.Solution('gri30.xml')
        self.gas2.ID = 'gas'
        resGas = ct.Solution('gri30.xml')
        solid = ct.Solution('diamond.xml', 'diamond')

        T0 = 1200
        P0 = 25*ct.one_atm
        X0 = 'CH4:0.5, H2O:0.2, CO:0.3'

        self.gas1.TPX = T0, P0, X0
        self.gas2.TPX = T0, P0, X0

        self.r1 = ct.IdealGasReactor(self.gas1)
        self.r2 = self.reactorClass(self.gas2)

        self.r1.volume = 0.2
        self.r2.volume = 0.2

        resGas.TP = T0 - 300, P0
        env = ct.Reservoir(resGas)

        U = 300 if add_Q else 0

        self.w1 = ct.Wall(self.r1, env, K=1e3, A=0.1, U=U)
        self.w2 = ct.Wall(self.r2, env, A=0.1, U=U)

        if add_mdot:
            mfc1 = ct.MassFlowController(env, self.r1, mdot=0.05)
            mfc2 = ct.MassFlowController(env, self.r2, mdot=0.05)

        if add_surf:
            self.interface1 = ct.Interface('diamond.xml', 'diamond_100',
                                      (self.gas1, solid))
            self.interface2 = ct.Interface('diamond.xml', 'diamond_100',
                                      (self.gas2, solid))

            C = np.zeros(self.interface1.n_species)
            C[0] = 0.3
            C[4] = 0.7
            self.surf1 = ct.ReactorSurface(self.interface1, A=0.2)
            self.surf2 = ct.ReactorSurface(self.interface2, A=0.2)
            self.surf1.coverages = C
            self.surf2.coverages = C
            self.surf1.install(self.r1)
            self.surf2.install(self.r2)

        self.net1 = ct.ReactorNet([self.r1])
        self.net2 = ct.ReactorNet([self.r2])
        self.net1.set_max_time_step(0.05)
        self.net2.set_max_time_step(0.05)
        self.net2.max_err_test_fails = 10
Exemple #4
0
    def setUp(self):
        self.gas = ct.Solution('h2o2.xml')

        # create a reservoir for the fuel inlet, and set to pure methane.
        self.gas.TPX = 300.0, ct.one_atm, 'H2:1.0'
        fuel_in = ct.Reservoir(self.gas)
        fuel_mw = self.gas.mean_molecular_weight

        # Oxidizer inlet
        self.gas.TPX = 300.0, ct.one_atm, 'O2:1.0, AR:3.0'
        oxidizer_in = ct.Reservoir(self.gas)
        oxidizer_mw = self.gas.mean_molecular_weight

        # to ignite the fuel/air mixture, we'll introduce a pulse of radicals.
        # The steady-state behavior is independent of how we do this, so we'll
        # just use a stream of pure atomic hydrogen.
        self.gas.TPX = 300.0, ct.one_atm, 'H:1.0'
        self.igniter = ct.Reservoir(self.gas)

        # create the combustor, and fill it in initially with a diluent
        self.gas.TPX = 300.0, ct.one_atm, 'AR:1.0'
        self.combustor = ct.IdealGasReactor(self.gas)

        # create a reservoir for the exhaust
        self.exhaust = ct.Reservoir(self.gas)

        # compute fuel and air mass flow rates
        factor = 0.1
        oxidizer_mdot = 4 * factor * oxidizer_mw
        fuel_mdot = factor * fuel_mw

        # The igniter will use a time-dependent igniter mass flow rate.
        def igniter_mdot(t, t0=0.1, fwhm=0.05, amplitude=0.1):
            return amplitude * math.exp(
                -(t - t0)**2 * 4 * math.log(2) / fwhm**2)

        # create and install the mass flow controllers. Controllers
        # m1 and m2 provide constant mass flow rates, and m3 provides
        # a short Gaussian pulse only to ignite the mixture
        m1 = ct.MassFlowController(fuel_in, self.combustor, mdot=fuel_mdot)
        m2 = ct.MassFlowController(oxidizer_in,
                                   self.combustor,
                                   mdot=oxidizer_mdot)
        m3 = ct.MassFlowController(self.igniter,
                                   self.combustor,
                                   mdot=igniter_mdot)

        # put a valve on the exhaust line to regulate the pressure
        self.v = ct.Valve(self.combustor, self.exhaust, K=1.0)

        # the simulation only contains one reactor
        self.sim = ct.ReactorNet([self.combustor])
 def run_single(self):
     
     gas=self.processor.solution
     reactorPressure=gas.P
     self.reactorPressure=self.processor.solution.P
     pressureValveCoefficient=self.pvalveCoefficient
     maxPressureRiseAllowed=self.maxPrise
     
     print(maxPressureRiseAllowed,self.reactorPressure,pressureValveCoefficient)
     #Build the system components for JSR
     fuelAirMixtureTank=ct.Reservoir(self.processor.solution)
     exhaust=ct.Reservoir(self.processor.solution)
     
     stirredReactor=ct.IdealGasReactor(self.processor.solution,energy=self.energycon,volume=self.reactor_volume)
     massFlowController=ct.MassFlowController(upstream=fuelAirMixtureTank,
                                              downstream=stirredReactor,mdot=stirredReactor.mass/self.residence_time)
     pressureRegulator=ct.Valve(upstream=stirredReactor,downstream=exhaust,K=pressureValveCoefficient)
     reactorNetwork=ct.ReactorNet([stirredReactor])
     
     if bool(self.observables) and self.kineticSens==1:
         for i in range(gas.n_reactions):
             stirredReactor.add_sensitivity_reaction(i)
         
     if self.kineticSens and bool(self.observables)==False:
         #except:
             print('Please supply a non-empty list of observables for sensitivity analysis or set kinetic_sens=0')
     if self.physicalSens==1 and bool(self.observables)==False:
Exemple #6
0
    def setup_reactor(self):
        self.gas = ct.Solution(self.rxnmech)
        self.xinit = {"O2": 0.21, "N2": 0.79}
        self.gas.TPX = self.T0, self.p0, self.xinit

        self.injection_gas, _ = setup_injection_gas(self.rxnmech,
                                                    self.fuel,
                                                    pure_fuel=True)
        self.injection_gas.TP = self.T0, self.p0
        fuel_res = ct.Reservoir(self.injection_gas)

        # Create the reactor object
        self.reactor = ct.Reactor(self.gas)
        self.rempty = ct.Reactor(self.gas)

        # Set the initial states of the reactor
        self.reactor.chemistry_enabled = True
        self.reactor.volume = self.history["V"][0]

        # Add in a fuel injector
        self.injector = ct.MassFlowController(fuel_res, self.reactor)

        # Add in a wall that moves according to piston velocity
        self.piston = ct.Wall(
            left=self.reactor,
            right=self.rempty,
            A=np.pi / 4.0 * self.bore**2,
            U=0.0,
            velocity=self.history["piston_velocity"][0],
        )

        # Create the network object
        self.sim = ct.ReactorNet([self.reactor])
Exemple #7
0
def solve(gas, t):
    # Set the temperature and pressure for gas
    # t is different from t0
    gas.TPX = t, pressure, composition
    surf.TP = t, pressure
    TDY = gas.TDY
    cov = surf.coverages

    # create a new reactor
    gas.TDY = TDY
    r = ct.IdealGasReactor(gas, energy='on')
    r.volume = rvol

    upstream = ct.Reservoir(gas, name='upstream')
    downstream = ct.Reservoir(gas, name='downstream')
    rsurf = ct.ReactorSurface(surf, r, A=cat_area)
    m = ct.MassFlowController(upstream, r, mdot=mass_flow_rate)

    v = ct.PressureController(r, downstream, master=m, K=1e-5)

    sim = ct.ReactorNet([r])
    sim.max_err_test_fails = 20
    sim.rtol = 1.0e-9
    sim.atol = 1.0e-21

    # define time, space, and other information vectors
    z2 = (np.arange(NReactors)) * rlen * 1e3

    t_r2 = np.zeros_like(z2)  # residence time in each reactor

    t2 = np.zeros_like(z2)
    states2 = ct.SolutionArray(gas)

    for n in range(NReactors):
        # Set the state of the reservoir to match that of the previous reactor
        gas.TDY = r.thermo.TDY
        upstream.syncState()
        sim.reinitialize()

        sim.advance_to_steady_state()
        dist = n * rlen * 1.0e3  # distance in mm

        t_r2[n] = r.mass / mass_flow_rate  # residence time in this reactor
        t2[n] = np.sum(t_r2)
        states2.append(gas.state)
    print('Temperature of Gas :', t, ' residence time :', t2[-1])
    MolFrac_CH4 = states2('CH4').X
    MolFrac_CO2 = states2('CO2').X
    MolFrac_CO = states2('CO').X
    MolFrac_H2 = states2('H2').X
    MolFrac_H2O = states2('H2O').X
    MolFrac_O2 = states2('O2').X
    kq = np.zeros(6)
    kq[0] = MolFrac_CH4[-1] * 100
    kq[1] = MolFrac_CO2[-1] * 100
    kq[2] = MolFrac_CO[-1] * 100
    kq[3] = MolFrac_H2[-1] * 100
    kq[4] = MolFrac_H2O[-1] * 100
    kq[5] = MolFrac_O2[-1] * 100
    return kq
Exemple #8
0
    def test_mass_flow_controller(self):
        self.makeReactors(nReactors=1)
        gas2 = ct.Solution('h2o2.xml')
        gas2.TPX = 300, 10*101325, 'H2:1.0'
        reservoir = ct.Reservoir(gas2)

        mfc = ct.MassFlowController(reservoir, self.r1)
        mfc.setMassFlowRate(lambda t: 0.1 if 0.2 <= t < 1.2 else 0.0)

        self.assertEqual(len(reservoir.inlets), 0)
        self.assertEqual(len(reservoir.outlets), 1)
        self.assertEqual(reservoir.outlets[0], mfc)
        self.assertEqual(len(self.r1.outlets), 0)
        self.assertEqual(len(self.r1.inlets), 1)
        self.assertEqual(self.r1.inlets[0], mfc)

        ma = self.r1.volume * self.r1.density
        Ya = self.r1.Y

        self.net.advance(2.5)

        mb = self.r1.volume * self.r1.density
        Yb = self.r1.Y

        self.assertNear(ma + 0.1, mb)
        self.assertArrayNear(ma * Ya + 0.1 * gas2.Y, mb * Yb)
def runSinglePSR(T, P, moleFraction, factor, reactionIndex, targetSpc):

    start = time.time()

    # create the gas mixture
    gas = ct.Solution('HXD15_Battin_mech.xml')
    gas.TPX = T, P, moleFraction

    # create an upstream reservoir that will supply the reactor. The temperature,
    # pressure, and composition of the upstream reservoir are set to those of the
    # 'gas' object at the time the reservoir is created.
    upstream = ct.Reservoir(gas)

    # Now create the reactor object with the same initial state
    cstr = ct.IdealGasReactor(gas)

    # Set its volume to 80 cm^3. In this problem, the reactor volume is fixed, so
    # the initial volume is the volume at all later times.
    cstr.volume = 80.0*1.0e-6

    # Connect the upstream reservoir to the reactor with a mass flow controller
    # (constant mdot). Set the mass flow rate.
    vdot = 40* 1.0e-6 # m^3/s
    mdot = gas.density * vdot # kg/s
    mfc = ct.MassFlowController(upstream, cstr, mdot=mdot)

    # now create a downstream reservoir to exhaust into.
    downstream = ct.Reservoir(gas)

    # connect the reactor to the downstream reservoir with a valve, and set the
    # coefficient sufficiently large to keep the reactor pressure close to the
    # downstream pressure.
    v = ct.Valve(cstr, downstream, K=1.0e-9)

    # create the network
    network = ct.ReactorNet([cstr])

    # modify the A factor of the given reaction
    gas.set_multiplier(factor,reactionIndex-1)

    # now integrate in time
    t = 0.0
    dt   = 0.1

    print "\n\n\n**************************\n***** Solving case %d *****\n"%(reactionIndex)

    while t < 30.0:
        print t
        t += dt
        network.advance(t)

    results = []
    for spc in targetSpc:
        results.append(cstr.thermo[spc].X[0]*1.0e6)

    end = time.time()
    print 'Execution time is:'
    print end - start

    return [gas.reaction_equation(reactionIndex-1)] + results
Exemple #10
0
def cstr0(self, F, P, V, T=None, dt=2.0, t=None, disp=0):
    # mix streams if there is more than one
    self, F = mixer(self, F)
    # set initial conditions
    self.TP = T, P
    # create a new reactor
    if T == None or T == 0:
        r = ct.IdealGasReactor(self, energy='on')
    else:
        r = ct.IdealGasReactor(self, energy='off')
    r.volume = V
    # create up and downstream reservoirs
    upstream = ct.Reservoir(self)
    downstream = ct.Reservoir(self)
    # set mass flow into reactor
    m = ct.MassFlowController(upstream, r, mdot=F)
    # set valve to hold pressure constant
    ct.PressureController(r, downstream, master=m, K=1e-5)
    # create reactor network
    s = ct.ReactorNet([r])
    s.rtol, s.atol, s.max_err_test_fails = rel_tol, abs_tol, test_fails
    # set parameters
    time = 0
    residual = 1
    all_done = False
    # forces reinitialization
    s.set_initial_time(0)
    while not all_done:
        Yo = r.thermo.Y
        To = r.thermo.T
        try:
            time += dt
            s.advance(time)
        except:
            dt *= 0.1
            time += dt
            s.advance(time)
        if t != None and time >= t: all_done = False
        if time > 10 * dt:
            all_done = True
            residual = slope(Yo, r.thermo.Y, dt)
            if T == None:
                residual = np.max(np.append(residual,slope(To,r.thermo.T,dt)))
            if residual > rel_tol:
                all_done = False
                break
        if disp == True: print 'Residual: %1.3e' %(residual)
    return self, time, residual
Exemple #11
0
def psr_ss(soln_in, soln_out, p, T0, T, X0, X, tau):

    #sys.stdout.flush()

    """
    find the steady state of a PSR

    :param mech:    mechanism
    :param p:       pressure (Pa)
    :param T0:      temperature (K) of the inlet flow
    :param T:       initial temperature (K) of the reactor
    :param tau:     residence time (s) of the reactor

    :return reactor:

    """

    vol = 1.0     # unit: m3
    K = 1.0
    t_end = tau * 100.0

    #print 't_end = '+str(t_end)

    soln_out.TPX = T, p, X
    soln_in.TPX = T0, p, X0

    inlet = ct.Reservoir(soln_in)
    reactor = ct.IdealGasReactor(soln_out)
    reactor.volume = vol

    vdot = vol/tau
    mdot = soln_out.density * vdot
    mfc = ct.MassFlowController(inlet, reactor, mdot=mdot)

    exhaust = ct.Reservoir(soln_out)
    valve = ct.Valve(reactor, exhaust, K=K)

    network = ct.ReactorNet([reactor])
    try:
        network.advance(t_end)
    except RuntimeError as e:

        print '@'*10+'\nct.exceptions = \n'+str(e)
        #sys.exit()
        return None

    return soln_out
Exemple #12
0
    def test_pressure_controller_errors(self):
        self.make_reactors()
        res = ct.Reservoir(self.gas1)
        mfc = ct.MassFlowController(res, self.r1, mdot=0.6)

        p = ct.PressureController(self.r1, self.r2, master=mfc, K=0.5)

        with self.assertRaises(ct.CanteraError):
            p = ct.PressureController(self.r1, self.r2, K=0.5)
            p.mdot(0.0)

        with self.assertRaises(ct.CanteraError):
            p = ct.PressureController(self.r1, self.r2, master=mfc)
            p.mdot(0.0)

        with self.assertRaises(ct.CanteraError):
            p = ct.PressureController(self.r1, self.r2)
            p.mdot(0.0)
Exemple #13
0
    def test_pressure_controller(self):
        self.makeReactors(nReactors=1)
        g = ct.Solution('h2o2.xml')
        g.TPX = 500, 2*101325, 'H2:1.0'
        inletReservoir = ct.Reservoir(g)
        g.TP = 300, 101325
        outletReservoir = ct.Reservoir(g)

        mfc = ct.MassFlowController(inletReservoir, self.r1)
        mdot = lambda t: np.exp(-100*(t-0.5)**2)
        mfc.setMassFlowRate(mdot)

        pc = ct.PressureController(self.r1, outletReservoir)
        pc.setMaster(mfc)
        pc.setPressureCoeff(1e-5)

        t = 0
        while t < 1.0:
            t = self.net.step(1.0)
            self.assertNear(mdot(t), mfc.mdot(t))
            dP = self.r1.thermo.P - outletReservoir.thermo.P
            self.assertNear(mdot(t) + 1e-5 * dP, pc.mdot(t))
 def run(self,):
     
     gas=processor.solution.P
     reactorPressure=gas
     pressureValveCoefficient=pvalveCoefficient
     maxPressureRiseAllowed=maxPrise
     
     
     #Build the system components for JSR
     fuelAirMixtureTank=ct.Reservoir(gas)
     exhaust=ct.Reservoir(gas)
     
     stirredReactor=ct.IdealGasReactor(gas,energy=energycon,volume=volume)
     massFlowController=ct.MassFlowController(upstream=fuelAirMixtureTank,
                                              downstream=stirredReactor,mdot=stirredReactor.mass/restime)
     pressureRegulator=ct.Valve(upstream=stirredReactor,downstream=exhaust,K=pressureValveCoefficient)
     reactorNetwork=ct.ReactorNet([stirredReactor])
     
     if bool(self.moleFractionObservables) and self.kineticSens==1:
         for i in range(gas.n_reactions):
             stirredReactor.add_sensitivity_reaction(i)
         
     if self.kineticSens and bool(self.moleFractionObservables)==False:
         except:
# temperature.
env = ct.Reservoir(gas)

# Create a heat-conducting wall between the reactor and the environment. Set its
# area, and its overall heat transfer coefficient. Larger U causes the reactor
# to be closer to isothermal. If U is too small, the gas ignites, and the
# temperature spikes and stays high.
w = ct.Wall(cstr, env, A=1.0, U=0.02)

# Connect the upstream reservoir to the reactor with a mass flow controller
# (constant mdot). Set the mass flow rate to 1.25 sccm.
sccm = 1.25
vdot = sccm * 1.0e-6 / 60.0 * (
    (ct.one_atm / gas.P) * (gas.T / 273.15))  # m^3/s
mdot = gas.density * vdot  # kg/s
mfc = ct.MassFlowController(upstream, cstr, mdot=mdot)

# now create a downstream reservoir to exhaust into.
downstream = ct.Reservoir(gas)

# connect the reactor to the downstream reservoir with a valve, and set the
# coefficient sufficiently large to keep the reactor pressure close to the
# downstream pressure of 60 Torr.
v = ct.Valve(cstr, downstream, K=1.0e-9)

# create the network
network = ct.ReactorNet([cstr])

# In[3]:

# now integrate in time
Exemple #16
0
def runSinglePFR(T_0, pressure, composition_0, length, v_0, d, tempProfile,
                 factor, reactionIndex):

    start = time.time()

    # input file containing the reaction mechanism
    reaction_mechanism = 'HXD15_Battin_mech.xml'

    # import the gas model and set the initial conditions
    gas2 = ct.Solution(reaction_mechanism)
    gas2.TPX = T_0, pressure, composition_0
    mass_flow_rate2 = v_0 * gas2.density * (1.01325e5 / pressure) * (T_0 /
                                                                     298.15)

    # Resolution: The PFR will be simulated by 'n_steps' time steps or by a chain
    # of 'n_steps' stirred reactors.
    n_steps = 100
    area = math.pi * d * d / 4
    dz = length / n_steps
    r_vol = area * dz

    # create a new reactor
    r2 = ct.IdealGasReactor(gas2)
    r2.volume = r_vol

    # create a reservoir to represent the reactor immediately upstream. Note
    # that the gas object is set already to the state of the upstream reactor
    upstream = ct.Reservoir(gas2, name='upstream')

    # create a reservoir for the reactor to exhaust into. The composition of
    # this reservoir is irrelevant.
    downstream = ct.Reservoir(gas2, name='downstream')

    # The mass flow rate into the reactor will be fixed by using a
    # MassFlowController object.
    m = ct.MassFlowController(upstream, r2, mdot=mass_flow_rate2)

    # We need an outlet to the downstream reservoir. This will determine the
    # pressure in the reactor. The value of K will only affect the transient
    # pressure difference.
    v = ct.PressureController(r2, downstream, master=m, K=1.0e-9)

    sim2 = ct.ReactorNet([r2])

    from scipy.interpolate import UnivariateSpline
    [zz, tem] = readTemperatureProfile(tempProfile)
    para = UnivariateSpline(zz, tem)

    # modify the A factor of the given reaction
    gas2.set_multiplier(factor, reactionIndex - 1)

    # iterate through the PFR cells

    # define time, space, and other information vectors
    # z2 = (np.arange(n_steps+1) + 1) * dz
    # t_r2 = np.zeros_like(z2)  # residence time in each reactor
    # u2 = np.zeros_like(z2)
    # t2 = np.zeros_like(z2)

    for n in range(n_steps + 1):
        print n
        position = dz * float(n)
        # Set the state of the reservoir to match that of the previous reactor
        gas2.TDY = para(position), r2.thermo.density, r2.thermo.Y

        upstream.syncState()
        sim2.reinitialize()
        # integrate the reactor forward in time until steady state is reached
        sim2.advance_to_steady_state()
        # compute velocity and transform into time
        # u2[n] = mass_flow_rate2 / area / r2.thermo.density
        # t_r2[n] = r2.mass / mass_flow_rate2  # residence time in this reactor
        # t2[n] = np.sum(t_r2)
        # write output data
        # print position, r2.thermo.T, r2.thermo.P, u2[n], t2[n], r2.thermo['C3H6'].X[0]
        # moleFractionC3H6.append([dz*n, u2[n], t2[n], r2.thermo.T, r2.thermo['C3H6'].X[0]])

    end = time.time()
    print 'Done! Execution time is:'
    print end - start

    return [
        gas2.reaction_equation(reactionIndex - 1),
        r2.thermo['C3H6'].X[0] * 1.0e6
    ]
Exemple #17
0
r1.Y

residence_time = 0.8e-4


def mdot_out(t):
    return r1.mass / residence_time


#Poner una válvula a la entrada del reactor r1 para mantener P=cte y evitar que se #devuelva el flujo. Véase  help(ct.Valve)
#Nótese el uso del objeto upstream que es un tipo Reservoir devinido arriba
inlet = ct.Valve(upstream, r1, K=100)
#Pone un objeto MassFlowController a la salidad de r1 que mantiene el flujo másico
#constante, véase help(ct.MassFlowController)
#Nótese el uso del objeto downstream que es un tipo Reservoir devinido arriba
outlet = ct.MassFlowController(r1, downstream)
#fija el flujo másico a la salida del reactor
outlet.set_mass_flow_rate(mdot_out)

net = ct.ReactorNet([r1])

#Creo los "pasos de tiempo" en los que quiero ver el progreso de la solución
#El solver de cantera resuelve de forma automática y escoge su paso de tiempo de #forma automática así t sea 2, 20 o 2000 puntos
t = np.linspace(0, residence_time, 2)
#
#¿Por qué el código original de Ray multiplica por 5 el tiempo de residencia?
#t = np.linspace(0, 5*residence_time, 2)
#

#Vector donde guardo las temperaturas
T = np.zeros(t.shape)
Exemple #18
0
gas.set_equivalence_ratio(0.30, 'c12h26', 'n2:3.76, o2:1.0')
gas.equilibrate('TP')
r = ct.IdealGasReactor(gas)
r.volume = 0.001  # 1 liter


def fuel_mdot(t):
    """Create an inlet for the fuel, supplied as a Gaussian pulse"""
    total = 3.0e-3  # mass of fuel [kg]
    width = 0.5  # width of the pulse [s]
    t0 = 2.0  # time of fuel pulse peak [s]
    amplitude = total / (width * np.sqrt(2 * np.pi))
    return amplitude * np.exp(-(t - t0)**2 / (2 * width**2))


mfc = ct.MassFlowController(inlet, r, mdot=fuel_mdot)

# Create the reactor network
sim = ct.ReactorNet([r])

# Integrate for 10 seconds, storing the results for later plotting
tfinal = 10.0
tnow = 0.0
i = 0
tprev = tnow
states = ct.SolutionArray(gas, extra=['t'])

while tnow < tfinal:
    tnow = sim.step()
    i += 1
    # Storing results after every step can be excessive. Instead, store results
def simulatePFRorTPRwithCantera(model_name, canteraGasPhaseObject, canteraSurfacePhaseObject, simulation_settings_module):
    #simulation_settings_module_name must be a string if it is provided. The module itself should not be passed as an argument. This is intentional.
    canteraPhases ={}
    gas = canteraGasPhaseObject
    surf = canteraSurfacePhaseObject
    canteraPhases['gas'] = gas
    canteraPhases['surf'] = surf
       
    
    '''Now the code that handles *either* isothermal PFR or surface TPR. In future, will allow PFR TPR as well'''
    #We are going to model things as a flow reactor made of CSTRs, with no flow for the surface TPR case, following this example: https://cantera.org/examples/python/reactors/surf_pfr.py.html
    #it could probably also have been done as a flow reactor with no flow:  https://cantera.org/examples/python/surface_chemistry/catalytic_combustion.py.html
      

    
    '''START OF settings that users should change.'''
    flow_type = simulation_settings_module.flow_type
    T_gas_feed = simulation_settings_module.T_gas_feed
    T_surf = simulation_settings_module.T_surf
    velocity = simulation_settings_module.velocity
    reactor_cross_area = simulation_settings_module.reactor_cross_area
    cat_area_per_vol = simulation_settings_module.cat_area_per_vol
    porosity = simulation_settings_module.porosity
    length = simulation_settings_module.length
    P_gas = simulation_settings_module.P_gas
    gas_composition = simulation_settings_module.gas_composition
    t_step_size = simulation_settings_module.t_step_size
    t_final = simulation_settings_module.t_final
    NReactors = simulation_settings_module.NReactors
    print_frequency = simulation_settings_module.print_frequency
    heating_rate = simulation_settings_module.heating_rate
    surface_coverages =  simulation_settings_module.surface_coverages
    rtol = simulation_settings_module.rtol
    atol = simulation_settings_module.atol
    exportOutputs = simulation_settings_module.exportOutputs
    '''END OF settings that users should change.'''
    


    #Initiate concentrations output file and headers.
    if exportOutputs == True:
        concentrations_output_filename = model_name + "_output_concentrations.csv"
        outfile = open(concentrations_output_filename,'w')
        writer = csv.writer(outfile)
    concentrationsArrayHeaderList = ['Distance (m)', 'time(s)',  'T_gas (K)', 'T_surf (K)', 'P (atm)'] + \
                    gas.species_names + surf.species_names
    concentrationsArrayHeader = str(concentrationsArrayHeaderList)[1:-1] #The species names were imported when "surf" and "gas" objects were created.
    if exportOutputs == True:    
        writer.writerow(concentrationsArrayHeaderList)
    
    
    if flow_type == "Static":
        velocity = 0
        NReactors = 2 #In the surf_pfr example. For static, we only need 1 reactor, but the rlen formula below has a minimum value of 2. #FIXME
    
    num_t_steps = ceil(t_final / t_step_size) #rounds up.
    
    rlen = length/(NReactors-1) #This is each individual CSTR's length. #FIXME: Why is this not just Nreactors? Is it because of reservoirs?...
    #rvol is the reactor volume. We're modeling this as as a single CSTR with no flow.
    rvol = reactor_cross_area * rlen * porosity #Each individual CSTR gas volume reduced by porosity.
    # catalyst area in one reactor
    cat_area = cat_area_per_vol * rvol
    
    
    #Set the initial conditions for the gas and the surface.
    gas.TPX = T_gas_feed, P_gas, gas_composition
    surf.TP = T_surf, P_gas
    surf.X = surface_coverages
    
    mass_flow_rate = velocity * reactor_cross_area * gas.density  #linear velocity times area is volume/s, times kg/vol becomes kg/s. I think that for this example we neglect effects of surface adsorption regarding how much mass is in the gas phase?
    
    TDY = gas.TDY #Get/Set temperature [K] and density [kg/m^3 or kmol/m^3], and mass fractions. From: https://cantera.org/documentation/docs-2.4/sphinx/html/cython/thermo.html
    cov = surf.coverages #This is normalized coverages, built in from InerfacePhase class: https://cantera.github.io/docs/sphinx/html/cython/thermo.html#cantera.InterfacePhase
    #It would also be possible to type surface.site_density, giving [kmol/m^2] for surface phases. Also possible to use surf.set_unnormalized_coverages(self, cov) for cases when don't want to use normalized coverages.
    
    # create a new reactor
    gas.TDY = TDY #<-- If TDY was changing, and if original gas wanted to be kept, this could have been gas = copy.deepcopy(gas)?
    reactor = ct.IdealGasReactor(gas, energy='off')
    reactor.volume = rvol
    
    # create a reservoir to represent the reactor immediately upstream. Note
    # that the gas object is set already to the state of the upstream reactor
    upstream_of_CSTR = ct.Reservoir(gas, name='upstream') #A cantera reservoir never changes no matter what goes in/out: https://cantera.org/documentation/docs-2.4/sphinx/html/cython/zerodim.html#cantera.Reservoir
    
    # create a reservoir for the reactor to exhaust into. The composition of
    # this reservoir is irrelevant.
    downstream_of_CSTR = ct.Reservoir(gas, name='downstream') #A cantera reservoir never changes no matter what goes in/out: https://cantera.org/documentation/docs-2.4/sphinx/html/cython/zerodim.html#cantera.Reservoir
    
    #Note: these are reservoirs for individual CSTRs. It's used in a clever way in this example, as will be seen later.
    #I would prefer to call these reservoirs "feed" and "exhaust", and would consider to fill the downstream/exhaust with inert to make it clear that it is different. Or maybe make deep copies of gas called "feed_gas" and "exhaust_gas".
    
    # Add the reacting surface to the reactor. The area is set to the desired
    # catalyst area in the reactor.
    rsurf = ct.ReactorSurface(surf, reactor, A=cat_area)  #Here is where the catalyst site density gets used.  Note that cat_area is actually in meters now, even though site_density is defined as mol/cm^2 in the cti file.
    
    # The mass flow rate into the reactor will be fixed by using a
    # MassFlowController object.
    f_mfr = ct.MassFlowController(upstream_of_CSTR, reactor, mdot=mass_flow_rate) #mass flow controller makes flow that goes from the first argument to the second argument with mdot providing "The mass flow rate [kg/s] through this device at time t [s]."s
    
    # We need an outlet to the downstream reservoir. This will determine the
    # pressure in the reactor. The value of K will only affect the transient
    # pressure difference.
    e_mfr = ct.PressureController(reactor, downstream_of_CSTR, master=f_mfr, K=1e-5)  #This makes flow that goes from first argument to second argument with the mass flow controller "f_mfr" controlling the pressure here. K has units of kg/s/Pa times the pressure difference. this "v" that comes out is in same units as the mass flow rate, it's in kg/s.   https://cantera.org/documentation/docs-2.4/sphinx/html/cython/zerodim.html#flowdevice e_mfr is the exhaust mass flow rate.
    
    sim = ct.ReactorNet([reactor]) #This is normally a list of reactors that are coupled.
    sim.max_err_test_fails = 12 #Even after looking at docs, I'm not sure what this does. I think this is how many relative and absolute tolerance failures there can be in a single time step before the resolution of the ODE integrator does that step again with finer resolution? https://cantera.org/documentation/docs-2.4/sphinx/html/cython/zerodim.html#reactor-networks
    
    #Static versus PFR flag
    
    
    
    # set relative and absolute tolerances on the simulation
    sim.rtol = rtol
    sim.atol = atol
    gas_rates = [] #NOTE: These are just the rates from the surface phase. These are *not* including any homogeneous rates.
    surface_rates = [] #NOTE: These are just the rates from the surface phase. These are *not* including any homogeneous rates.
    sim_times = [] #NOTE: This is less useful if one uses advance_to_steady_state
    sim_dist = [] #This is the distance in the reactor. If one is using flow and advance_to_steady_state, then this is representative of the kinetics.
    concentrationsArray = []
    #Print some things out for before the simulation, these are basically headers.
    if print_frequency != None:
        print(concentrationsArrayHeader)
    
    if flow_type == "PFR":
        for n in range(NReactors): #iterate across the CSTRs.
            # Set the state of the reservoir to match that of the previous reactor
            gas.TDY = reactor.thermo.TDY #<-- setting gas to *most recent* state of the reactor.
            upstream_of_CSTR.syncState() #<-- this is an interesting trick. Once one CSTR has been simulated, we set the current values (the one from the just simulated CSTR) to be upstream value. This works because we're doing implicit ODE down a reactor length, and probably only gives the right answer for steady state kinetics. It also only works because we don't care what's happening downstream. We have a fixed K for the e_mfr, and also f_mfr.
            sim.reinitialize()
            sim.advance_to_steady_state() #<-- we advance the current CSTR to steady state before going to the next one.  For a tpr, we'd probably use advance(self, double t) instead. The syntax would be something like sim.advance(10.0) for 10 seconds. https://cantera.github.io/docs/sphinx/html/cython/examples/reactors_reactor1.html#py-example-reactor1-py
        
            dist = n * rlen # distance in m <-- this could have been defined above, and I would have... but it's probably good to have it down here to make it clear that only 'n" is being used rather than this value, to simulate the reactor.
            sim_dist.append(dist)
            sim_times.append(sim.time)
            gas_rates.append(surf.get_net_production_rates('gas'))
            surface_rates.append(surf.get_net_production_rates('surf'))
            # write the gas mole fractions and surface coverages vs. distance
            rowListOfStrings = [dist, sim.time, gas.T, surf.T, reactor.thermo.P/ct.one_atm] + \
                        list(gas.concentrations) + list(surf.coverages)
            if exportOutputs == True:
                writer.writerow(rowListOfStrings)
                concentrationsArray.append(np.array(rowListOfStrings))
            if print_frequency != None: 
                if not n % print_frequency: #This only prints every specified number of steps.
                    try:
                        with np.printoptions(precision=3):
                            print(np.array(rowListOfStrings))
                    except:
                            print(np.array(rowListOfStrings))
    
    if flow_type == "Static":
        T_surf_0 = T_surf
        #sim.set_max_time_step(t_step_size) #Cantera's sim.step normally advances in a variable way.
        for i_step in range(num_t_steps): #iterate across the CSTRs.
            time = i_step*t_step_size
            T_surf = T_surf_0 + time*heating_rate
            surf.TP = T_surf, P_gas
            if simulation_settings_module.piecewise_coverage_dependence == True:
                modified_reactions_parameters_array = canteraKineticsParametersParser.calculatePiecewiseCoverageDependentModifiedParametersArray(simulation_settings_module, surf.species_names, surf.coverages) #This feature requires the piecewise coverage dependence settings AND the reactions_parameters_array to already be inside the surf object **in advance**
                canteraKineticsParametersParser.modifyReactionsInOnePhase(surf, modified_reactions_parameters_array, ArrheniusOnly=True) #TODO: Right now this is constrainted to Arrhenius only because cantera does not yet allow modifyReactionsInOnePhase to do more (but it's planned to change in developers roadmap)                
            surf.advance_coverages(t_step_size)  #sim.advance(time) would not work. Changing T with time is not officially supported but happens to work with surf.advance_coverages. Supported way to change temperature during simulation for arbitrary reactors is to use custom integrator: https://cantera.org/examples/python/reactors/custom.py.html
            dist = 0.0
            sim_dist.append(dist)
            sim_times.append(time)
            gas_rates.append(surf.get_net_production_rates('gas'))
            surface_rates.append(surf.get_net_production_rates('surf'))        
            rowListOfStrings = [dist, time, gas.T, surf.T, reactor.thermo.P/ct.one_atm] + \
                    list(gas.X) + list(surf.coverages)
            if exportOutputs == True:
                writer.writerow(rowListOfStrings)
                concentrationsArray.append(np.array(rowListOfStrings))
            if print_frequency != None:
                if not i_step % print_frequency: #This only prints every specified number of steps.
                    try:
                        with np.printoptions(precision=3):
                            print(np.array(rowListOfStrings))
                    except:
                            print(np.array(rowListOfStrings))

           
    #Need to get things into a stackable state. Figured out from numpy shape that I needed to do at_least2D and transpose.
    sim_dist =  np.atleast_2d(sim_dist).transpose()
    sim_times =  np.atleast_2d(sim_times).transpose()
    gas_rates =  np.array(gas_rates)
    surface_rates =  np.array(surface_rates)    
    gasRatesArray = np.hstack((sim_dist,sim_times, gas_rates))
    surfaceRatesArray = np.hstack((sim_dist,sim_times, surface_rates))
    rates_all_array = np.hstack((sim_dist,sim_times, gas_rates, surface_rates))
    concentrationsArray = np.array(concentrationsArray)
    concentrationsArrayHeader = concentrationsArrayHeader
    gasRatesArrayHeader = 'dist(m), time(s),'+str(gas.species_names).replace("'","")[1:-1]
    surfaceRatesArrayHeader = 'dist(m),time(s),'+str(surf.species_names).replace("'","")[1:-1]
    rates_all_array_header = 'dist(m),time(s),'+str(gas.species_names).replace("'","")[1:-1]+"," + str(surf.species_names).replace("'","")[1:-1]
    canteraSimulationsObject = sim
    cantera_phase_rates = {"gas":gasRatesArray, "surf":surfaceRatesArray}
    cantera_phase_rates_headers = {"gas":gasRatesArrayHeader, "surf":surfaceRatesArrayHeader}
    
    if exportOutputs == True:
        np.savetxt(model_name + "_output_rates_all.csv", rates_all_array, delimiter=",", comments = '', header = rates_all_array_header)
        np.savetxt(model_name + "_output_rates_gas.csv", gasRatesArray, delimiter=",", comments = '', header = gasRatesArrayHeader )
        np.savetxt(model_name + "_output_rates_surf.csv", surfaceRatesArray, delimiter=",", comments = '', header = surfaceRatesArrayHeader)     
    if exportOutputs == True:    
        outfile.close()
    return concentrationsArray, concentrationsArrayHeader, rates_all_array, rates_all_array_header, cantera_phase_rates, canteraPhases, cantera_phase_rates_headers, canteraSimulationsObject
Exemple #20
0
#mixer: filled initially with nitrogen

fuel2.TPX= 700.0,10.3e5,'N2:1'
mixer2=ct.IdealGasReactor(fuel2, energy='on')
mixer2.volume=10e-6   # Volume Computed as per experimental dimensions in m3

combustor=ct.IdealGasReactor(fuel2,energy='on')
combustor.volume=71.136e-6   # Experimental Dimensions in m3

exhaust2=ct.Reservoir(fuel2)  # Exhaust Reservoir

eq_ratio2=1  # Equivalence Ratio
# mdot of oxidiser - 1.4 kg/s according to the experiment

fuel_pipe2= ct.MassFlowController(NG_inlet2, mixer2, mdot=1.4*eq_ratio2)
oxy_pipe2=ct.MassFlowController(oxy_inlet2,mixer2,mdot=1.4)


# Igniter modeled as pulsed radicals of Hydrogen
fwhm=0.2
amp=0.1
t0=1
igniter_mdot= lambda t:amp*math.exp(-(t-t0)**2*4*math.log(2)/fwhm**2)
ignite_pipe=ct.MassFlowController(igniter,combustor,mdot=igniter_mdot)

# The premixed reactants have to enter the combustor

mixer2combustor=ct.MassFlowController(mixer2,combustor)

#exhaust valve
combustor2.volume = 1.0

# Create a reservoir for the exhaust
exhaust1 = ct.Reservoir(gas1) #gas1
exhaust2 = ct.Reservoir(gas2) #gas2

# Use a variable mass flow rate to keep the residence time in the reactor
# constant (residence_time = mass / mass_flow_rate). The mass flow rate function
# can access variables defined in the calling scope, including state variables
# of the Reactor object (combustor) itself.

#gas1
def mdot(t):
    return combustor1.mass / residence_time1

inlet1_mfc = ct.MassFlowController(inlet1, combustor1, mdot=mdot)

#gas2
def mdot(t):
    return combustor2.mass / residence_time2

inlet2_mfc = ct.MassFlowController(inlet2, combustor2, mdot=mdot)

# A PressureController has a baseline mass flow rate matching the 'master'
# MassFlowController, with an additional pressure-dependent term. By explicitly
# including the upstream mass flow rate, the pressure is kept constant without
# needing to use a large value for 'K', which can introduce undesired stiffness.
outlet1_mfc = ct.PressureController(combustor1, exhaust1, master=inlet1_mfc, K=0.01) #gas1
outlet2_mfc = ct.PressureController(combustor2, exhaust2, master=inlet2_mfc, K=0.01) #gas2

# the simulation
Exemple #22
0
def execute():
    #==============================================================================
#     set up the cantera gases and reactors
#==============================================================================
    drop = droplet(50e-6, 'A2', 300, 1) #drop is defined only to use the drop properties
    #environment air
    gas_env = ct.Solution('a2.cti')
    gas_env.TPX = 300, ct.one_atm, 'O2:29,N2:71'

    gas_fuel = ct.Solution('a2.cti')
    gas_fuel.TPX = drop.ABP, ct.one_atm, 'POSF10325:1' #gaseous fuel at average boiling temperature

    gas_kernel = ct.Solution('a2.cti')
    gas_kernel.TPX = 4000, ct.one_atm, 'O2:29,N2:71'
    gas_kernel.equilibrate('HP')
    
    res_air = ct.Reservoir(gas_env)
    res_fuel = ct.Reservoir(gas_fuel)
    kernel = ct.IdealGasConstPressureReactor(gas_kernel)
    kernel.volume = 2.4e-8 #m^3

    mfc1 = ct.MassFlowController(res_air, kernel) #connect air reservoir to kernel
    mfc2 = ct.MassFlowController(res_fuel, kernel) #connect fuel reservoir to kernel

    mfc1.set_mass_flow_rate(6e-5)
    mfc2.set_mass_flow_rate(0)

    w = ct.Wall(kernel, res_fuel)
    w.set_heat_flux(0)
    w.expansion_rate_coeff = 1e8

    net = ct.ReactorNet({kernel})
    net.atol = 1e-10 #absolute tolerance
    net.rtol = 1e-10 #relative tolerance
#==============================================================================
#   endtime, time steps, and data to be stored    
#==============================================================================
    dt = 1e-6 #change time step for advancing the reactor
    endtime = 1000e-6
    mdot_fuel = 1.98e-6 #this number should be calculated based on equivalence ratio, kg/s
    
    droplets = []
    T = []
    time = []
    m = []
    m_dot = []
    q_dot = []
    droplet_count = []
    X_fuel = []
    X_O = []
    X_CO2 = []
    num_d = []
    
#==============================================================================
#     advance reaction
#==============================================================================
    print("Running simulation")
    for i in range(1,int(endtime/dt)):
        print (int(endtime/dt) - i)
        #entrain droplets every 1 microsecond
        droplets.extend(entrainer(400, 5.*mdot_fuel))  
        mdot, qdot = vaporize(gas_kernel.T, droplets, dt)
        
#        print(gas_kernel.T, mdot, qdot, len(droplets))
#        print(str(mdot) + str(qdot) + str(gas_kernel.T)+'  '+str(len(droplets)))
        mfc2.set_mass_flow_rate(mdot)
        w.set_heat_flux(qdot) #heat required to heat up the droplets during that time step
        
        net.advance(i*dt)
        
        num_d.append(len(droplets))
        #storing variables
        T.append(gas_kernel.T)
        time.append(net.time)
        m.append(kernel.mass)
        m_dot.append(mdot)
        q_dot.append(qdot)
        droplet_count.append(len(droplets))
        if gas_kernel.X[0] < 0:
            gas_kernel.X[0] = 0
        X_fuel.append(gas_kernel.X[gas_kernel.species_index("POSF10325")])
        X_O.append(gas_kernel.X[gas_kernel.species_index("O")])
        X_CO2.append(gas_kernel.X[gas_kernel.species_index("CO2")])
        
#==============================================================================
#   plotting important information      
#==============================================================================
    plt.plot([t*1e3 for t in time],T, linewidth=3)
    plt.xlabel('time(ms)', FontSize=15)
    plt.ylabel('Temperature (K)', FontSize=15)
    plt.show()
    
    fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax1.plot([t*1e3 for t in time], X_fuel, color = 'red', linewidth = 3)
    ax1.set_xlabel('time (ms)', FontSize=15)
    ax1.set_ylabel('X_fuel', color='red', FontSize=15)
#    ax2.plot([t*1e3 for t in time], X_O, color = 'green', linewidth = 3)
    ax2.set_ylabel('X_CO2', color='green', FontSize=15)
    ax2.plot([t*1e3 for t in time], X_CO2, color = 'blue', linewidth = 3)
    plt.show()
    
    fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax1.plot([t*1e3 for t in time], m_dot, color = 'red', linewidth = 3)
    ax1.set_xlabel('time (ms)', FontSize=15)
    ax1.set_ylabel('m_dot', color='red', FontSize=15)
    ax2.plot([t*1e3 for t in time], q_dot, color = 'green', linewidth = 3)
    ax2.set_ylabel('q_dot', color='green', FontSize=15)
    plt.show()
    
    fig,ax1 = plt.subplots()
    ax1.plot([t*1e3 for t in time], num_d, linewidth=3)
    ax1.set_xlabel('time(ms)', FontSize=15)
    ax1.set_ylabel('#droplets', FontSize=15)
    plt.show()
    def __init__(self):
        """Constructor for the SimEnv class. Call SimEnv(...) to create a SimEnv object.

        Arguments:
            None
        """

        # super(SimEnv) returns the superclass, in this case gym.Env. Construct a gym.Env instance
        # gym.Env.__init__(self)
        # EzPickle.__init__(self)

        self.dt = DT
        self.age = 0
        self.steps_taken = 0
        self.reward = 0
        # Create main burner objects
        self.main_burner_gas = ct.Solution(MECH)
        self.main_burner_gas.TPX = main_burner_reactor.thermo.TPX
        self.main_burner_reactor = ct.ConstPressureReactor(
            self.main_burner_gas)
        self.main_burner_reservoir = ct.Reservoir(
            contents=self.main_burner_gas)
        self.remaining_main_burner_mass = M_air_main + M_fuel_main

        # Create secondary stage objects
        self.sec_fuel = ct.Solution(MECH)
        self.sec_fuel.TPX = T_FUEL, P, {'CH4': 1.0}
        self.sec_fuel_reservoir = ct.Reservoir(contents=self.sec_fuel)
        self.sec_fuel_remaining = M_fuel_sec
        self.sec_air = ct.Solution(MECH)
        self.sec_air.TPX = T_AIR, P, {'N2': 0.79, 'O2': 0.21}
        self.sec_air_reservoir = ct.Reservoir(contents=self.sec_air)
        self.sec_air_remaining = M_air_sec

        # Create simulation network model
        self.sec_stage_gas = ct.Solution(MECH)
        self.sec_stage_gas.TPX = 300, P, {'AR': 1.0}
        self.sec_stage_reactor = ct.ConstPressureReactor(self.sec_stage_gas)
        self.sec_stage_reactor.volume = 1e-8  # second stage starts off small, and grows as mass is entrained
        self.network = ct.ReactorNet(
            [self.main_burner_reactor, self.sec_stage_reactor])

        # Create main and secondary mass flow controllers and connect them to the secondary stage
        self.mfc_main = ct.MassFlowController(self.main_burner_reservoir,
                                              self.sec_stage_reactor)
        self.mfc_main.set_mass_flow_rate(0)  # zero initial mass flow rate

        self.mfc_air_sec = ct.MassFlowController(self.sec_air_reservoir,
                                                 self.sec_stage_reactor)
        self.mfc_air_sec.set_mass_flow_rate(0)

        self.mfc_fuel_sec = ct.MassFlowController(self.sec_fuel_reservoir,
                                                  self.sec_stage_reactor)
        self.mfc_fuel_sec.set_mass_flow_rate(0)

        # Define action and observation spaces; must be gym.spaces
        # we're controlling three things: mdot_main, mdot_fuel_sec, mdot_air_sec
        #TODO: check to see if chosen tau_ent and self.action_space.high definition allow for complete entrainment of mass
        self.action_space = spaces.Box(
            low=np.array([0, 0, 0]),
            high=np.array([
                self.remaining_main_burner_mass / tau_ent_main,
                self.sec_fuel_remaining / tau_ent_sec,
                self.sec_air_remaining / tau_ent_sec
            ]),
            dtype=np.float32)
        low = np.array([0] * 55 + [-np.finfo(np.float32).max] * 53)
        high = np.array([3000, 10] + [1] * 53 +
                        [np.finfo(np.float64).max] * 53)
        num_cols = len(self.sec_stage_gas.state) + \
            len(self.sec_stage_gas.net_production_rates)
        self.observation_space = spaces.Box(low=np.tile(low, (10, 1)),
                                            high=np.tile(high, (10, 1)),
                                            dtype=np.float64)

        self.observation_array = self._next_observation(init=True)

        # Reward variables for T, NO, and CO
        self.reward_T = 0
        self.reward_NO = 0
        self.reward_CO = 0
Exemple #24
0
# create a reservoir for the exhaust
exhaust = ct.Reservoir(gas)

# lean combustion, phi = 0.5
equiv_ratio = 0.5

# compute fuel and air mass flow rates
factor = 0.1
air_mdot = factor * 9.52 * air_mw
fuel_mdot = factor * equiv_ratio * fuel_mw

# create and install the mass flow controllers. Controllers m1 and m2 provide
# constant mass flow rates, and m3 provides a short Gaussian pulse only to
# ignite the mixture
m1 = ct.MassFlowController(fuel_in, combustor, mdot=fuel_mdot)

# note that this connects two reactors with different reaction mechanisms and
# different numbers of species. Downstream and upstream species are matched by
# name.
m2 = ct.MassFlowController(air_in, combustor, mdot=air_mdot)

# The igniter will use a Gaussian time-dependent mass flow rate.
fwhm = 0.2
amplitude = 0.1
t0 = 1.0
igniter_mdot = lambda t: amplitude * math.exp(-(t - t0)**2 * 4 * math.log(2) /
                                              fwhm**2)
m3 = ct.MassFlowController(igniter, combustor, mdot=igniter_mdot)

# put a valve on the exhaust line to regulate the pressure
Exemple #25
0
    # create a new reactor
    r2 = ct.IdealGasReactor(gas2)
    r2.volume = r_vol

    # create a reservoir to represent the reactor immediately 	upstream. Note
    # that the gas object is set already to the state of the 	upstream reactor
    upstream = ct.Reservoir(gas2, name='upstream')

    # create a reservoir for the reactor to exhaust into. The 	composition of
    # this reservoir is irrelevant.
    downstream = ct.Reservoir(gas2, name='downstream')

    # The mass flow rate into the reactor will be fixed by using 	a
    # MassFlowController object.
    m = ct.MassFlowController(upstream, r2, mdot=mass_flow_rate2)

    # We need an outlet to the downstream reservoir. This will 	determine the
    # pressure in the reactor. The value of K will only affect 	the transient
    # pressure difference.
    v = ct.PressureController(r2, downstream, master=m, K=1e-5)

    sim2 = ct.ReactorNet([r2])

    # define time, space, and other information vectors
    z2 = (np.arange(n_steps) + 1) * dz
    t_r2 = np.zeros_like(z2)  # residence time in each reactor
    u2 = np.zeros_like(z2)
    t2 = np.zeros_like(z2)
    states2 = ct.SolutionArray(r2.thermo)
    # iterate through the PFR cells
Exemple #26
0
def monolith_simulation(path_to_cti, temp, mol_in, verbose=False, sens=False):
    """
    Set up and solve the monolith reactor simulation.

    Verbose prints out values as you go along
    Sens is for sensitivity, in the form [perturbation, reaction #]

    Args:
        path_to_cti: full path to the cti file
        temp (float): The temperature in Kelvin
        mol_in (3-tuple or iterable): the inlet molar ratios of (CH4, O2, Ar)
        verbose (Boolean): whether to print intermediate results
        sens (False or 2-tuple/list): if not False, then should be a 2-tuple or list [dk, rxn]
                in which dk = relative change (eg. 0.01) and rxn = the index of the surface reaction rate to change

    Returns:
        gas_out, # gas molar flow rate in moles/minute
        surf_out, # surface mole fractions
        gas_names, # gas species names
        surf_names, # surface species names
        dist_array, # distances (in mm)
        T_array # temperatures (in K)
    """
    sols_dict = setup_ct_solution(path_to_cti)
    gas, surf, i_ar, n_surf_reactions = sols_dict['gas'], sols_dict[
        'surf'], sols_dict['i_ar'], sols_dict['n_surf_reactions']
    print(
        f"Running monolith simulation with CH4 and O2 concs {mol_in[0], mol_in[1]} on thread {threading.get_ident()}"
    )
    ch4, o2, ar = mol_in
    ratio = ch4 / (2 * o2)

    X = f"CH4(2):{ch4}, O2(3):{o2}, Ar:{ar}"
    gas.TPX = 273.15, ct.one_atm, X  # need to initialize mass flow rate at STP
    # mass_flow_rate = velocity * gas.density_mass * area  # kg/s
    mass_flow_rate = flow_rate * gas.density_mass
    gas.TPX = temp, ct.one_atm, X
    temp_cat = temp
    surf.TP = temp_cat, ct.one_atm
    surf.coverages = 'X(1):1.0'
    gas.set_multiplier(1.0)

    TDY = gas.TDY
    cov = surf.coverages

    if verbose is True:
        print(
            '  distance(mm)   X_CH4        X_O2        X_H2       X_CO       X_H2O       X_CO2'
        )

    # create a new reactor
    gas.TDY = TDY
    r = ct.IdealGasReactor(gas)
    r.volume = rvol

    # create a reservoir to represent the reactor immediately upstream. Note
    # that the gas object is set already to the state of the upstream reactor
    upstream = ct.Reservoir(gas, name='upstream')

    # create a reservoir for the reactor to exhaust into. The composition of
    # this reservoir is irrelevant.
    downstream = ct.Reservoir(gas, name='downstream')

    # Add the reacting surface to the reactor. The area is set to the desired
    # catalyst area in the reactor.
    rsurf = ct.ReactorSurface(surf, r, A=cat_area)

    # The mass flow rate into the reactor will be fixed by using a
    # MassFlowController object.
    # mass_flow_rate = velocity * gas.density_mass * area  # kg/s
    # mass_flow_rate = flow_rate * gas.density_mass
    m = ct.MassFlowController(upstream, r, mdot=mass_flow_rate)

    # We need an outlet to the downstream reservoir. This will determine the
    # pressure in the reactor. The value of K will only affect the transient
    # pressure difference.
    v = ct.PressureController(r, downstream, master=m, K=1e-5)

    sim = ct.ReactorNet([r])
    sim.max_err_test_fails = 12

    # set relative and absolute tolerances on the simulation
    sim.rtol = 1.0e-10
    sim.atol = 1.0e-20

    gas_names = gas.species_names
    surf_names = surf.species_names
    gas_out = []
    surf_out = []
    dist_array = []
    T_array = []

    surf.set_multiplier(0.0)  # no surface reactions until the gauze
    for n in range(N_reactors):
        # Set the state of the reservoir to match that of the previous reactor
        gas.TDY = r.thermo.TDY
        upstream.syncState()
        if n == on_catalyst:
            surf.set_multiplier(1.0)
            if sens is not False:
                surf.set_multiplier(1.0 + sens[0], sens[1])
        if n == off_catalyst:
            surf.set_multiplier(0.0)
        sim.reinitialize()
        sim.advance_to_steady_state()
        dist = n * reactor_len * 1.0e3  # distance in mm
        dist_array.append(dist)
        T_array.append(surf.T)
        kmole_flow_rate = mass_flow_rate / gas.mean_molecular_weight  # kmol/s
        gas_out.append(1000 * 60 * kmole_flow_rate *
                       gas.X.copy())  # molar flow rate in moles/minute
        surf_out.append(surf.X.copy())

        # stop simulation when things are done changing, to avoid getting so many COVDES errors
        if n >= 1001:
            if np.max(abs(np.subtract(gas_out[-2], gas_out[-1]))) < 1e-15:
                break

        # make reaction diagrams
        # out_dir = 'rxnpath'
        # os.path.exists(out_dir) or os.makedirs(out_dir)
        # elements = ['H', 'O']
        # locations_of_interest = [1000, 1200, 1400, 1600, 1800, 1999]
        # if sens is False:
        #     if n in locations_of_interest:
        #             location = str(int(n / 100))
        #             diagram = ct.ReactionPathDiagram(surf, 'X')
        #             diagram.title = 'rxn path'
        #             diagram.label_threshold = 1e-9
        #             dot_file = f"{out_dir}/rxnpath-{ratio:.1f}-x-{location}mm.dot"
        #             img_file = f"{out_dir}/rxnpath-{ratio:.1f}-x-{location}mm.pdf"
        #             diagram.write_dot(dot_file)
        #             os.system('dot {0} -Tpng -o{1} -Gdpi=200'.format(dot_file, img_file))
        #
        #             for element in elements:
        #                 diagram = ct.ReactionPathDiagram(surf, element)
        #                 diagram.title = element + 'rxn path'
        #                 diagram.label_threshold = 1e-9
        #                 dot_file = f"{out_dir}/rxnpath-{ratio:.1f}-x-{location}mm-{element}.dot"
        #                 img_file = f"{out_dir}/rxnpath-{ratio:.1f}-x-{location}mm-{element}.pdf"
        #                 diagram.write_dot(dot_file)
        #                 os.system('dot {0} -Tpng -o{1} -Gdpi=200'.format(dot_file, img_file))
        # else:
        #     pass

        if verbose is True:
            if not n % 100:
                print(
                    '  {0:10f}  {1:10f}  {2:10f}  {3:10f} {4:10f} {5:10f} {6:10f}'
                    .format(
                        dist,
                        *gas['CH4(2)', 'O2(3)', 'H2(6)', 'CO(7)', 'H2O(5)',
                             'CO2(4)'].X * 1000 * 60 * kmole_flow_rate))

    gas_out = np.array(gas_out)
    surf_out = np.array(surf_out)
    gas_names = np.array(gas_names)
    surf_names = np.array(surf_names)
    data_out = gas_out, surf_out, gas_names, surf_names, dist_array, T_array, i_ar, n_surf_reactions
    print(
        f"Finished monolith simulation for CH4 and O2 concs {mol_in[0], mol_in[1]} on thread {threading.get_ident()}"
    )
    return data_out
Exemple #27
0
def compute(X):

    global combustor
    global residence_time

    x1, x2, x3, x4, x5 = X
    inject_parameters(x1, x2, x3, x4, x5)

    #导入network计算
    win32api.ShellExecute(0, 'open', 'C:\\Users\\86183\\network_flow.exe', '', '', 1)
    #停止程序执行,等待network计算结果
    time.sleep(8)
    #识别result文件中某几行的数据之和
    path = os.getcwd()+ "\\result.dat"
    f=open(path,'r')
    data=f.readlines()
    f.close()

    for i in range(len(data)):
        line=data[i].split()[1]
        data[i]=float(line)

# print(data)
    result=np.sum(data[1:2]+data[2:3])
    # print(result)
    # print(result/3)

    #CRN 化学反应网络法
    # 设置反应器气体
    gas = ct.Solution('gri30.yaml')

    # 确定油气等效比、燃气温度、燃气压强
    equiv_ratio =result/3 
    gas.TP = 300.0, 101325
    gas.set_equivalence_ratio(equiv_ratio, 'CH4:1.0', 'O2:1.0, N2:3.76')
    inlet = ct.Reservoir(gas)

# 让反应器达到平衡状态
    gas.equilibrate('HP')
    combustor = ct.IdealGasReactor(gas)
    combustor.volume = 1.0

# 设置出口排放
    exhaust = ct.Reservoir(gas)

# 计算进出口质量流量

    inlet_mfc = ct.MassFlowController(inlet, combustor, mdot=mdot)

    outlet_mfc = ct.PressureController(combustor, exhaust, master=inlet_mfc, K=0.01)

    sim = ct.ReactorNet([combustor])

# 设置驻留时间,计算驻留时间逐渐减小所对应的反应器温度
    states = ct.SolutionArray(gas, extra=['tres'])

    temperatureList=[]
    while combustor.T > 500:
        sim.set_initial_time(0.0) 
        sim.advance_to_steady_state()
        # print('tres = {:.2e}; T = {:.1f}'.format(residence_time, combustor.T))
        states.append(combustor.thermo.state, tres=residence_time)
        residence_time *= 0.9  
        temperatureList.append(combustor.T)
    # print(temperatureList)

    maxT=max(temperatureList)
    return (-1)*maxT
Exemple #28
0
        # create the combustor, and fill it in initially with N2
        gas.TPX = T, P, 'N2:1.0'
        przestrzen_obliczeniowa = ct.IdealGasReactor(gas)
        przestrzen_obliczeniowa.volume = 1.0

        # outlet from reactor
        exhaust = ct.Reservoir(gas)

        # mass streams of methane and air - setting A/F ratio
        factor = 0.1
        air_mdot = factor * 9.52 * air_mw
        fuel_mdot = factor * fi * fuel_mw

        # mass flow stabilizer for methane
        m1 = ct.MassFlowController(fuel_in,
                                   przestrzen_obliczeniowa,
                                   mdot=fuel_mdot)

        # mass flow stabilizer for air
        m2 = ct.MassFlowController(air_in,
                                   przestrzen_obliczeniowa,
                                   mdot=air_mdot)

        # ignition modelled by Gaussian pulse
        fwhm = 0.2
        amplitude = 0.1
        t0 = 1.0
        igniter_mdot = lambda t: amplitude * math.exp(-(t - t0)**2 * 4 * math.
                                                      log(2) / fwhm**2)
        m3 = ct.MassFlowController(igniter,
                                   przestrzen_obliczeniowa,
Exemple #29
0
combustor.volume = 1.0

# Create a reservoir for the exhaust
exhaust = ct.Reservoir(gas)

# Use a variable mass flow rate to keep the residence time in the reactor
# constant (residence_time = mass / mass_flow_rate). The mass flow rate function
# can access variables defined in the calling scope, including state variables
# of the Reactor object (combustor) itself.


def mdot(t):
    return combustor.mass / residence_time


inlet_mfc = ct.MassFlowController(inlet, combustor, mdot=mdot)

# A PressureController has a baseline mass flow rate matching the 'master'
# MassFlowController, with an additional pressure-dependent term. By explicitly
# including the upstream mass flow rate, the pressure is kept constant without
# needing to use a large value for 'K', which can introduce undesired stiffness.
outlet_mfc = ct.PressureController(combustor,
                                   exhaust,
                                   master=inlet_mfc,
                                   K=0.01)

# the simulation only contains one reactor
sim = ct.ReactorNet([combustor])

# Run a loop over decreasing residence times, until the reactor is extinguished,
# saving the state after each iteration.
# define inlet state
gas.TPX = T_inlet, p_inlet, comp_inlet
inlet = ct.Reservoir(gas)
# define injector state (gaseous!)
gas.TPX = T_injector, p_injector, comp_injector
injector = ct.Reservoir(gas)
# define outlet pressure (temperature and composition don't matter)
gas.TPX = T_ambient, p_outlet, comp_ambient
outlet = ct.Reservoir(gas)
# define ambient pressure (temperature and composition don't matter)
gas.TPX = T_ambient, p_ambient, comp_ambient
ambient_air = ct.Reservoir(gas)

# set up connecting devices
inlet_valve = ct.Valve(inlet, r)
injector_mfc = ct.MassFlowController(injector, r)
outlet_valve = ct.Valve(r, outlet)
piston = ct.Wall(ambient_air, r)

# convert time to crank angle
def crank_angle(t):
    return np.remainder(2 * np.pi * f * t, 4 * np.pi)

# set up IC engine parameters
V_oT = V_H / (epsilon - 1.)
A_piston = .25 * np.pi * d_piston ** 2
stroke = V_H / A_piston
r.volume = V_oT
piston.area = A_piston
def piston_speed(t):
    return - stroke / 2 * 2 * np.pi * f * np.sin(crank_angle(t))