def test_sequence(self): f = ct.Func1([5]) for t in [0.1, 0.7, 4.5]: self.assertNear(f(t), 5) with self.assertRaises(TypeError): ct.Func1([3, 4])
def test_numpy(self): f = ct.Func1(np.array(5)) g = ct.Func1(np.array([[5]])) for t in [0.1, 0.7, 4.5]: self.assertNear(f(t), 5) self.assertNear(g(t), 5) with self.assertRaises(TypeError): ct.Func1(np.array([3, 4]))
def test_failure(self): def fails(t): raise ValueError('bad') f = ct.Func1(fails) with self.assertRaises(ValueError): f(0.1)
def test_callable(self): class Multiplier(object): def __init__(self, factor): self.factor = factor def __call__(self, t): return self.factor * t m = Multiplier(8.1) f = ct.Func1(m) for t in [0.1, 0.7, 4.5]: self.assertNear(f(t), 8.1*t)
def test_function(self): f = ct.Func1(np.sin) self.assertNear(f(0), np.sin(0)) self.assertNear(f(0.1), np.sin(0.1)) self.assertNear(f(0.7), np.sin(0.7))
def test_uncopyable(self): import copy f = ct.Func1(np.sin) with self.assertRaises(NotImplementedError): copy.copy(f)
def test_unpicklable(self): import pickle f = ct.Func1(np.sin) with self.assertRaises(NotImplementedError): pickle.dumps(f)
def test_constant(self): f = ct.Func1(5) for t in [0.1, 0.7, 4.5]: self.assertNear(f(t), 5)
def test_lambda(self): f = ct.Func1(lambda t: np.sin(t) * np.sqrt(t)) for t in [0.1, 0.7, 4.5]: self.assertNear(f(t), np.sin(t) * np.sqrt(t))
def setup_case(self): """ Sets up the case to be run. Initializes the ``ThermoPhase``, ``Reactor``, and ``ReactorNet`` according to the values from the input file. """ self.gas = ct.Solution(self.mech_filename) initial_temp = self.keywords['temperature'] # The initial pressure in Cantera is expected in Pa; in SENKIN # it is expected in atm, so convert initial_pres = self.keywords['pressure'] * ct.one_atm # If the equivalence ratio has been specified, send the # keywords for conversion. if 'eqRatio' in self.keywords: reactants = utils.equivalence_ratio( self.gas, self.keywords['eqRatio'], self.keywords['fuel'], self.keywords['oxidizer'], self.keywords['completeProducts'], self.keywords['additionalSpecies'], ) else: # The reactants are stored in the ``keywords`` dictionary # as a list of strings, so they need to be joined. reactants = ','.join(self.keywords['reactants']) self.gas.TPX = initial_temp, initial_pres, reactants # Create a non-interacting ``Reservoir`` to be on the other # side of the ``Wall``. env = ct.Reservoir(ct.Solution('air.xml')) # Set the ``temp_func`` to ``None`` as default; it will be set # later if needed. self.temp_func = None # All of the reactors are ``IdealGas`` Reactors. Set a ``Wall`` # for every case so that later code can be more generic. If the # velocity is set to zero, the ``Wall`` won't affect anything. # We have to set the ``n_vars`` here because until the first # time step, ``ReactorNet.n_vars`` is zero, but we need the # ``n_vars`` before the first time step. if self.keywords['problemType'] == 1: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 2: self.reac = ct.IdealGasConstPressureReactor(self.gas) # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 3: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=VolumeProfile(self.keywords)) elif self.keywords['problemType'] == 4: self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 5: self.reac = ct.IdealGasReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 6: from user_routines import VolumeFunctionTime self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=VolumeFunctionTime()) elif self.keywords['problemType'] == 7: from user_routines import TemperatureFunctionTime self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) self.temp_func = ct.Func1(TemperatureFunctionTime()) elif self.keywords['problemType'] == 8: self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) self.temp_func = ct.Func1(TemperatureProfile(self.keywords)) elif self.keywords['problemType'] == 9: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(env, self.reac, A=1.0, velocity=ICEngineProfile(self.keywords)) if 'reactorVolume' in self.keywords: self.reac.volume = self.keywords['reactorVolume'] # Create the Reactor Network. self.netw = ct.ReactorNet([self.reac]) if 'sensitivity' in self.keywords: self.sensitivity = True # There is no automatic way to calculate the sensitivity of # all of the reactions, so do it manually. for i in range(self.reac.kinetics.n_reactions): self.reac.add_sensitivity_reaction(i) # If no tolerances for the sensitivity are specified, set # to the SENKIN defaults. if 'sensAbsTol' in self.keywords: self.netw.atol_sensitivity = self.keywords['sensAbsTol'] else: self.netw.atol_sensitivity = 1.0E-06 if 'sensRelTol' in self.keywords: self.netw.rtol_sensitivity = self.keywords['sensRelTol'] else: self.netw.rtol_sensitivity = 1.0E-04 else: self.sensitivity = False # If no solution tolerances are specified, set to the default # SENKIN values. if 'abstol' in self.keywords: self.netw.atol = self.keywords['abstol'] else: self.netw.atol = 1.0E-20 if 'reltol' in self.keywords: self.netw.rtol = self.keywords['reltol'] else: self.netw.rtol = 1.0E-08 if 'tempLimit' in self.keywords: self.temp_limit = self.keywords['tempLimit'] else: # tempThresh is set in the parser even if it is not present # in the input file self.temp_limit = (self.keywords['tempThresh'] + self.keywords['temperature']) self.tend = self.keywords['endTime'] # Set the maximum time step the solver can take. If a value is # not specified in the input file, default to 0.001*self.tend. # Set the time steps for saving to the binary file and writing # to the screen. If the time step for printing to the screen is # not set, default to printing 100 times. print_time_int = self.keywords.get('prntTimeInt') save_time_int = self.keywords.get('saveTimeInt') max_time_int = self.keywords.get('maxTimeStep') time_ints = [ value for value in [print_time_int, save_time_int, max_time_int] if value is not None ] if time_ints: self.netw.set_max_time_step(min(time_ints)) else: self.netw.set_max_time_step(self.tend / 100) if print_time_int is not None: self.print_time_step = print_time_int else: self.print_time_step = self.tend / 100 self.print_time = self.print_time_step self.save_time_step = save_time_int if self.save_time_step is not None: self.save_time = self.save_time_step # Store the species names in a slightly shorter variable name self.species_names = self.reac.thermo.species_names # Initialize the ignition time, in case the end time is reached # before ignition occurs self.ignition_time = None
def test_rate_func(self): f = ct.Func1(self._rate) rate = ct.CustomRate(f) self.assertNear(rate(self.gas.T), self.gas.forward_rate_constants[self._index])
def test_from_func(self): f = ct.Func1(self._rate) rxn = ct.CustomReaction(equation=self._equation, rate=f, kinetics=self.gas) self.check_rxn(rxn)
t_step_1 = t_1/steps_1 steps_2 = 110 t_2 = 0.031 t_step_2 = (t_2 - t_1)/steps_2 steps_3 = 200 t_3 = 0.033 t_step_3 = (t_3 - t_2)/steps_3 steps_4 = 250 t_4 = 0.0355 t_step_4 = (t_4 - t_3)/steps_4 steps_5 = 3000 t_5 = 0.3355 t_step_5 = (t_5 - t_4)/steps_5 # Velocity of the piston v_1 = ct.Func1(lambda t: 21/20*1000*t ) v_2 = ct.Func1(lambda t: (26.5-21)/11*(t*1000-20)+21 ) v_3 = ct.Func1(lambda t: (26.5 - 1)/2*(33-t*1000)+1 ) v_4 = ct.Func1(lambda t: (35.5-t*1000)/2.5*1 ) v_5 = ct.Func1(lambda t: 0 ) # Heat loss setting for the boundary layer zone. It varies with the wall area. q_1 = ct.Func1(lambda t: -1/area_2*(r2.T - Tw)*h_2*(2*(area_1+area_2) + Awalls - t*t/0.02*21/2*np.pi*dia_2) ) q_2 = ct.Func1(lambda t: -1/area_2*(r2.T - Tw)*h_2*(2*(area_1+area_2) + Awalls - (0.02*21/2 + (21+((26.5-21)/0.011*(t-0.02))+21)*(t-0.02)/2)*np.pi*dia_2) ) q_3 = ct.Func1(lambda t: -1/area_2*(r2.T - Tw)*h_2*(2*(area_1+area_2) + Awalls - (0.02*21/2 + (21+26.5)*0.011/2 + ( (26.5-1)/0.002*(0.033-t)+1 +26.5 )*(t-0.031)/2)*np.pi*dia_2) ) q_4 = ct.Func1(lambda t: -1/area_2*(r2.T - Tw)*h_2*(2*(area_1+area_2) + Awalls - (0.02*21/2 + (21+26.5)*0.011/2 + (26.5+1)*0.002/2 + (0.0025*1/2 - (0.0355-t)*(0.0355-t)/0.0025*1/2) )*np.pi*dia_2) ) q_5 = ct.Func1(lambda t: -1/area_2*(r2.T - Tw)*h_2*(2*(area_1+area_2) + Awalls - (0.02*21/2 + (21+26.5)*0.011/2 + (26.5+1)*0.002/2 + 0.0025*1/2 )*np.pi*dia_2) ) n_steps = steps_1 + steps_2 + steps_3 + steps_4 + steps_5 data = np.zeros( (n_steps, 13) )
def test_rate_func(self): # check result of rate expression f = ct.Func1(self._rate) rate = ct.CustomRate(f) self.assertNear(rate(self.gas.T), self.gas.forward_rate_constants[self._index])
def test_from_func1(self): # check instantiation from keywords / rate provided as func1 f = ct.Func1(self._rate) rxn = ct.CustomReaction(equation=self._equation, rate=f, kinetics=self.gas) self.check_rxn(rxn)
def test_from_func1(self): # check instantiation from keywords / rate provided as func1 f = ct.Func1(self._rate) rxn = self.from_rate(f) self.check_rxn(rxn)