Advertisement
Guest User

tidal_simulation

a guest
Mar 26th, 2014
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.95 KB | None | 0 0
  1. """
  2. Power Generation Sim
  3.  
  4. Refactored version of previous simulation.
  5. """
  6. from mpl_toolkits.mplot3d import Axes3D
  7. import matplotlib
  8. from matplotlib import cm
  9. import matplotlib.pyplot as plt
  10. import pandas as pd
  11. import math as math
  12. import numpy as np
  13.  
  14. #function to find index of nearest value; used to find bay height
  15. #for a given volume
  16. def find_nearest(array,value):
  17.     idx = (np.abs(array-value)).argmin()
  18.     return idx
  19.  
  20. #function to calculate flow based on orifice and head
  21. def flow_calc(tide_h, bay_h, orifice_area):
  22.     if(tide_h > bay_h):
  23.         return abs((0.65 * math.sqrt(19.62 * (orifice_area ** 2) * (tide_h - bay_h))))
  24.     return abs((-0.65 * (math.sqrt(19.62 * (orifice_area ** 2) * (bay_h - tide_h)))))
  25.  
  26. #function to calculate instantaneous tide height
  27. def tide_height(time):
  28.     tidal_constants = [[0.131, 2.3621, 0.00438],[0.092, 6.1107, 0.00406],[1.390, 3.4478, 0.00843],[0.545, 4.0361, 0.00873]]
  29.     tide = 2.893
  30.     for element in tidal_constants:
  31.         tide += (element[0] * math.cos((element[2] * time) + element[1]))
  32.     return tide
  33.  
  34. #function to calculate efficiency of turbine based on given curve
  35. def efficiency_calc(flow_percent):
  36.     #values required for turbine calculations
  37.     eff_values = np.array([0.5, 0.73, 0.82, 0.88, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.86, 0.75, 0.5, 0.4])
  38.     flow_eff_values = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4])
  39.     return eff_values[find_nearest(flow_eff_values, flow_percent)]
  40.    
  41. #function to calculate instantaneous power of turbine using equation P = 1000*Q*H*\eta, turbine_on value is due to way the control logic works
  42. def inst_P(flow, head, efficiency, turbine_on, pumping = 0):
  43.     if(pumping):
  44.         return (1000.0 * flow * head * 9.81 * efficiency * turbine_on)
  45.     return abs(1000.0 * flow * head * 9.81 * efficiency * turbine_on)
  46.  
  47. #function to control sleiuces, turbines, returns 2-element array, first element is whether
  48. #turbine is on or off, second element is orifice size i.e. sluice or turbine inlet
  49. def ebb_logic(tide_height, cut_in, change, turbine_area):
  50.     #if tide is coming in, open sleuice gates
  51.     if (change > 0):
  52.         return [0, 10]
  53.     #if tide is going out but still beneath cut in height, close sluice
  54.     elif (change < 0 and (tide_height > cut_in)):
  55.         return [0, 0]
  56.     #otherwise open turbine gates, turbine on
  57.     else:
  58.         return [1, turbine_area]
  59.    
  60. def flood_logic(tide_height, cut_in, change, turbine_area):
  61.     #if tide going out, open sluice gates
  62.     if (change < 0):
  63.         return [0, 10]
  64.     #if tide coming in but less than cut in height, close sluice
  65.     elif (change > 0 and (tide_height < cut_in)):
  66.         return [0, 0]
  67.     #else open turbine gates, turbine on
  68.     else:
  69.         return [1, turbine_area]
  70.  
  71. def two_way_logic(tide_height, cut_in, change, turbine_area):
  72.     #if tide going our and head low, close gates
  73.     if ((change < 0) and (tide_height > cut_in)):
  74.         return [0, 0]
  75.     #if tide going out an below cut in value, turbine on
  76.     elif ((change < 0) and (tide_height < cut_in)):
  77.         return [1, turbine_area]
  78.     #if tide coming in but less that cut in, close gates
  79.     elif ((change > 0) and (tide_height < cut_in)):
  80.         return [0, 0]
  81.     #if tide coming in and above cut in value
  82.     else:
  83.         return [1, turbine_area]
  84.  
  85. #function to calculate total power generated in kWh for a given
  86. #rated flow and turbine size
  87. def power_value_total(tide_list, rated_flow, turbine_area, control_function):
  88.     #initial values
  89.     previous_tide = 0
  90.     previous_bay = 0
  91.     cut_in = 3.4
  92.     #local vars
  93.     bay_h = 0
  94.     bay_volume = 0
  95.     inst_P_list = []
  96.     for tide in tide_list:
  97.         #calculate gradient
  98.         grad = tide - previous_tide
  99.         #calculate orifice/turbine values
  100.         control_signal = control_function(tide, cut_in, grad, turbine_area)
  101.         turbine_on = control_signal[0]
  102.         orifice_area = control_signal[1]
  103.         #calculate flow rate
  104.         flow_rate = flow_calc(tide, previous_bay, orifice_area)
  105.         #add fluid to bay volume and find new bay height
  106.         bay_volume += (flow_rate * 60)
  107.         bay_h = (find_nearest(bay_vol_ref, bay_volume) / 100.0)
  108.    
  109.    
  110.         head = abs(tide - bay_h)
  111.    
  112.         flow_percent = abs(flow_rate/rated_flow)
  113.         efficiency = efficiency_calc(flow_percent)
  114.    
  115.         instantaneous_P = inst_P(flow_rate, head, efficiency, turbine_on)
  116.         inst_P_list.append(instantaneous_P)
  117.         previous_tide = tide
  118.         previous_bay = bay_h
  119.         total_energy = [power*60 for power in inst_P_list]
  120.    
  121.     return (sum(total_energy) / 3600000)
  122.  
  123. #function takes two arrays and brute forces the best configuration of flow/turbine sizes by calculating the total power output for all combinations, then returning the indices of the maximal optimal values - Note that this is a very inefficient method, with run times for a full month of data approaching 12 hours
  124. def optimisation(turbine_array, flow_array, control_logic):
  125.     #initialise C style array
  126.     power_array = np.empty([len(turbine_array),len(flow_array)])
  127.     #calculate power output for all values of turbine size and flow rate
  128.     for t_idx, turbine_area in enumerate(turbine_array):
  129.         for r_idx, rated_flow in enumerate(flow_array):
  130.             power_array[t_idx][r_idx] = power_value_total(tide_list, rated_flow, turbine_area, control_logic)
  131.     #find maximum power value stored in array      
  132.     max_power = np.amax(power_array)
  133.     #find index of maximum value
  134.     optimum_tup = np.unravel_index(power_array.argmax(), power_array.shape)
  135.     optimum_turbine = turbine_area_list[optimum_tup[0]]
  136.     optimum_flow = rated_flow_list[optimum_tup[1]]
  137.    
  138.    
  139.     return power_array, max_power, optimum_turbine, optimum_flow
  140.  
  141. #function to save a plot of power by turbine size and flow rate
  142. def surface_map(rated_flow_list, turbine_area_list, power_array, save_name, title_string):
  143.     rated_flow_list, turbine_area_list = np.meshgrid(rated_flow_list, turbine_area_list)
  144.     plot_title = 'Total Energy Generation By Turbine Size and Rated Flow: ' + title_string
  145.     fig = plt.figure()
  146.     ax = fig.add_subplot(111, projection='3d')
  147.     ax.plot_surface(rated_flow_list, turbine_area_list, power_array, rstride=1, cstride=1, cmap=cm.YlOrRd_r)
  148.     ax.set_xlabel(r'Rated Flow $(m^{3}s^{-1})$')
  149.     ax.set_ylabel(r'Turbine Swept Area $(m^2)$')
  150.     ax.set_zlabel(r'Total Energy Generated $(kWh)$')
  151.     plt.suptitle(plot_title)
  152.     plt.savefig(save_name)
  153.  
  154. #set parameters for simulation
  155. sim_length = 44000
  156. sim_time_division = 2  
  157. #time index for all calculations, calculate all tides
  158. time_values = np.arange(0, sim_length, sim_time_division)
  159. tide_list = [tide_height(time) for time in time_values]
  160.  
  161. #values for turbine swept area and turbine rating for optimisation
  162. #purposes
  163. rated_flow_list = [x for x in np.arange(1, 100, 1)]
  164. turbine_area_list = [x for x in np.arange(0.2, 20, 0.2)]
  165.  
  166. #import bay volume values and read trapeziodal as bay model
  167. bay_data_df = pd.read_csv('bay_volume_data')
  168. bay_vol_ref = bay_data_df['trapezoidal_bay']
  169.  
  170. #simulate total power generated for turbine sizes, flow rate and control logic
  171. ebb_power_gen, ebb_power_max, ebb_turbine, ebb_flow = optimisation(turbine_area_list, rated_flow_list, ebb_logic)
  172. flood_power_gen, flood_power_max, flood_turbine, flood_flow = optimisation(turbine_area_list, rated_flow_list, flood_logic)
  173. two_way_power_gen, two_way_power_max, two_way_turbine, two_way_flow = optimisation(turbine_area_list, rated_flow_list, two_way_logic)
  174.  
  175. #save surface map plots of previously calculated values
  176. surface_map(rated_flow_list, turbine_area_list, ebb_power_gen, 'ebb_power_optimisation.png', 'Ebb Generation')
  177. surface_map(rated_flow_list, turbine_area_list, flood_power_gen, 'flood_power_optimisation.png', 'Flood Generation')
  178. surface_map(rated_flow_list, turbine_area_list, two_way_power_gen, 'two_way_power_optimisation', 'Two Way Generation')
  179.  
  180. #formatted string for writing to file
  181. desc_string = 'power_total, optimal_turbine, optimal_flow\n'
  182. formatted_string = '%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f' % (ebb_power_max, ebb_turbine, ebb_flow, flood_power_max, flood_turbine, flood_flow, two_way_power_max, two_way_turbine, two_way_flow)
  183.  
  184. #write to and save file
  185. with open('optimisation_file.dat', 'w') as data_file:
  186.     data_file.write(desc_string)
  187.     data_file.write(formatted_string)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement