def input_properties_case_REFPROP___ButaneOctane(comp1, comp2, kij): this_function_name = sys._getframe().f_code.co_name print('\n---\n THE DATA USED IN THIS SIMULATION WAS OBTAINED FROM: ', this_function_name) print('\n---\n') ''' SOURCE: REFPROP -- BUTANE AND OCTANE. ''' critical_pressure = np.array([comp1.pC, comp2.pC]) critical_temperature = np.array([comp1.Tc, comp2.Tc]) acentric_factor = np.array([comp1.AcF, comp2.AcF]) molar_mass = np.array([comp1.MM, comp2.MM]) omega_a = 0.45724 * np.ones_like(molar_mass) omega_b = 0.07780 * np.ones_like(molar_mass) binary_interaction = np.array([[0.0000, kij], [kij, 0.0000]]) specific_heat_mass_base = np.array([comp1.Cp, comp2.Cp]) specific_heat = Tools_Convert.convert_specific_heat_massbase_TO_molarbase( specific_heat_mass_base, molar_mass) return (critical_pressure, critical_temperature, acentric_factor, molar_mass, omega_a, omega_b, binary_interaction, specific_heat)
=================================== @(PRESSURE, TEMPERATURE, GLOBAL MOLAR FRACTION): These are the conditions you are interested to evaluate =================================== LEGEND: p: Interested pressure (evaluate the enthalpy for this pressure) [Pa] T: Interested temperature (evaluate the enthalpy considering this isotherm) [K] OCR: oil-circulation ratio [-]: it is a mass fraction of oil per total mass mixture z_mass: global mass fraction z: global molar fraction ''' p = 0.3e5 # <=============================== change here T = (30. + 273.15) # <=============================== change here LC, base = 0.40, 'mass' # <=============================== change here zin = np.array([LC, (1. - LC)]) z, z_mass = Tools_Convert.frac_input(MM, zin, base) ''' ======================================= CREATING OBJECTS - [to a better identification, all objects' names are followed by "_obj"] ======================================= ''' rr_obj = RachfordRice() eos_obj = PengRobinsonEos(pC, Tc, AcF, omega_a, omega_b, kij) michelsen_obj = Michelsen() flash_obj = Flash(max_iter=50, tolerance=1.0e-13, print_statistics=False) prop_obj = Properties(pC, Tc, AcF, omega_a, omega_b, kij) def getting_the_results_from_FlashAlgorithm_main(p, T, pC, Tc, AcF, z): initial_K_values = calculate_K_values_wilson(p, T, pC, Tc, AcF)
============================================================================================================= Class Molecule("name", MM, Tc, pC, AcF, Cp) LEGEND: name: compost name MM: molar mass of each component [kg/kmol] Tc: critical temperature [K] pC: critical pressure [Pa] AcF: acentric factor [-] Cp: specific heat [J / kg K] !<=== HERE IT IS IN MASS BASE, BUT IT IS CONVERTED TO MOLAR BASE INSIDE THE FUNCTION ============================================================================================================= ''' MM = np.array([58.12, 240.]) specific_heat_mass_base = np.array([1663.0, 1490.0]) #(J/kg K) specific_heat = Tools_Convert.convert_specific_heat_massbase_TO_molarbase( specific_heat_mass_base, MM) #sort as name, molar_mass, Tc, pC, AcF, Cp comp1 = Molecule("R600a", 58.12, (134.7 + 273.15), 36.4e5, 0.1853, specific_heat[0]) comp2 = Molecule("AB_ISO5", 240., (675.9 + 273.15), 20.6e5, 0.9012, specific_heat[1]) kij = -0.02668 ''' =============================================================================================================== Do you have kij above? If you don't have it ==> uncomment the CODE's 4 lines below =============================================================================================================== ''' # p_C = np.array([comp1.pC, comp2.pC]) # T_C = np.array([comp1.TC, comp2.TC]) # kij_obj = Kij_class(p_C, T_C)
def __call__(self): zin = np.array([self.LC, (1. - self.LC)]) z, z_mass = Tools_Convert.frac_input(self.MM, zin, self.base) return (self.p, self.T, z, z_mass)
Building the isotherm and molar concentration to feed the code. Why does it necessary? Because Pb = Pb @(T, z): We want Pb for a specific global molar fraction and isotherm ========================================================================================================= LEGEND: T: Interested temperature (evaluate the enthalpy considering this isotherm) [K] LC: Lighter component of your binary mixture base: It is the base of your fraction, i.e., you must specify 'molar' ou 'mass' z_mass: global {mass} fraction z: global {molar} fraction ''' T = 520. #(40. + 273.15) # <=================================== change here LC, base = 0.10, 'mass' # <=============================== change here zin = np.array([LC, (1. - LC)]) z, z_mass = Tools_Convert.frac_input(BubbleP.MM, zin, base) ''' ========================================================================================================= CHANGE HERE (II) BUILDING A RANGE: this 4 lines below it is necessary to create a range of pressure necessary in... ... executable() function. To do this it's necessary to import the function calculate_pressure_guess()... ... from BubbleP.py VERY IMPORTANT!: the step size determines how close we are to the correct root. So, smaller step produces more precise results ========================================================================================================= LEGEND: pG: Guess pressure [Pa] - It is necessary to initialize the search for correct bubble pressure
CompN = MM.shape[0] #components number Pbubble_store = np.zeros([LN, CN]) #matrix with LN lines and CN columns # Sy_store = np.zeros([LN, CN]) # y_store = np.zeros([LN, 2 * CN]) ''' ======================== PUTTING TO RUN: with a for loop ======================== ''' for index_out, T in enumerate(T_list): for index, LC_mass in enumerate(LC_mass_list): logging.debug('LC mass concentration =======> ' + str(LC_mass)) logging.debug('Temperatura =======> ' + str(T)) z_mass = np.array([LC_mass, (1. - LC_mass)]) z = Tools_Convert.convert_massfrac_TO_molarfrac(MM, z_mass) pBubble, y, Sy, counter = bubble_obj(T, z) Pbubble_store[index, index_out] = pBubble # Sy_store[index, index_out] = Sy # y_store[index, 2 * index_out:2 * index_out + 2] = y # print('%.2f \t %.2e \t %.5f' % (T, pBubble, Sy)) ''' ===================== PLOTTING ===================== ''' colors = ['r', 'b', 'k', 'y', 'm', 'c', 'g', 'lightgray'] markers = ['o', 'v', '<', '>', '.', 'p', 'P', 's', '*'] plt.title('Bubble Pressure of Mixture of ' + comp1.name + comp2.name + '(Dados Artigo Moisés)')
def calculate_enthalpy_entropy(p, pR, pC, T, TR, Tc, AcF, Cp, z, MM, hR, sR, printResults=False): pB, y_sat, Sy, counter = bubble_obj(T, z) if printResults: print('You\'re running pressure = %.3e [Pa] and temperature = %.2f C' % (p, (T - 273.15))) print( 'For this temperature the bubble pressure is: pB = %.3e [Pa] at T = (%.2f C)' % (pB, (T - 273.15))) print('\n---------------------------------------------------------)') if (p >= pB): F_V = 0.0 H_subcooled = prop_obj.calculate_enthalpy(TR, T, pR, p, z, z, hR, Cp, 'liquid') M_L = prop_obj.calculate_weight_molar_mixture(MM, z, 'liquid') H_subcooled_mass = H_subcooled * np.reciprocal(M_L) S_subcooled = prop_obj.calculate_entropy(TR, T, pR, p, z, z, sR, Cp, 'liquid') S_subcooled_mass = S_subcooled * np.reciprocal(M_L) h, s = H_subcooled_mass, S_subcooled_mass if printResults: print('--> This @(p,T) falls into single phase region') print('\nSubcooled liquid with h = %.3e [J/ kg]' % H_subcooled_mass) print('\nSubcooled liquid with s = %.3e [J/(kg K)]' % S_subcooled_mass) else: if printResults: print('This @(p,T) falls into two phase region') F_V, is_stable, K_values_newton, initial_K_values = \ FlashAlgorithm_main.getting_the_results_from_FlashAlgorithm_main(p, T, pC, Tc, AcF, z) x = z / (F_V * (K_values_newton - 1.) + 1.) y = K_values_newton * x x_mass = Tools_Convert.convert_molarfrac_TO_massfrac(MM, x) y_mass = Tools_Convert.convert_molarfrac_TO_massfrac(MM, y) H_sat_vapor = prop_obj.calculate_enthalpy(TR, T, pR, p, y, z, hR, Cp, 'saturated_vapor') M_V = prop_obj.calculate_weight_molar_mixture(MM, y, 'saturated_vapor') H_sat_vapor_mass = H_sat_vapor * np.reciprocal(M_V) H_sat_liquid = prop_obj.calculate_enthalpy(TR, T, pR, p, x, z, hR, Cp, 'saturated_liquid') M_L = prop_obj.calculate_weight_molar_mixture(MM, x, 'saturated_liquid') H_sat_liquid_mass = H_sat_liquid * np.reciprocal(M_L) enthalpy_mixture = (1. - F_V) * H_sat_liquid + F_V * H_sat_vapor F_V_mass = np.reciprocal((M_L / M_V) * (1 / F_V - 1.) + 1.) enthalpy_mixture_mass = ( 1. - F_V_mass) * H_sat_liquid_mass + F_V_mass * H_sat_vapor_mass if printResults: print( 'The mixture\'s state is ELV with a quality = %.3f [molar base]' % F_V) print( 'The mixture\'s state is ELV with a quality = %.3f [mass base]' % F_V_mass) print('x [molar base] = ', x) print('y [molar base] = ', y) print('x_mass [mass base] = ', x_mass) print('y_mass [mass base] = ', y_mass) print( '\n======\nThe mixture liquid/vapor with h = %.3e [J/ kmol]' % enthalpy_mixture) print( 'The mixture liquid/vapor with h_mass = %.3e [J/ kg] {mass base}' % enthalpy_mixture_mass) S_sat_vapor = prop_obj.calculate_entropy(TR, T, pR, p, y, z, sR, Cp, 'vapor') S_sat_vapor_mass = S_sat_vapor * np.reciprocal(M_V) S_sat_liquid = prop_obj.calculate_entropy(TR, T, pR, p, x, z, sR, Cp, 'liquid') S_sat_liquid_mass = S_sat_liquid * np.reciprocal(M_L) entropy_mixture = (1. - F_V) * S_sat_liquid + F_V * S_sat_vapor entropy_mixture_mass = ( 1. - F_V_mass) * S_sat_liquid_mass + F_V_mass * S_sat_vapor_mass h, s = enthalpy_mixture_mass, entropy_mixture_mass if printResults: print( '\n======\nThe mixture liquid/vapor with s = %.3e [J/(kmol K)]' % entropy_mixture) print( 'The mixture liquid/vapor with s_mass = %.3e [J/(kg K)] {mass base}' % entropy_mixture_mass) return F_V, h, s
sR: reference entropy (in molar base) [J/kmol K] MM: molar mass of each component [kg/kmol] M: mixture molar mass [kg/kgmol] ==> depend on phase composition ''' ''' ========================================================================================================= CHANGE HERE (I) @(PRESSURE, TEMPERATURE, GLOBAL MOLAR FRACTION): These are the conditions you are interested to evaluate ========================================================================================================= ''' p = 200e3 T = (20. + 273.15) LC, base = 99. / 100, 'mass' # <=============================== change here zin = np.array([LC, (1. - LC)]) z, z_mass = Tools_Convert.frac_input(MM, zin, base) ''' ========================================================================================================= CHANGE HERE (II) BUBBLE PRESSURE - First you MUST load BubbleP.py to get the bubble pressure at the interested ... temperature. Such value is used as reference_pressure {i.e., pR = pB (T,z)} ========================================================================================================= ''' TR = 273.15 pR, y_sat, Sy_sat, counter = bubble_obj(TR, z) hR_mass = 200e3 hR = hR_mass * prop_obj.calculate_weight_molar_mixture(MM, z, 'saturated_liquid') sR_mass = 1000. sR = sR_mass * prop_obj.calculate_weight_molar_mixture(MM, z,
f_L, Z_L = eos_obj.calculate_fugacities_with_minimum_gibbs_energy(p, T, x, 'liquid') f_V, Z_V = eos_obj.calculate_fugacities_with_minimum_gibbs_energy(p, T, y, 'vapor') PHI_L = f_L / (x * p) PHI_V = f_V / (y * p) delta = np.sum(np.abs(x * PHI_L - y * PHI_V)) print('delta before = ', delta) if delta < epsilon: print('delta', delta) print('Liquid Composition', x) print('Vapor Composition', y) return x,y, counter else: x[0] = PHI_V[0] * (PHI_V[1] - PHI_L[1]) / (PHI_L[0] * PHI_V[1] - PHI_V[0] * PHI_L[1]) x[1] = 1. - x[0] y[0] = x[0] * PHI_L[0] / PHI_V[0] y[1] = 1. - y[0] T = 500.0 p = 2 * 1e6 xguess = np.array([0.1, 0.9]) yguess = np.array([0.9, 0.1]) x, y, counter = calculate(xguess, yguess, p, T) print('Loop', counter) x_mass = Tools_Convert.convert_molarfrac_TO_massfrac(MM, x) y_mass = Tools_Convert.convert_molarfrac_TO_massfrac(MM, y) print('Liquid Mass Fraction [-] = ', x_mass) print('Vapor Mass Fraction [-] = ', y_mass)