def test_equilibrium(): mechanism = 'gri30.cti' # define states initial_gas = Solution(mechanism) initial_gas.TPX = 300, 101325, {'H2': 1} working_gas = Solution(mechanism) working_gas.TPX = 300, 101325 * 2, {'H2': 1} velocity_guess = 7 # errors from hand calculations good_errors = [ -18.375000000, # enthalpy 101322.993718076, # pressure ] test_errors = calculate_error.equilibrium( working_gas=working_gas, initial_state_gas=initial_gas, initial_velocity_guess=velocity_guess) for test, good in zip(test_errors, good_errors): assert abs(test - good) / good < 1e-7
def test_reflected_shock_frozen(): mechanism = 'gri30.cti' # define states initial_gas = Solution(mechanism) initial_gas.TPX = 300, 101325, {'H2': 1} working_gas = Solution(mechanism) working_gas.TPX = 300, 101325 * 2, {'H2': 1} velocity_guess = 7 # errors from hand calculations good_errors = [ -73.5, # enthalpy 101316.97487230592 # pressure ] test_errors = calculate_error.reflected_shock_frozen( working_gas=working_gas, post_shock_gas=initial_gas, shock_speed=velocity_guess) for test, good in zip(test_errors, good_errors): assert abs(test - good) / good < 1e-7
def test_no_convergence(): # ensure the proper warning is generated when solution doesn't converge mechanism = 'gri30.cti' initial_gas = Solution(mechanism) initial_gas.TPX = 300, 101325, {'H2': 1} working_gas = Solution(mechanism) working_gas.TPX = 300, 101325 * 2, {'H2': 1} with pytest.warns(Warning, match='No convergence within 1 iterations'): sd.Detonation.cj_state(working_gas, initial_gas, 1e-50, 1e-50, 1.5, 1)
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 test_good_input(): # compare against SDToolbox results mechanism = 'gri30.cti' initial_gas = Solution(mechanism) initial_gas.TPX = 300, 101325, {'H2': 1} working_gas = Solution(mechanism) working_gas.TPX = 300, 101325 * 2, {'H2': 1} cj_calcs = sd.Detonation.cj_state( working_gas, initial_gas, 1e-5, 1e-5, 1.5 ) good_temp = 355.77590742266216 good_press = 180244.9690980063 good_species = {'H': 2.8407416566652653e-30, 'H2': 1.0} test_temp = cj_calcs[0].T check_temp = abs(test_temp - good_temp) / good_temp < 1e-7 test_press = cj_calcs[0].P check_press = abs(test_press - good_press) / good_press < 1e-7 good_velocity = 1700.3611387277992 test_velocity = cj_calcs[1] check_velocity = abs(test_velocity - good_velocity) / good_velocity \ < 1e-7 checks = [check_temp, check_press, check_velocity] # make sure the species in each solution are the same test_species = cj_calcs[0].mole_fraction_dict() for species in good_species: checks.append( good_species[species] - test_species[species] < 1e-7 ) assert all(checks)
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 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