def test_mechanism_simple_api_methods(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) sol = Solution(xml) m = ChemicalMechanismSpec.from_solution(sol) self.assertEqual(m.n_species, sol.n_species, 'ChemicalMechanismSpec.n_species vs ct.Solution.n_species') self.assertEqual(m.n_reactions, sol.n_reactions, 'ChemicalMechanismSpec.n_reactions vs ct.Solution.n_reactions') for i in range(m.n_species): self.assertEqual(m.species_names[i], sol.species_names[i], 'ChemicalMechanismSpec.species_name[i] vs ct.Solution.species_name[i]') for n in m.species_names: self.assertEqual(m.species_index(n), sol.species_index(n), 'ChemicalMechanismSpec.species_index(name) vs ct.Solution.species_index(name)') for i, n in enumerate(m.species_names): self.assertEqual(m.species_index(n), i, 'species names and indices are consistent, index vs i') self.assertEqual(n, m.species_names[i], 'species names and indices are consistent, name vs n') self.assertEqual(m.molecular_weight(i), m.molecular_weight(n), 'ChemicalMechanismSpec molecular_weight(name) vs molecular_weight(idx)') except: self.assertTrue(False) try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) m = ChemicalMechanismSpec.from_solution(Solution(xml)) m.molecular_weight(list()) self.assertTrue(False) except: self.assertTrue(True)
def test_create_invalid_stpair_streams(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) m = ChemicalMechanismSpec(xml, 'h2-burke') m.stream(stp_air=False) self.assertTrue(False) except: self.assertTrue(True)
def test_create_invalid_streams_no_property_values(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) m = ChemicalMechanismSpec(xml, 'h2-burke') m.stream('TPX') self.assertTrue(False) except: self.assertTrue(True)
def validate_on_mechanism(mech, temperature, pressure, tau, do_rhs, do_jac): xml = join(test_mech_directory, mech + '.xml') T = temperature Tin = T + 1000. p = pressure r = ChemicalMechanismSpec(xml, 'gas').griffon gas = Solution(xml) ns = gas.n_species y = np.ones(ns) # equal masses in the reactor gas.TPY = T, p, y y = np.copy(gas.Y) xin = np.ones(ns) # equal moles in the feed gas.TPX = Tin, p, xin yin = np.copy(gas.Y) state = hstack((T, y[:-1])) rhsCN = rhs_cantera(p, T, y, Tin, yin, tau, gas) rhsGR = np.empty(ns) r.reactor_rhs_isobaric(state, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR) if do_rhs: return max(abs(rhsGR - rhsCN) / (abs(rhsCN) + 1.)) < 1.e-4 if do_jac: jacGR = np.empty(ns * ns) r.reactor_jac_isobaric(state, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, 0, 0, rhsGR, jacGR) jacGR = jacGR.reshape((ns, ns), order='F') dT = 1.e-6 dY = 1.e-6 jacFD = np.empty((ns, ns)) rhsGR1, rhsGR2 = np.empty(ns), np.empty(ns) state_m = hstack((T - dT, y[:-1])) state_p = hstack((T + dT, y[:-1])) r.reactor_rhs_isobaric(state_m, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR1) r.reactor_rhs_isobaric(state_p, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR2) jacFD[:, 0] = (- rhsGR1 + rhsGR2) / (2. * dT) for i in range(ns - 1): y_m1, y_p1 = np.copy(y), np.copy(y) y_m1[i] += - dY y_m1[-1] -= - dY y_p1[i] += dY y_p1[-1] -= dY state_m = hstack((T, y_m1[:-1])) state_p = hstack((T, y_p1[:-1])) r.reactor_rhs_isobaric(state_m, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR1) r.reactor_rhs_isobaric(state_p, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR2) jacFD[:, 1 + i] = (- rhsGR1 + rhsGR2) / (2. * dY) pass_jac = max(abs(jacGR - jacFD) / (abs(jacGR) + 1.)) < 1.e-2 return pass_jac
def construct_adiabatic_flamelet(initialization, grid_type, diss_rate_form): test_xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) mechanism = ChemicalMechanismSpec(cantera_xml=test_xml, group_name='h2-burke') air = mechanism.stream(stp_air=True) fuel = mechanism.stream('X', 'H2:1') fuel.TP = 300, air.P if grid_type == 'uniform': grid_specs = {'grid_points': 8} elif grid_type == 'clustered-1args': grid_specs = {'grid_points': 8} elif grid_type == 'clustered-2args': grid_specs = {'grid_points': 8, 'grid_cluster_intensity': 4.} elif grid_type == 'clustered-3args': grid_specs = {'grid_points': 8, 'grid_cluster_intensity': 4., 'grid_cluster_point': 0.4} elif grid_type == 'custom': grid_specs = {'grid': np.linspace(0., 1., 8)} if diss_rate_form == 'Peters': drf_specs = {'max_dissipation_rate': 1., 'dissipation_rate_form': diss_rate_form} elif diss_rate_form == 'uniform': drf_specs = {'max_dissipation_rate': 1., 'dissipation_rate_form': diss_rate_form} elif diss_rate_form == 'custom': drf_specs = {'dissipation_rate': np.linspace(0., 1., 8)} flamelet_specs = {'mech_spec': mechanism, 'oxy_stream': air, 'fuel_stream': fuel, 'initial_condition': initialization} flamelet_specs.update(grid_specs) flamelet_specs.update(drf_specs) try: Flamelet(**flamelet_specs) Flamelet(flamelet_specs=flamelet_specs) fso = FlameletSpec(**flamelet_specs) f = Flamelet(fso) fso_pickle = pickle.dumps(fso) fso2 = pickle.loads(fso_pickle) f = Flamelet(fso2) lib = f.make_library_from_interior_state(f.initial_interior_state) Flamelet(library_slice=lib) lib_pickle = pickle.dumps(lib) lib2 = pickle.loads(lib_pickle) Flamelet(library_slice=lib2) return True except: return False
def test_create_invalid_mechanism_spec_bad_group(self): xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) try: ChemicalMechanismSpec(xml, 'bad group') self.assertTrue(False) except CanteraLoadError: self.assertTrue(True)
def test_create_valid_mechanism_spec_from_xml(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) m = ChemicalMechanismSpec(xml, 'h2-burke') g = m.griffon x = m.mech_xml_path s = m.gas self.assertTrue(True) except: self.assertTrue(False)
def test_mechanism_serialization(self): xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) sol = Solution(xml) m1 = ChemicalMechanismSpec.from_solution(sol) m1_pickle = pickle.dumps(m1) m2 = pickle.loads(m1_pickle) self.assertTrue(m1.mech_data['species'] == m2.mech_data['species']) self.assertTrue(m1.mech_data['reactions'] == m2.mech_data['reactions'])
def test_create_valid_mechanism_spec_from_solution(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) sol = Solution(xml) m = ChemicalMechanismSpec.from_solution(sol) g = m.griffon x = m.mech_xml_path n = m.group_name s = m.gas self.assertTrue(True) except: self.assertTrue(False)
def test_create_valid_streams(self): try: xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) m = ChemicalMechanismSpec(xml, 'h2-burke') air = m.stream(stp_air=True) h2o2 = m.stream('TPX', (300., 101325., 'H2:1, O2:1')) air_copy = m.copy_stream(air) mix = m.mix_streams([(h2o2, 1.), (air, 1.)], 'mass', 'HP') mix = m.mix_streams([(h2o2, 1.), (air, 1.)], 'mole', 'TP') mix = m.mix_streams([(h2o2, 1.), (air, 1.)], 'mass', 'UV') self.assertTrue(True) except: self.assertTrue(False)
def verify_rates_mechanism(ctsol: ct.Solution, serialize_mech: bool): mech = Mechanism.from_solution(ctsol) if serialize_mech: serialized = pickle.dumps(mech) mech = pickle.loads(serialized) tolerance = 1.e-14 def verify_T_p(temp, pres): valid = True for mix in [ np.ones(ctsol.n_species), np.array([1., 1.e-8, 1.e-8, 1.e-8, 1.e-8, 1.e-8]), np.array([1.e-8, 1., 1.e-8, 1.e-8, 1.e-8, 1.e-8]), np.array([1.e-8, 1.e-8, 1., 1.e-8, 1.e-8, 1.e-8]), np.array([1.e-8, 1.e-8, 1.e-8, 1., 1.e-8, 1.e-8]), np.array([1.e-8, 1.e-8, 1.e-8, 1.e-8, 1., 1.e-8]), np.array([1.e-8, 1.e-8, 1.e-8, 1.e-8, 1.e-8, 1.]), np.array([1., 1.e-16, 1.e-16, 1.e-16, 1.e-16, 1.e-16]), np.array([1.e-16, 1., 1.e-16, 1.e-16, 1.e-16, 1.e-16]), np.array([1.e-16, 1.e-16, 1., 1.e-16, 1.e-16, 1.e-16]), np.array([1.e-16, 1.e-16, 1.e-16, 1., 1.e-16, 1.e-16]), np.array([1.e-16, 1.e-16, 1.e-16, 1.e-12, 1., 1.e-16]), np.array([1.e-16, 1.e-16, 1.e-16, 1.e-12, 1.e-16, 1.]) ]: ns = ctsol.n_species ctsol.TPY = temp, pres, mix rho = ctsol.density_mass w_ct = ctsol.net_production_rates * ctsol.molecular_weights w_gr = np.zeros(ns) mech.griffon.production_rates(T, rho, ctsol.Y, w_gr) valid = valid and np.max( np.abs(w_gr - w_ct) / (np.abs(w_ct) + 1.e0)) < tolerance return valid pass_test = True for T in T_range: for p in p_range: pass_test = pass_test and verify_T_p(T, p) return pass_test
for i, s in enumerate(species_decl): species_dict['const'].append(ct.Species(s.name, s.composition)) species_dict['const'][-1].thermo = ct.ConstantCp( 300., 3000., 101325., (300., 0., 0., float(i + 1) * 1.e4)) species_dict['nasa7'].append(ct.Species(s.name, s.composition)) coeffs = [ float(i + 1) * v for v in [1.e0, 1.e-2, 1.e-4, 1.e-6, 1.e-8, 1.e-10, 1.e-12] ] species_dict['nasa7'][-1].thermo = ct.NasaPoly2( 300., 3000., 101325., hstack([1200.] + coeffs + coeffs)) mechs = [('const', Mechanism.from_solution( ct.Solution(thermo='IdealGas', kinetics='GasKinetics', species=species_dict['const'], reactions=[]))), ('nasa7', Mechanism.from_solution( ct.Solution(thermo='IdealGas', kinetics='GasKinetics', species=species_dict['nasa7'], reactions=[])))] tolerance = 1.e-14 def do_mmw(griffon, gas, T, p, y): gas.TPY = T, p, y ct = gas.mean_molecular_weight
def validate_on_mechanism(mech, temperature, pressure, test_rhs=True, test_jac=True): xml = join(test_mech_directory, mech + '.xml') T = temperature p = pressure r = ChemicalMechanismSpec(xml, 'gas').griffon gas = Solution(xml) ns = gas.n_species gas.TPX = T, p, ones(ns) y = gas.Y state = hstack((T, y[:-1])) rhsGR = np.empty(ns) r.reactor_rhs_isobaric(state, p, 0., np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, rhsGR) if test_jac: Tin, yin, tau = 0, np.ndarray(1), 0 rhsTmp = np.empty(ns) jacGR = np.empty(ns * ns) r.reactor_jac_isobaric(state, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, 0, 0, rhsTmp, jacGR) jacGR = jacGR.reshape((ns, ns), order='F') dT = 1.e-6 dY = 1.e-6 jacFD = np.empty((ns, ns)) rhsGR1, rhsGR2 = np.empty(ns), np.empty(ns) state_m = hstack((T - dT, y[:-1])) state_p = hstack((T + dT, y[:-1])) r.reactor_rhs_isobaric(state_m, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, rhsGR1) r.reactor_rhs_isobaric(state_p, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, rhsGR2) jacFD[:, 0] = (- rhsGR1 + rhsGR2) / (2. * dT) for i in range(ns - 1): y_m1, y_p1 = np.copy(y), np.copy(y) y_m1[i] += - dY y_m1[-1] -= - dY y_p1[i] += dY y_p1[-1] -= dY state_m = hstack((T, y_m1[:-1])) state_p = hstack((T, y_p1[:-1])) r.reactor_rhs_isobaric(state_m, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, rhsGR1) r.reactor_rhs_isobaric(state_p, p, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, rhsGR2) jacFD[:, 1 + i] = (- rhsGR1 + rhsGR2) / (2. * dY) pass_jac = max(abs(jacGR - jacFD) / (abs(jacGR) + 1.)) < 1.e-2 w = gas.net_production_rates * gas.molecular_weights h = gas.standard_enthalpies_RT * gas.T * gas_constant / gas.molecular_weights rhsCN = zeros(ns) rhsCN[1:] = w[:-1] / gas.density rhsCN[0] = - sum(w * h) / gas.density / gas.cp_mass pass_rhs = max(abs(rhsGR - rhsCN) / (abs(rhsCN) + 1.)) < 100. * sqrt(np.finfo(float).eps) if test_rhs and test_jac: return pass_rhs and pass_jac if test_rhs: return pass_rhs if test_jac: return pass_jac
def validate_on_mechanism(mech, temperature, pressure, tau, do_rhs, do_jac): xml = join(test_mech_directory, mech + '.xml') T = temperature Tin = T + 1000. p = pressure r = ChemicalMechanismSpec(xml, 'gas').griffon gas = Solution(xml) ns = gas.n_species y = np.ones(ns) # equal masses in the reactor gas.TPY = T, p, y y = np.copy(gas.Y) rho = gas.density_mass xin = np.ones(ns) # equal moles in the feed gas.TPX = Tin, p, xin yin = np.copy(gas.Y) rhoin = gas.density_mass state = hstack((rho, T, y[:-1])) rhsGRChemOnly = np.zeros(ns + 1) r.reactor_rhs_isochoric(state, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, False, rhsGRChemOnly) rhsCN = rhs_cantera(p, T, y, rhoin, Tin, yin, tau, gas, rhsGRChemOnly) rhsGR = np.empty(ns + 1) r.reactor_rhs_isochoric(state, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR) if do_rhs: return max(abs(rhsGR - rhsCN) / (abs(rhsCN) + 1.)) < 100. * sqrt(np.finfo(float).eps) if do_jac: jacGR = np.empty((ns + 1) * (ns + 1)) r.reactor_jac_isochoric(state, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, 0, rhsGR, jacGR) jacGR = jacGR.reshape((ns + 1, ns + 1), order='F') drho = 1.e-6 dT = 1.e-6 dY = 1.e-6 jacFD = np.empty((ns + 1, ns + 1)) rhsGR1, rhsGR2 = np.empty(ns + 1), np.empty(ns + 1) state_m = hstack((rho - drho, T, y[:-1])) state_p = hstack((rho + drho, T, y[:-1])) r.reactor_rhs_isochoric(state_m, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR1) r.reactor_rhs_isochoric(state_p, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR2) jacFD[:, 0] = (-rhsGR1 + rhsGR2) / (2. * drho) state_m = hstack((rho, T - dT, y[:-1])) state_p = hstack((rho, T + dT, y[:-1])) r.reactor_rhs_isochoric(state_m, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR1) r.reactor_rhs_isochoric(state_p, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR2) jacFD[:, 1] = (-rhsGR1 + rhsGR2) / (2. * dT) for i in range(ns - 1): y_m1, y_p1 = np.copy(y), np.copy(y) y_m1[i] += -dY y_m1[-1] -= -dY y_p1[i] += dY y_p1[-1] -= dY state_m = hstack((rho, T, y_m1[:-1])) state_p = hstack((rho, T, y_p1[:-1])) r.reactor_rhs_isochoric(state_m, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR1) r.reactor_rhs_isochoric(state_p, rhoin, Tin, yin, tau, 0, 0, 0, 0, 0, 0, True, rhsGR2) jacFD[:, 2 + i] = (-rhsGR1 + rhsGR2) / (2. * dY) return max(abs(jacGR - jacFD) / (abs(jacGR) + 1.)) < 1.e-4
def validate_on_mechanism(mech, temperature, pressure, full_Jacobian, isochoric): xml = join(test_mech_directory, mech + '.xml') r = ChemicalMechanismSpec(xml, 'gas').griffon gas = Solution(xml) ns = gas.n_species T = temperature p = pressure gas.TPX = T, p, ones(ns) y = gas.Y rho = gas.density_mass if full_Jacobian and isochoric: state = hstack((rho, T, y[:-1])) rhsGRTemporary = np.empty(ns + 1) jac_dense = np.empty((ns + 1) * (ns + 1)) jac_sparse = np.empty((ns + 1) * (ns + 1)) r.reactor_jac_isochoric(state, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, 0, rhsGRTemporary, jac_dense) r.reactor_jac_isochoric(state, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, 2, rhsGRTemporary, jac_sparse) jac_dense = jac_dense.reshape((ns + 1, ns + 1), order='F') jac_sparse = jac_sparse.reshape((ns + 1, ns + 1), order='F') elif full_Jacobian and not isochoric: state = hstack((T, y[:-1])) k = np.empty(ns) jac_dense = np.empty(ns * ns) jac_sparse = np.empty(ns * ns) r.reactor_jac_isobaric(state, p, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, 0, 0, k, jac_dense) r.reactor_jac_isobaric(state, p, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, 2, 0, k, jac_sparse) jac_dense = jac_dense.reshape((ns, ns), order='F') jac_sparse = jac_sparse.reshape((ns, ns), order='F') else: jac_dense = np.zeros((ns + 1) * (ns + 1)) jac_sparse = np.zeros((ns + 1) * (ns + 1)) r.prod_rates_primitive_sensitivities(rho, T, y, 0, jac_dense) r.prod_rates_primitive_sensitivities(rho, T, y, 2, jac_sparse) jac_dense = jac_dense.reshape((ns + 1, ns + 1), order='F')[:-1, :] jac_sparse = jac_sparse.reshape((ns + 1, ns + 1), order='F')[:-1, :] jac_fd = np.zeros_like(jac_dense) rhsGR1 = np.zeros(ns) rhsGR2 = np.zeros(ns) dT = 1.e-4 dr = 1.e-4 dY = 1.e-4 r.production_rates(T, rho + dr, y, rhsGR1) r.production_rates(T, rho - dr, y, rhsGR2) jac_fd[:, 0] = (rhsGR1 - rhsGR2) / dr * 0.5 r.production_rates(T + dT, rho, y, rhsGR1) r.production_rates(T - dT, rho, y, rhsGR2) jac_fd[:, 1] = (rhsGR1 - rhsGR2) / dT * 0.5 for spec_idx in range(ns - 1): Yp = np.copy(y) Yp[spec_idx] += dY Yp[-1] -= dY Ym = np.copy(y) Ym[spec_idx] -= dY Ym[-1] += dY r.production_rates(T, rho, Yp, rhsGR1) r.production_rates(T, rho, Ym, rhsGR2) jac_fd[:, 2 + spec_idx] = (rhsGR1 - rhsGR2) / dY * 0.5 pass_sparse_vs_dense_jac = np.linalg.norm( jac_dense.ravel() - jac_sparse.ravel(), ord=np.Inf) < 1.e-10 # if not pass_sparse_vs_dense_jac: # print(mech) # diff = abs(jac_dense - jac_sparse) / (abs(jac_dense) + 1.) # nr, nc = jac_dense.shape # print('dense') # for ir in range(nr): # for ic in range(nc): # print(f'{jac_dense[ir, ic]:8.0e}', end=', ') # print('') # print('sparse') # for ir in range(nr): # for ic in range(nc): # print(f'{jac_sparse[ir, ic]:8.0e}', end=', ') # print('') # print('finite difference') # for ir in range(nr): # for ic in range(nc): # print(f'{jac_fd[ir, ic]:8.0e}', end=', ') # print('') # print('diff') # for ir in range(nr): # for ic in range(nc): # print(f'{diff[ir, ic]:8.0e}' if diff[ir, ic] > 1.e-12 else f'{"":8}', end=', ') # print('') return pass_sparse_vs_dense_jac
def create_test(ht, ic, gt, drf): if ht == 'adiabatic': def test(self): self.assertTrue(construct_adiabatic_flamelet(ic, gt, drf)) elif ht == 'nonadiabatic': def test(self): self.assertTrue(construct_nonadiabatic_flamelet(ic, gt, drf)) return test class Construction(unittest.TestCase): pass test_xml = abspath(join('tests', 'test_mechanisms', 'h2-burke.xml')) mechanism = ChemicalMechanismSpec(cantera_xml=test_xml, group_name='h2-burke') air = mechanism.stream(stp_air=True) fuel = mechanism.stream('X', 'H2:1') fuel.TP = 300, air.P flamelet_specs = {'mech_spec': mechanism, 'oxy_stream': air, 'fuel_stream': fuel, 'grid_points': 8, 'grid_cluster_intensity': 4., 'initial_condition': 'equilibrium', 'max_dissipation_rate': 0.} temp_flamelet = Flamelet(**flamelet_specs) for ht in temp_flamelet._heat_transfers:
def validate_on_mechanism(mech, temperature, pressure, test_rhs=True, test_jac=True): xml = join(test_mech_directory, mech + '.xml') r = ChemicalMechanismSpec(xml, 'gas').griffon gas = Solution(xml) ns = gas.n_species T = temperature p = pressure gas.TPX = T, p, ones(ns) y = gas.Y rho = gas.density_mass state = hstack((rho, T, y[:-1])) rhsGR = np.empty(ns + 1) rhsGRTemporary = np.empty(ns + 1) jacGR = np.empty((ns + 1) * (ns + 1)) r.reactor_rhs_isochoric(state, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, rhsGR) r.reactor_jac_isochoric(state, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, 0, rhsGRTemporary, jacGR) jacGR = jacGR.reshape((ns + 1, ns + 1), order='F') def cantera_rhs(rho_arg, T_arg, Y_arg): gas.TDY = T_arg, rho_arg, Y_arg w = gas.net_production_rates * gas.molecular_weights e = gas.standard_int_energies_RT * gas.T * gas_constant / gas.molecular_weights cv = gas.cv_mass rhs = zeros(ns + 1) rhs[0] = 0. rhs[1] = -sum(w * e) / (rho_arg * cv) rhs[2:] = w[:-1] / rho return rhs rhsCN = cantera_rhs(rho, T, y) if test_rhs: pass_rhs = max(abs(rhsGR - rhsCN) / (abs(rhsCN) + 1.)) < 100. * sqrt(np.finfo(float).eps) if test_jac: jacFD = zeros((ns + 1, ns + 1)) wm1 = zeros(ns + 1) wp1 = zeros(ns + 1) drho = 1.e-4 dT = 1.e-2 dY = 1.e-6 state_m = hstack((rho - drho, T, y[:-1])) state_p = hstack((rho + drho, T, y[:-1])) r.reactor_rhs_isochoric(state_m, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wm1) r.reactor_rhs_isochoric(state_p, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wp1) jacFD[:, 0] = (-wm1 + wp1) / (2. * drho) state_m = hstack((rho, T - dT, y[:-1])) state_p = hstack((rho, T + dT, y[:-1])) r.reactor_rhs_isochoric(state_m, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wm1) r.reactor_rhs_isochoric(state_p, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wp1) jacFD[:, 1] = (-wm1 + wp1) / (2. * dT) for i in range(ns - 1): y_m1, y_p1 = copy(y), copy(y) y_m1[i] += -dY y_m1[-1] -= -dY y_p1[i] += dY y_p1[-1] -= dY state_m = hstack((rho, T, y_m1[:-1])) state_p = hstack((rho, T, y_p1[:-1])) r.reactor_rhs_isochoric(state_m, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wm1) r.reactor_rhs_isochoric(state_p, 0, 0, np.ndarray(1), 0, 0, 0, 0, 0, 0, 0, False, wp1) jacFD[:, 2 + i] = (-wm1 + wp1) / (2. * dY) gas.TDY = T, rho, y cv = gas.cv_mass cvi = gas.standard_cp_R * gas_constant / gas.molecular_weights w = gas.net_production_rates * gas.molecular_weights e = gas.standard_int_energies_RT * gas.T * gas_constant / gas.molecular_weights gas.TDY = T + dT, rho, y wp = gas.net_production_rates * gas.molecular_weights cvp = gas.cv_mass gas.TDY = T - dT, rho, y wm = gas.net_production_rates * gas.molecular_weights cvm = gas.cv_mass wsensT = (wp - wm) / (2. * dT) cvsensT = (cvp - cvm) / (2. * dT) jacFD11 = np.copy(jacFD[1, 1]) jacSemiFD11 = -1. / cv * (1. / rho * (sum(wsensT * e) + sum(cvi * w)) + cvsensT * rhsGR[1]) pass_jac = max(abs(jacGR - jacFD) / (abs(jacGR) + 1.)) < 1.e-4 if test_rhs: return pass_rhs if test_jac: if not pass_jac: print(jacGR[1, 1]) print(jacSemiFD11) print(jacFD11) print(abs(jacGR - jacFD) / (abs(jacGR) + 1.)) return pass_jac
import unittest import numpy as np from os.path import join, abspath import cantera as ct from spitfire import ChemicalMechanismSpec as Mechanism, HomogeneousReactor import spitfire.chemistry.analysis as sca xml = abspath(join('tests', 'test_mechanisms', 'hydrogen_one_step.xml')) sol = ct.Solution(thermo='IdealGas', kinetics='GasKinetics', species=ct.Species.listFromFile(xml), reactions=ct.Reaction.listFromFile(xml)) mechanism = Mechanism.from_solution(sol) def construct_reactor(configuration, mass_transfer, heat_transfer, shape): air = mechanism.stream(stp_air=True) fuel = mechanism.stream('X', 'H2:1') mix = mechanism.mix_for_equivalence_ratio(1.0, fuel, air) mix.TP = 1200., 101325. feed = mechanism.copy_stream(mix) tau = 1.e-3 extra_args = dict() if mass_transfer == 'open': if configuration == 'isobaric': extra_args['feed_temperature'] = feed.T extra_args['feed_mass_fractions'] = feed.Y
def verify_sensitivities_mechanism(ctsol: ct.Solution, serialize_mech: bool): mech = Mechanism.from_solution(ctsol) if serialize_mech: serialized = pickle.dumps(mech) mech = pickle.loads(serialized) tolerance = 1.e-2 def verify_T_p(temp, pres): valid = True for mix in [np.ones(ctsol.n_species)]: ns = ctsol.n_species ctsol.TPY = temp, pres, mix rho = ctsol.density_mass jacGR = np.zeros((ns + 1) * (ns + 1)) mech.griffon.prod_rates_primitive_sensitivities( rho, T, ctsol.Y, 0, jacGR) jacGR = jacGR.reshape((ns + 1, ns + 1), order='F')[:-1, :] jacFD = np.zeros_like(jacGR) rhsGR1 = np.zeros(ns) rhsGR2 = np.zeros(ns) dT = 1.e-4 dr = 1.e-4 dY = 1.e-4 mech.griffon.production_rates(T, rho + dr, ctsol.Y, rhsGR1) mech.griffon.production_rates(T, rho - dr, ctsol.Y, rhsGR2) jacFD[:, 0] = (rhsGR1 - rhsGR2) / dr * 0.5 mech.griffon.production_rates(T + dT, rho, ctsol.Y, rhsGR1) mech.griffon.production_rates(T - dT, rho, ctsol.Y, rhsGR2) jacFD[:, 1] = (rhsGR1 - rhsGR2) / dT * 0.5 for spec_idx in range(ns - 1): Yp = np.copy(ctsol.Y) Yp[spec_idx] += dY Yp[-1] -= dY Ym = np.copy(ctsol.Y) Ym[spec_idx] -= dY Ym[-1] += dY mech.griffon.production_rates(T, rho, Yp, rhsGR1) mech.griffon.production_rates(T, rho, Ym, rhsGR2) jacFD[:, 2 + spec_idx] = (rhsGR1 - rhsGR2) / dY * 0.5 scale = np.abs(jacFD) + 1.0 error = np.max(np.abs((jacFD - jacGR) / scale)) > tolerance if error: print(f'T = {T}, p = {p}, Y = {mix}') print('fd:') for i in range(ns): for j in range(ns + 1): print(f'{jacFD[i, j]:12.2e}', end=', ') print('') print('gr:') for i in range(ns): for j in range(ns + 1): print(f'{jacGR[i, j]:12.2e}', end=', ') print('') print('gr-fd:') for i in range(ns): for j in range(ns + 1): print(f'{jacGR[i, j] - jacFD[i, j]:12.2e}', end=', ') print('') valid = valid and not error return valid pass_test = True for T in T_range: for p in p_range: pass_test = pass_test and verify_T_p(T, p) return pass_test
def test_create_invalid_mechanism_spec(self): try: ChemicalMechanismSpec('does not exist', 'at all') self.assertTrue(False) except CanteraLoadError: self.assertTrue(True)