def setUp(self): # calculate stage pressures cmp_p0 = 101.3 # kPa cmp_p2 = 10.0e3 # kPa cmp_p1 = (1.43 * cmp_p0 * cmp_p2)**0.5 # kPa exp_p0 = 7.0e3 # kPa exp_p2 = 101.3 # kPa exp_p1 = (1.43 * exp_p0 * exp_p2)**0.5 # kPa # test conditions T_atm_K = 293.15 T_atm_C = T_atm_K - 273.15 inputs = ICAES.get_default_inputs() inputs['p_atm'] = cmp_p0 # kPa inputs['T_atm'] = T_atm_C # C inputs['depth'] = 900.0 # [m] inputs['PR_type'] = 'fixed' # inputs['n_stages_cmp'] = 2 inputs['PR_cmp'] = [cmp_p1 / cmp_p0, cmp_p2 / cmp_p1] inputs['ML_cmp1'] = 1.0 * (1.65 / (cmp_p1 / 1000) - 0.05) inputs['ML_cmp2'] = 5.0 * (1.65 / (cmp_p2 / 1000) - 0.05) inputs['ML_cmp3'] = -1.0 # inputs['n_stages_exp'] = 2 inputs['PR_exp'] = [exp_p0 / exp_p1, exp_p1 / exp_p2] inputs['ML_exp1'] = 5.0 * (1.65 / (exp_p0 / 1000) - 0.05) inputs['ML_exp2'] = 1.0 * (1.65 / (exp_p1 / 1000) - 0.05) inputs['ML_exp3'] = -1.0 self.sys = ICAES(inputs=inputs) # overwrite calculated air and water properties self.sys.M = 29.0 self.sys.cp = 1.004 self.sys.gamma = 1.4 self.sys.c_water = 4.1816 self.sys.T_store_init = T_atm_K # [K] self.sys.T_store = T_atm_K # [K] self.sys.T2 = T_atm_K # [K] self.sys.T3 = T_atm_K # [K] self.sys.m_store = self.sys.m_store * 1.2 # increase amount of air to stay within pressure limits # solve two timesteps (index 0 = compression, index 1 = expansion) self.sys.update(m_dot=10.0, delta_t=2.0) self.sys.update(m_dot=-10.0, delta_t=1.0) self.sys.data.to_csv('test_perf.csv')
def parameter_sweep(sensitivity_input): start = time.time() # create system inputs = ICAES.get_default_inputs() for variable in sensitivity_input.index: inputs[variable] = sensitivity_input[variable] system = ICAES(inputs=inputs) # run single cycle and analyze system.single_cycle() results = system.analyze_performance() end = time.time() results['solve_time'] = end - start # combine inputs and results to return in single series single_output = pd.concat([sensitivity_input, results]) return single_output
def parameter_sweep(sweep_input): start = time.time() # create system inputs = ICAES.get_default_inputs() inputs['steps'] = sweep_input['steps'] # [kPa] inputs['p_store_min'] = sweep_input['p_min'] # [kPa] inputs['p_store_init'] = sweep_input['p_min'] # [kPa] inputs['p_store_max'] = sweep_input['p_max'] # [kPa] inputs['eta_storage'] = sweep_input['eta_storage'] # [-] inputs['V_res'] = sweep_input['V_res'] # [m3] inputs['phi'] = sweep_input['phi'] # porosity [-] inputs['Slr'] = sweep_input['Slr'] # liquid residual fraction [-] system = ICAES(inputs=inputs) # run single cycle and analyze system.single_cycle() results = system.analyze_performance() end = time.time() results['solve_time'] = end - start # combine inputs and results to return in single series single_output = pd.concat([sweep_input, results]) return single_output
from caes import ICAES, plot_series import matplotlib.pyplot as plt # create system inputs = ICAES.get_default_inputs() inputs['depth'] = 5550.0 system = ICAES(inputs=inputs) # system.debug_perf() # # # run single cycle and analyze system.single_cycle() results = system.analyze_performance() results.to_csv('single_cycle_performance.csv') system.data.to_csv('single_cycle_timeseries.csv') print(results) # # plot results system.plot_overview() system.plot_pressures() system.plot_pressure_losses()
class TestICAES(unittest.TestCase): def setUp(self): # calculate stage pressures cmp_p0 = 101.3 # kPa cmp_p2 = 10.0e3 # kPa cmp_p1 = (1.43 * cmp_p0 * cmp_p2)**0.5 # kPa exp_p0 = 7.0e3 # kPa exp_p2 = 101.3 # kPa exp_p1 = (1.43 * exp_p0 * exp_p2)**0.5 # kPa # test conditions T_atm_K = 293.15 T_atm_C = T_atm_K - 273.15 inputs = ICAES.get_default_inputs() inputs['p_atm'] = cmp_p0 # kPa inputs['T_atm'] = T_atm_C # C inputs['depth'] = 900.0 # [m] inputs['PR_type'] = 'fixed' # inputs['n_stages_cmp'] = 2 inputs['PR_cmp'] = [cmp_p1 / cmp_p0, cmp_p2 / cmp_p1] inputs['ML_cmp1'] = 1.0 * (1.65 / (cmp_p1 / 1000) - 0.05) inputs['ML_cmp2'] = 5.0 * (1.65 / (cmp_p2 / 1000) - 0.05) inputs['ML_cmp3'] = -1.0 # inputs['n_stages_exp'] = 2 inputs['PR_exp'] = [exp_p0 / exp_p1, exp_p1 / exp_p2] inputs['ML_exp1'] = 5.0 * (1.65 / (exp_p0 / 1000) - 0.05) inputs['ML_exp2'] = 1.0 * (1.65 / (exp_p1 / 1000) - 0.05) inputs['ML_exp3'] = -1.0 self.sys = ICAES(inputs=inputs) # overwrite calculated air and water properties self.sys.M = 29.0 self.sys.cp = 1.004 self.sys.gamma = 1.4 self.sys.c_water = 4.1816 self.sys.T_store_init = T_atm_K # [K] self.sys.T_store = T_atm_K # [K] self.sys.T2 = T_atm_K # [K] self.sys.T3 = T_atm_K # [K] self.sys.m_store = self.sys.m_store * 1.2 # increase amount of air to stay within pressure limits # solve two timesteps (index 0 = compression, index 1 = expansion) self.sys.update(m_dot=10.0, delta_t=2.0) self.sys.update(m_dot=-10.0, delta_t=1.0) self.sys.data.to_csv('test_perf.csv') # self.data.to_csv('single_cycle_timeseries.csv') # compresor tests def test_cmp_nLP(self): self.assertAlmostEqual(self.sys.data.loc[0, 'cmp_n0'], 1.046, places=3) def test_cmp_nHP(self): self.assertAlmostEqual(self.sys.data.loc[0, 'cmp_n1'], 1.092, places=3) def test_cmp_wLP(self): self.assertAlmostEqual(self.sys.data.loc[0, 'cmp_w_stg0'], -219.737, places=3) # expander tests def test_exp_nLP(self): self.assertAlmostEqual(self.sys.data.loc[1, 'exp_n1'], 1.039, places=3) def test_exp_nHP(self): self.assertAlmostEqual(self.sys.data.loc[1, 'exp_n0'], 1.062, places=3) def test_exp_wHP(self): self.assertAlmostEqual(self.sys.data.loc[1, 'exp_w_stg0'], 154.024, places=3)
savename = "sweep_soln_settings.png" # ------------------ # integer inputs # ------------------ ncpus = 3 # int(os.getenv('NUM_PROCS')) # ------------------ # numpy array inputs # ------------------ # investigated steps = np.array([ 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 8.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0, 750.0, 1000.0 ]) # number of solution time steps [-] # kept at default values p_mins = np.array([ICAES.get_default_inputs()['p_store_min'] ]) # minimum pressure [kPa] PRs = np.array([ ICAES.get_default_inputs()['p_store_max'] / ICAES.get_default_inputs()['p_store_min'] ]) # pressure ratio [-] eta_storages = np.array([ICAES.get_default_inputs()['eta_storage'] ]) # storage efficiency [fr] V_ress = np.array([ICAES.get_default_inputs()['V_res'] ]) # reservoir volume [m3] phis = np.array([ICAES.get_default_inputs()['phi']]) # porosity [-] Slrs = np.array([ICAES.get_default_inputs()['Slr'] ]) # liquid residual fraction [-] # ============== # run simulations
h = 62.44 # thickness [m] phi = 0.2292 # porosity k = 38.33 # permeability [mD] m_dot = 530.2402606 # mass flow rate [kg/s] r_f = 174.6289785 # formation radius [m] r_w = 0.41 / 2.0 # well radius [m] df = pd.DataFrame() for i in range(9): # get default inputs if i == 0: inputs = CAES.get_default_inputs() else: inputs = ICAES.get_default_inputs() # Common inputs inputs['depth'] = depth inputs['h'] = h inputs['phi'] = phi inputs['k'] = k inputs['r_f'] = r_f inputs['r_w'] = r_w inputs['m_dot'] = m_dot # options to include/exclude various loss mechanisms inputs['include_interstage_dp'] = False inputs['include_thermal_gradient'] = False inputs['include_air_leakage'] = False inputs['include_aquifer_dp'] = False
1.0e5, 5.0e5, 1.0e6, 5.0e6, 1.0e7, 5.0e7, 1.0e8, 5.0e8, 1.0e9, 5.0e9, ]) # reservoir volume [m3] PRs = np.arange(1.1, 2.1, 0.1) # pressure ratio [-] phis = np.array([1.0]) # porosity [-] Slrs = np.array([0.0]) # liquid residual fraction [-] # kept at default values steps = np.array([ICAES.get_default_inputs()['steps'] ]) # number of solution time steps [-] p_mins = np.array([ICAES.get_default_inputs()['p_store_min'] ]) # minimum pressure [kPa] eta_storages = np.array([ICAES.get_default_inputs()['eta_storage'] ]) # storage efficiency [fr] # ============== # run simulations # ============== # prepare dataframe to store inputs attributes = [ 'steps', 'p_min', 'PR', 'p_max', 'eta_storage', 'V_res', 'phi', 'Slr' ] sweep_inputs = pd.DataFrame(columns=attributes)
def parameter_sweep(sweep_input, debug=True): start = time.time() # convert inputs to model units kW_out = sweep_input['capacity_MW'] * 1e3 kWh_out = sweep_input['capacity_MW'] * sweep_input['duration_hr'] * 1e3 if debug: print('\nStarting sizing') print("kW_out (desired) : " + str(round(kW_out, 3))) print("kWh_out (desired) : " + str(round(kWh_out, 3))) print("\nDepth (m) : " + str(sweep_input['depth_m'])) print("Thickness (m) : " + str(sweep_input['thickness_m'])) print("Porosity (-) : " + str(sweep_input['porosity'])) print("Permeability (mD): " + str(sweep_input['permeability_mD'])) # allowable calculation error error = 1e-6 # maximum number of iterations count_max = 200 # initial guesses m_dot = 10.0 r_f = 10.0 # initial results kW_out_actual = 0.0 kWh_out_actual = 0.0 count = 0 while abs(kW_out_actual - kW_out) / kW_out + abs( kWh_out_actual - kWh_out) / kWh_out > error: if debug: print("\nIteration : " + str(count)) print("m_dot : " + str(round(m_dot, 3))) print("r_f : " + str(round(r_f, 3))) # create system inputs = ICAES.get_default_inputs() # user inputs inputs['depth'] = sweep_input['depth_m'] # porosity depth [m] inputs['h'] = sweep_input['thickness_m'] # porosity thickness [m] inputs['phi'] = sweep_input['porosity'] # formation porosity [-] inputs['k'] = sweep_input[ 'permeability_mD'] # formation permeability [mD] # current guess/iteration inputs['m_dot'] = m_dot # [kg/s] inputs['r_f'] = r_f # [m] system = ICAES(inputs=inputs) # run single cycle and analyze system.single_cycle() results = system.analyze_performance() # extract results of interest kW_out_actual = results['kW_out_avg'] kWh_out_actual = results['kWh_out'] # update guesses tau = 0.5 # solver time constant m_dot = m_dot * (1.0 + tau * (kW_out - kW_out_actual) / kW_out ) # m_dot linearly linked to kW r_f = r_f * (1.0 + tau**2 * (kWh_out - kWh_out_actual) / kWh_out_actual ) # r_f exponentially linked to kWh count = count + 1 if count > count_max: # sizing unsuccessful results['errors'] = True break if debug: print("MW_out_avg : " + str(round(kW_out_actual / 1e3, 3))) print("MWh_out : " + str(round(kWh_out_actual / 1e3, 3))) end = time.time() results['solve_time'] = end - start results['iterations'] = count results['m_dot'] = m_dot results['r_f'] = r_f # print out RTE print(results['RTE']) # combine inputs and results to return in single series single_output = pd.concat([sweep_input, results]) return single_output
phi = 0.2292 # porosity k = 38.33 # permeability [mD] m_dot = 200.0 # mass flow rate [kg/s] r_f = 100.0 # formation radius [m] r_w = 0.41 / 2.0 # well radius [m] depths = [1000.0, 2000.0, 3000.0, 4000.0, 5000.0] # depth [m] all_results = pd.DataFrame() # iterate through depths for depth in depths: # iterate through test cases for i in range(5): inputs = ICAES.get_default_inputs() inputs['depth'] = depth inputs['h'] = h inputs['phi'] = phi inputs['k'] = k inputs['r_f'] = r_f inputs['r_w'] = r_w inputs['m_dot'] = m_dot # =========================== # cases # =========================== if i == 0: casename = 'default' elif i == 1: # i == 1