def Init_Turb(MannBox, WindFarm): video = False # -------------------------- # SIZE THE TURBULENT BOXES # ------------------------ # # sizing mann for the biggest wake? # Get the max wake radius to size correctly the Mann box, # (be careful if you don't use the 'simplification' described by Larsen, # you must manage the wake movement in addition of the wake radius to size the turbulent box. # (note: not yet implemented but we can also positionate rightly the turbulent Box to be close to the ground # and we could manage the ground effect on the meandering) # for the moment the wake movement doesn't need to take care of the ground (no need to implement reflecting surface) WindFarm.Rw_Max = get_Rw(x=WindFarm.nodim_lenght, R=1., TI=WindFarm.TI, CT=WindFarm.CT) print 'Rw max in WindFarm is: ', WindFarm.Rw_Max if MannBox.Box_Kind == 'Mann': MannBox = sizing_MannBox(MannBox, WindFarm) # put: , windFarm_lenght=0.) for the first function of Main loop print 'ly/2: ', MannBox.ly/2 print 'dt: ', MannBox.dt # -------------------------- # INITIALIZATION # --------------------------------- # print 'Total simulation time for the entire MannBox: ', MannBox.ti[-1] # 819,2s in total # ---- # Get the wake radius # ---- # MannBox.WakeRadius_for_this_Plan = 1. # the wake generating plan rotor radius = wake radius (we assumed) MannBox.Af = m.pi * (2 * MannBox.WakeRadius_for_this_Plan) ** 2 if MannBox.Keck_Transport_Velocity: MannBox.U=0.8 ################################################################################################ # Initialization if no 'Simplification' """ # ---- # Compute for the two component for the generating plan # ---- # # According to 'Wake Meandering: A Pragmatic Approach' (2008) by Larsen and co. # We deal just with v, w component for char in ['vfluct', 'wfluct']: MannBox.plan_of_interest = get_plan_of_interest(MannBox, ti=0, component_char=char) # ---- # Interpolation Part (WakeCentered) # ---- # Interpo_Integrate = interpo_integrate() Interpo_Integrate = Interpolate_plan(MannBox, Interpo_Integrate, Meand_Mann) # ---- # Integration Part # ---- # Interpo_Integrate = polar_mesh_value(MannBox, Interpo_Integrate) Final_Integral_Value = Trapz_for_Integrate_general_grid(Interpo_Integrate) # ---- # Calculate the characteristic velocity # ---- # Meand_Mann.init_vc_wc.append(Final_Integral_Value / MannBox.Af) # [vc, wc] #""" return MannBox, WindFarm
def run_sdwm(WD, WS, TI, WTcoord, WTG, HH, R, stab, accum): """ Main wrapper to the core flow field DWM model This function: 1) handles inputs arguments, 2) set up defaults values, 3) call the wind farm layout model, 4) create the wake tree by calling the expansion of the GCL model 5) main loop run for each turbine from most upstream to the most downstream in flow coordinate system Parameters ---------- WD: float WS: float TI: float WTcoord: float WTG: float HH: float R: float stab: str accum: str Returns ------- Farm_p_out: WT_p_out: Vel_out: Pos_out: WF: WT: aero: meta: mfor: ffor: DWM: deficits: inlets_ffor: inlets_ffor_deficits: inlets_ffor_turb: turb: out: ID_waked: """ ttt = time.time() # Load wind turbine and wind farm WT = wt.WindTurbine('Windturbine',current_dir+'/WT-data/'+WTG+'/'+WTG+'_PC.dat',HH,R) WF = wf.WindFarm('Windfarm', coordFile=WTcoord, WT=WT) print '***** sDWM v'+ __version__+' // WF: '+str(WF.nWT)+' WT(s) / WD '+str(WD)+'deg / WS '+str(WS)+' m/s / TI '+str(TI)+' / accumulation: '+accum+' ******************' # Scaling wind farm to NREL's rotor size if 'Lill' in WTcoord: WF.vectWTtoWT=WF.vectWTtoWT*(WT.R/46.5) # 46.5 is the Lillgrund nominal radius of SWT turbine # Compute distance WT to WT in mean flow coordinate system distFlowCoord, nDownstream, id0= WF.turbineDistance(WD) # Init dictionnaries deficits, turb, inlets_ffor, inlets_ffor_deficits,inlets_ffor_turb,out, DWM, ID_waked, ID_wake_adj, Farm_p_out, WT_p_out, Vel_out, Pos_out=init(WF) # Extreme wake to define WT's in each wake, including partial wakes. This is a call to GCL expansion model [12] ID_wake = {id0[i]:(get_Rw(x=distFlowCoord[0,id0[i],:], R = 2. * WF.WT.R, TI=TI, CT=WT.get_CT(WS), pars=[0.435449861,0.797853685,-0.124807893,0.136821858,15.6298,1.0])>\ np.abs(distFlowCoord[1,id0[i],:])).nonzero()[0] \ for i in range(WF.nWT)} ## Main DWM loop over turbines for iT in range(WF.nWT): print 'Simulating turbine '+ str(iT+1) +'/'+str(WF.nWT) # Define flow case geometry cWT = id0[iT] #Radial coordinates in cWT for wake affected WT's x=distFlowCoord[0,cWT,ID_wake[cWT]] C2C = distFlowCoord[1,cWT,ID_wake[cWT]] index_orig=np.argsort(x) x=np.sort(x) row= ID_wake[id0[iT]][index_orig] C2C=C2C[index_orig] # wind turbine positions Pos_out[iT,0] = ((WF.pos[0,cWT]-min(WF.pos[0,:]))/(2.*WF.WT.R))*(WT.R/46.5) Pos_out[iT,1] = ((WF.pos[1,cWT]-min(WF.pos[1,:]))/(2.*WF.WT.R))*(WT.R/46.5) # Wrapping the DWM core model with inputs par={ 'WS' : WS, # wind speed [m/s] 'TI' : TI, # turbulence intensity 'atmo_stab' : stab, # atmospheric stability VU, U ,NU, N, NS, S, VS 'WTG' : WTG, # wind turbine name 'WTG_spec' : WT, # class holding wind turbine specifications 'wtg_ind' : row, # turbine index 'hub_z' : x/(2*WF.WT.R), # set up location of downstream turbines in flow direction 'hub_x' : np.ceil((3*(max(abs(C2C))+WF.WT.R))/WF.WT.R)*0.5+C2C/(WF.WT.R), # set up lateral displacements of downstream turbines 'C2C' : C2C, # parse the "Center to Center" distance between hubs 'lx' : np.ceil((3.*(max(abs(C2C))+WF.WT.R))/WF.WT.R), # set up length of the domain in lateral coordinates in rotor diameter [D] 'ly' : np.ceil((3.*(max(abs(C2C))+WF.WT.R))/WF.WT.R), # set up length of the domain in longitudinal in rotor diameter [D] 'accu_inlet' : True, # specify whether inlet propagation is enabled (more accurate but slows down simulations), if disable, it behaves like HAWC2-DWM 'accu' : accum, # type of wake accumulation (linear, dominant [4] or quadratic) 'full_output': True # Flag for generating the complete output with velocity deficit scalars (larger memory foot print if enabled) } ID_wake_adj[str(id0[iT])]=row aero, meta, mfor, ffor, DWM, deficits,inlets_ffor,inlets_ffor_deficits, \ inlets_ffor_turb,turb, out,ID_waked = DWM_main_field_model(ID_waked,deficits,inlets_ffor,inlets_ffor_deficits, inlets_ffor_turb,turb,DWM,out,**par) # Total power Farm_p_out= Farm_p_out+out[str(meta.wtg_ind[0])][0] # based on BEM,# Farm_p_out= Farm_p_out+out[str(meta.wtg_ind[0])][4] # based on power curve # Power by each turbine WT_p_out[iT]=out[str(meta.wtg_ind[0])][0] Vel_out[iT]=out[str(meta.wtg_ind[0])][1] elapsedttt = time.time() - ttt print '***** sDWM v'+ __version__+' // Farm prod. is: %4.2f kW, %i WT(s) : %s -- in %4.2f sec *************' %(Farm_p_out,WF.nWT,np.array_str(WT_p_out),elapsedttt) return Farm_p_out,WT_p_out,Vel_out,Pos_out,WF,WT,aero, meta, mfor, ffor, DWM, deficits,inlets_ffor,inlets_ffor_deficits, inlets_ffor_turb,turb, out,ID_waked
def sDWM(argv): """ Main wrapper to the core flow field DWM model This function: 1) handles inputs arguments, 2) set up defaults values, 3) call the wind farm layout model, 4) create the wake tree by calling the expansion of the GCL model 5) main loop run for each turbine from most upstream to the most downstream in flow coordinate system """ # default run values WD = 120.0;WS = 9.0;TI = 0.06;WTcoord=current_dir+'/data/Lill_full.dat'; WTG='NREL5MW'; HH=90.0; R=63.0; stab='N'; accum='dominant' # Input arguments parser try: opts, args = getopt.getopt(argv,"hi:",["WD=","WS=","TI=","WTcoord=","WTG=","HH=","R=","stab=","accum="]) except getopt.GetoptError: print('RUN_sDWM.py -i <WD> <WS> <TI> <WT coord.> <WTG> <HH> <R> <Stab.> <accum.> <optim>') sys.exit(2) for opt, arg in opts: if opt == '-h': print('usage: RUN_sDWM.py -i <WD: deg, 0deg is the north> <WS: m/s> <TI: [-]> <WT coord. turbine coordinate file> <WTG name> <HH hub height: m> <R turbine radius: m> <stab: VS, S ... VU, U> <accum: linear, quadratic, dominant, ewma>') sys.exit() elif opt in ("-i"): WD = float(sys.argv[2]) WS = float(sys.argv[3]) TI = float(sys.argv[4]) WTcoord = str(sys.argv[5]) WTG = str(sys.argv[6]) HH= float(sys.argv[7]) R= float(sys.argv[8]) stab= str(sys.argv[9]) accum= sys.argv[10] ttt = time.time() # Load wind turbine and wind farm WT = wt.WindTurbine('Windturbine','../WT-data/'+WTG+'/'+WTG+'_PC.dat',HH,R) WF = wf.WindFarm('Windfarm',WTcoord,WT) print('***** sDWM v'+ __version__+' // WF: '+str(WF.nWT)+' WT(s) / WD '+str(WD)+'deg / WS '+str(WS)+' m/s / TI '+str(TI)+' / accumulation: '+accum+' ******************') # Scaling wind farm to NREL's rotor size if 'Lill' in WTcoord: WF.vectWTtoWT=WF.vectWTtoWT*(WT.R/46.5) # 46.5 is the Lillgrund nominal radius of SWT turbine # Compute distance WT to WT in mean flow coordinate system distFlowCoord, nDownstream, id0= WF.turbineDistance(WD) # Init dictionnaries deficits, turb, inlets_ffor, inlets_ffor_deficits,inlets_ffor_turb,out, DWM, ID_waked, ID_wake_adj, Farm_p_out, WT_p_out, Vel_out, Pos_out=init(WF) # Extreme wake to define WT's in each wake, including partial wakes. This is a call to GCL expansion model [12] ID_wake = {id0[i]:(get_Rw(x=distFlowCoord[0,id0[i],:],\ R=2.*WF.WT.R,TI=TI,CT=WT.get_CT(WS),pars=[0.435449861,0.797853685,-0.124807893,0.136821858,15.6298,1.0])>\ np.abs(distFlowCoord[1,id0[i],:])).nonzero()[0] \ for i in range(WF.nWT)} ## Main DWM loop over turbines for iT in range(WF.nWT): # Define flow case geometry cWT = id0[iT] #Radial coordinates in cWT for wake affected WT's x=distFlowCoord[0,cWT,ID_wake[cWT]] C2C = distFlowCoord[1,cWT,ID_wake[cWT]] print cWT index_orig=np.argsort(x) x=np.sort(x) row= ID_wake[id0[iT]][index_orig] C2C=C2C[index_orig] # wind turbine positions Pos_out[iT,0] = ((WF.pos[0,cWT]-min(WF.pos[0,:]))/(2.*WF.WT.R))*(WT.R/46.5) Pos_out[iT,1] = ((WF.pos[1,cWT]-min(WF.pos[1,:]))/(2.*WF.WT.R))*(WT.R/46.5) # Wrapping the DWM core model with inputs par={ 'WS' : WS, # wind speed [m/s] 'TI' : TI, # turbulence intensity 'atmo_stab' : stab, # atmospheric stability VU, U ,NU, N, NS, S, VS 'WTG' : WTG, # wind turbine name 'WTG_spec' : WT, # class holding wind turbine specifications 'wtg_ind' : row, # turbine index 'hub_z' : x/(2*WF.WT.R), # set up location of downstream turbines in flow direction 'hub_x' : np.ceil((2*(max(abs(C2C))+WF.WT.R))/WF.WT.R)*0.5+C2C/(WF.WT.R), # set up lateral displacements of downstream turbines 'C2C' : C2C, # parse the "Center to Center" distance between hubs 'lx' : np.ceil((2.*(max(abs(C2C))+WF.WT.R))/WF.WT.R), # set up length of the domain in lateral coordinates in rotor diameter [D] 'ly' : np.ceil((2.*(max(abs(C2C))+WF.WT.R))/WF.WT.R), # set up length of the domain in longitudinal in rotor diameter [D] 'accu_inlet' : False, # specify whether inlet propagation is enabled (more accurate but slows down simulations), if disable, it behaves like HAWC2-DWM 'accu' : accum, # type of wake accumulation (linear, dominant [4] or quadratic) 'full_output': False # Flag for generating the complete output with velocity deficit scalars (larger memory foot print if enabled) } ID_wake_adj[str(id0[iT])]=row aero, meta, mfor, ffor, DWM, deficits,inlets_ffor,inlets_ffor_deficits, \ inlets_ffor_turb,turb, out,ID_waked = DWM_main_field_model(ID_waked,deficits,inlets_ffor,inlets_ffor_deficits, inlets_ffor_turb,turb,DWM,out,**par) # Total power Farm_p_out= Farm_p_out+out[str(meta.wtg_ind[0])][0] # based on BEM,# Farm_p_out= Farm_p_out+out[str(meta.wtg_ind[0])][4] # based on power curve # Power by each turbine WT_p_out[iT]=out[str(meta.wtg_ind[0])][0] Vel_out[iT]=out[str(meta.wtg_ind[0])][1] elapsedttt = time.time() - ttt print('***** sDWM v'+ __version__+' // Farm prod. is: %4.2f kW, %i WT(s) : %s -- in %4.2f sec *************' %(Farm_p_out,WF.nWT,np.array_str(WT_p_out),elapsedttt)) return Farm_p_out,WT_p_out,Vel_out,Pos_out,WF,WT,aero, meta, mfor, ffor, DWM, deficits,inlets_ffor,inlets_ffor_deficits, inlets_ffor_turb,turb, out,ID_waked
def sDWM(derating, kwargs, xind): # ttt = time.time() # WD,WS,TI,WTcoord,WTG,HH,R,stab,accum,optim, WD = kwargs.get('WD') WS = kwargs.get('WS') TI = kwargs.get('TI') WTcoord = kwargs.get('WTcoord') WTG = kwargs.get('WTG') HH = kwargs.get('HH') R = kwargs.get('R') stab = kwargs.get('stab') accum = kwargs.get('accum') optim = to_bool(kwargs.get('optim')) dynamic = to_bool(kwargs.get('dynamic')) Meandering_turb_box_name = kwargs.get('Meandering_turb_box_name') WaT_turb_box_name = kwargs.get('WaT_turb_box_name') # WT = wt.WindTurbine('Vestas v80 2MW offshore','V80_2MW_offshore.dat',70,40) # WF = wf.WindFarm('Horns Rev 1','HR_coordinates.dat',WT) WT = wt.WindTurbine('Windturbine', '../WT-data/' + WTG + '/' + WTG + '_PC.dat', HH, R) WF = wf.WindFarm('Windfarm', WTcoord, WT) ######################################################################################################### if dynamic: if Meandering_turb_box_name != None: print '# ------------------------------------------------------------------------------------------------ #' print '# -------------------------- Pre Init for Meandering --------------------------------------------- #' if Meandering_turb_box_name[1] == 'Mann_Box': filename = Meandering_turb_box_name[ 0] # must come from sDWM Input #R_wt = 46.5 # can come from sDWM #WTG = 'NY2' # can come from sDWM #HH = 90. # Hub height # can come from sDWM Rw = 1. # try with no expansion WF.U_mean = WS WF.WT_R = WT.R WF.WT_Rw = Rw WF.TI = TI WT = wt.WindTurbine('Windturbine', '../WT-data/' + WTG + '/' + WTG + '_PC.dat', HH, WT.R) # already present in sDWM TurBox, WF = pre_init_turb(filename, WF, WT) elif Meandering_turb_box_name[1] == 'LES_Box': filename = Meandering_turb_box_name[ 0] # must come from sDWM Input # R_wt = 46.5 # can come from sDWM # WTG = 'NY2' # can come from sDWM # HH = 90. # Hub height # can come from sDWM Rw = 1. # try with no expansion WF.U_mean = WS WF.WT_R = WT.R WF.WT_Rw = Rw WF.TI = TI WT = wt.WindTurbine('Windturbine', '../WT-data/' + WTG + '/' + WTG + '_PC.dat', HH, WT.R) # already present in sDWM TurBox, WF = pre_init_turb_LES(filename, WF, WT) print '# -------------------------- End Pre Init for Meandering ----------------------------------------- #' print '# ------------------------------------------------------------------------------------------------ #' else: print '# -------------------------- Used Saved DATA for MEANDERING / No Meandering ---------------------- #' TurBox = ReadMannInput('1028') if WaT_turb_box_name != None: print '# ------------------------------------------------------------------------------------------------ #' print '# -------------------------- Pre Init for WaT ---------------------------------------------------- #' MannBox = pre_init_turb_WaT(WaT_turb_box_name) MannBox.R_ref = R print '# -------------------------- End Pre Init for WaT ------------------------------------------------ #' print '# ------------------------------------------------------------------------------------------------ #' else: MannBox = None print 'TI Input:', TI #TI = TurBox.TI print 'TI from TurbBox', TI #################################################################################################################### if optim is True: print 'Performing optimization' WT.CP = np.load('../WT-data/' + WTG + '/' + WTG + '_CP.npy') WT.CT = np.load('../WT-data/' + WTG + '/' + WTG + '_CT.npy') #print 'Cp and then Ct are :' #print WT.CP #print WT.CT WT.lambdaf3 = WT.CP[:, :, 0] WT.PITCH3 = WT.CP[:, :, 1] WT.CP3 = WT.CP[:, :, 2] WT.CT3 = WT.CT[:, :, 2] WT.CP3[WT.CP3 > (16. / 27.)] = 0 WT.CP3[np.isnan(WT.CP3)] = 0 WT.CT3[np.isnan(WT.CT3)] = 0 WT.CPc = cntr.Cntr(WT.PITCH3, WT.lambdaf3, WT.CP3) WT.CTc = cntr.Cntr(WT.PITCH3, WT.lambdaf3, WT.CT3) elif optim is False: print 'Not Performing optimization' derating = 1.0 * np.ones((WF.nWT)) WT.CP = None WT.CT = None # Scaling wind farm to NREL's rotor size if 'Lill' in WTcoord: WF.vectWTtoWT = WF.vectWTtoWT * ( WT.R / 46.5) # 46.5 is the Lillgrund nominal radius of SWT turbine #print WT.R/46.5: 1.0 #print 'WF.vectWTtoWT: ', WF.vectWTtoWT #raw_input('...') # Compute distance WT to WT in mean flow coordinate system distFlowCoord, nDownstream, id0 = WF.turbineDistance(WD) """ print 'distflowcoord', distFlowCoord print 'ndownstream', nDownstream print 'id0', id0 raw_input('...') #""" # Init dictionnaries deficits, turb, inlets_ffor, inlets_ffor_deficits, inlets_ffor_turb, out, DWM, ID_waked, ID_wake_adj, Farm_p_out, WT_p_out, Vel_out, WT_pitch_out, WT_RPM_out = init( WF) #raw_input('entry') # Extreme wake to define WT's in each wake, including partial wakes # but it doesn't keep Rw, however Rw is an important quantity used to model Meandering Dynamic! # I don't really understant what is following. (it comes from 2009 simple analytical wake model Glarsen) # it seems to show wich wake we need for each iteration? # To keep the thoughts of ewma I keep this part but I am not sure about this... # For this reason we have to know TI from the turbulent box before this step. ID_wake = {id0[i]:(get_Rw(x=distFlowCoord[0,id0[i],:], R=2*WF.WT.R,TI=TI,CT=WT.get_CT(WS),pars=[0.435449861,0.797853685,-0.124807893,0.136821858,15.6298,1.0])>\ np.abs(distFlowCoord[1,id0[i],:])).nonzero()[0] \ for i in range(WF.nWT)} #""" print 'ID_wake {id: id with a wake}: ' print ID_wake print ID_wake[1] print distFlowCoord # Power output list Farm_p_out = 0. WT_p_out = np.zeros((WF.nWT)) WT_pitch_out = np.zeros((WF.nWT, 2)) WT_RPM_out = np.zeros((WF.nWT, 2)) Vel_out = np.zeros((WF.nWT)) # COMPUTING TO PLOT """ POWER_TURBINE = [] VEL_plot=[] RPM_plot=[] PITCH_plot=[] #""" ## Main DWM loop over turbines FFOR_result = [] print '############################################################################################################' print '# -------------------------- # MAIN LOOP OVER TURBINE PROCESSING # --------------------------------------- #' for iT in range(WF.nWT): print '# -------------------------- # PROCESSING for iteration ' + str( iT) + ' # -------------------------------- #' # Define flow case geometry cWT = id0[iT] #Radial coordinates in cWT for wake affected WT's x = distFlowCoord[0, cWT, ID_wake[cWT]] C2C = distFlowCoord[1, cWT, ID_wake[cWT]] index_orig = np.argsort(x) x = np.sort(x) row = ID_wake[id0[iT]][index_orig] C2C = C2C[index_orig] # Wrapping the DWM core model with I/O par = { 'WS': WS, 'TI': TI, 'atmo_stab': stab, 'WTG': WTG, #'WTG':'NREL5MW', 'WTG_spec': WT, 'wtg_ind': row, # turbine index 'hub_z': x / ( 2 * WF.WT.R ), # compute the flow field at downstream location of each downwind turbine ! 'hub_x': np.ceil((2 * (max(abs(C2C)) + WF.WT.R)) / WF.WT.R) * 0.5 + C2C / ( WF.WT.R ), # lateral offset of each downwind turbine with respect to the most upstream turbine in the tree 'C2C': C2C, # center 2 center distances between hubs 'lx': np.ceil((2. * (max(abs(C2C)) + WF.WT.R)) / WF.WT.R), # length of the domain in lateral 'ly': np.ceil((2. * (max(abs(C2C)) + WF.WT.R)) / WF.WT.R), # length of the domain in longitudinal in D 'wake_ind_setting': 1, 'accu_inlet': True, 'derating': derating[row[0]], 'optim': optim, 'accu': accum, # type of wake accumulation 'full_output': False, # Flag for generating the complete output with velocity deficit 'iT': iT } ID_wake_adj[str(id0[iT])] = row print row #""" if dynamic: aero, meta, mfor, ffor, DWM, deficits, inlets_ffor, inlets_ffor_deficits, inlets_ffor_turb, turb, out, ID_waked = DWM_main_field_model_partly_dynamic( ID_waked, deficits, inlets_ffor, inlets_ffor_deficits, inlets_ffor_turb, turb, DWM, out, TurBox, WF, MannBox, **par) """ if meta.iT == 0: FFOR_result = ffor.WS_axial_ffor else: FFOR_result[:,:,meta.iT:,:] = FFOR_result[:,:,meta.iT:,:] + ffor.WS_axial_ffor #raw_input('....') if meta.MEANDERING_Total_plot: plt.ion() plt.figure('Meandering draw in time for each turbine in the wake') x = ffor.x_vec y = ffor.y_vec # X, Y = np.meshgrid(x, y) X, Y = ffor.x_mat, ffor.y_mat ref_rotor_x_emitting = (meta.hub_x[0] + np.cos(np.linspace(-pi, pi))) / 2. ref_rotor_y_emitting = (meta.hub_y + np.sin(np.linspace(-pi, pi))) / 2. for i_z in np.arange(0, 3): # for i_z in np.arange(0, meta.nz): ref_rotor_x_concerned = (meta.hub_x[i_z] + np.cos(np.linspace(-pi, pi))) / 2. ref_rotor_y_concerned = (meta.hub_y + np.sin(np.linspace(-pi, pi))) / 2. for i_t in np.arange(0, meta.nt, 2): plt.cla() plt.clf() print 'i_t = ', i_t if True: plt.subplot(121) CS1 = plt.contourf(X, Y, FFOR_result[:, :, i_z, i_t], np.linspace(0., 1., 20)) plt.xlabel('x'), plt.ylabel('y'), plt.title( 'Axial WS FFoR for Turbine ' + str(meta.wtg_ind[i_z])) # 7-iz plt.plot(ref_rotor_x_emitting, ref_rotor_y_emitting, 'r', label='WT emitting') plt.plot(ref_rotor_x_concerned, ref_rotor_y_concerned, 'k', label='WT concerned') plt.legend() plt.colorbar(CS1) plt.draw() plt.pause(0.0001) #""" else: aero, meta, mfor, ffor, DWM, deficits, inlets_ffor, inlets_ffor_deficits, inlets_ffor_turb, turb, out, ID_waked = DWM_main_field_model( ID_waked, deficits, inlets_ffor, inlets_ffor_deficits, inlets_ffor_turb, turb, DWM, out, **par) if meta.steadyBEM_AINSLIE: if meta.iT == 0: FFOR_result = ffor.WS_axial_ffor else: FFOR_result[:, :, meta. iT:, :] = FFOR_result[:, :, meta. iT:, :] + ffor.WS_axial_ffor # raw_input('....') if meta.MEANDERING_Total_plot: plt.ion() plt.figure( 'Meandering draw in time for each turbine in the wake') x = ffor.x_vec y = ffor.y_vec # X, Y = np.meshgrid(x, y) X, Y = ffor.x_mat, ffor.y_mat ref_rotor_x_emitting = (meta.hub_x[0] + np.cos(np.linspace(-pi, pi))) / 2. ref_rotor_y_emitting = (meta.hub_y + np.sin(np.linspace(-pi, pi))) / 2. for i_z in np.arange(0, 3): # for i_z in np.arange(0, meta.nz): ref_rotor_x_concerned = (meta.hub_x[i_z] + np.cos( np.linspace(-pi, pi))) / 2. ref_rotor_y_concerned = ( meta.hub_y + np.sin(np.linspace(-pi, pi))) / 2. for i_t in np.arange(0, meta.nt, 4): plt.cla() plt.clf() print 'i_t = ', i_t if True: plt.subplot(121) CS1 = plt.contourf( X, Y, FFOR_result[:, :, i_z, i_t] ) #, np.linspace(0., 1., 20)) plt.xlabel('x'), plt.ylabel('y'), plt.title( 'Axial WS FFoR for Turbine ' + str(meta.wtg_ind[i_z])) # 7-iz plt.plot(ref_rotor_x_emitting, ref_rotor_y_emitting, 'r', label='WT emitting') plt.plot(ref_rotor_x_concerned, ref_rotor_y_concerned, 'k', label='WT concerned') plt.legend() plt.colorbar(CS1) plt.draw() plt.pause(0.0001) plt.ioff() # Farm_p_out= Farm_p_out+out[str(meta.wtg_ind[0])][4] # based on power curve # /!\/!\ not put in commentary this /!\/!\ #""" # Total power Farm_p_out = Farm_p_out + out[str(meta.wtg_ind[0])][0] # based on BEM # Power by each turbine WT_p_out[iT] = out[str(meta.wtg_ind[0])][0] # Pitch and RPM """ WT_pitch_out[iT,0]=aero.PITCH WT_pitch_out[iT,1]=aero.PITCH_opt WT_RPM_out[iT,0]=aero.RPM WT_RPM_out[iT,1]=aero.RPM_opt #""" Vel_out[iT] = out[str(meta.wtg_ind[0])][1] #PLOTTING """ POWER_TURBINE=POWER_TURBINE+[out[str(meta.wtg_ind[0])][0]] VEL_plot=VEL_plot+[meta.mean_WS_DWM] RPM_plot=RPM_plot+[WT_RPM_out[iT,0]] PITCH_plot=PITCH_plot+[WT_pitch_out[iT,0]] #""" print '# -------------------------- # PROCESSING for iteration ' + str( iT) + ' ended # -------------------------- #' print '########################################################################################################' print '########################################################################################################' print '# -------------------------- # MAIN LOOP OVER TURBINE PROCESS ENDED # ------------------------------------ #' print '############################################################################################################' # # # print id0 # print 'xind', xind # print 'wtp', WT_p_out[id0] # print 'pitch', WT_pitch_out[id0] # print 'omega', WT_RPM_out[id0] # print 'vel', Vel_out[id0] # print 'xind', xind[id0] """ Main Results Plot""" """ plt.plot(range(WF.nWT),POWER_TURBINE) plt.title('Power Production for each Turbines'), plt.xlabel('Turbine Location'), plt.ylabel('Power (kW)') plt.show() plt.plot(range(WF.nWT), VEL_plot) plt.title('Velocity for each Turbines'), plt.xlabel('Turbine Location'), plt.ylabel('Velocity (m/s)') plt.show() plt.plot(range(WF.nWT), RPM_plot) plt.title('RPM for each Turbines'), plt.xlabel('Turbine Location'), plt.ylabel('RPM') plt.show() plt.plot(range(WF.nWT), PITCH_plot) plt.title('Pitch for each Turbines'), plt.xlabel('Turbine Location'), plt.ylabel('Pitch ()') plt.show() """ print 'The farm production is: %4.2f kW, where each turbine is: %s' % ( Farm_p_out, np.array_str(WT_p_out)) print 'Vel_out:', Vel_out return Farm_p_out, WT_p_out[id0], WT_pitch_out[id0], WT_RPM_out[ id0], Vel_out[id0], id0
def DWM_extract_meandering_from_TurbBox(MannBox, WindFarm): """ Notice: in Future Work we can add the fact that the Turbulence Box becomes slower through the windfarm :param filename: :param WindFarm: :param WT: :return: """ # WT location in the streamwise (come from meta.z_vec of Make Grid in sDWM): # [0 4 8 12 17 21 25 30] # ---- # For Test, this have to come from sDWM and so to be a parameter # ---- # WindFarm.stream_location_z = [2*ld for ld in WindFarm.stream_location_z] # [R] # reverse index location: originally the wind farm is index like this: 7 6 5 4 3 2 1 0 (upstream to downstream) WindFarm.stream_location_z = WindFarm.stream_location_z[::-1] WindFarm.stream_location_z = [abs(ld-max(WindFarm.stream_location_z)) for ld in WindFarm.stream_location_z] # : now 0 1 2 3 4 5 6 7 print 'WindFarm.stream_location_z ', WindFarm.stream_location_z #then [0, 4, 8, 12, 17, 21, 25] # then [0, 4, 8, 12, 17, 21] # then [0, 4, 8, 12, 17] # then [0, 4, 8, 12] etc... WindFarm.nodim_lenght = WindFarm.stream_location_z[-1] video = False # -------------------------------- # INITIALIZATION # ------------------------------------ # MannBox, WindFarm = Init_Turb(MannBox, WindFarm) # What Can we do for a not constant spacing # Not Implemented for now for the not crude approach #""" RW = {} LD = {} for Wake_index in range(len(WindFarm.stream_location_z)): ld_ref = WindFarm.stream_location_z[Wake_index] tho_ref = ld_ref / MannBox.U Ld = [abs(ld - ld_ref) for ld in WindFarm.stream_location_z[Wake_index:]] RW[Wake_index] = get_Rw(x=Ld, R=1., TI=MannBox.TI, CT=WindFarm.CT) LD[Wake_index] = Ld print RW print LD #raw_input('....') #""" # -------------- # Meandering Computation for each plan of interest # --------------------------- # # Ld is the list of the distance between generating plan and the plans of interest #Ld = WindFarm.stream_location_z # We are at a specified distance so we can get the wake radius at this distance # (doesn't change in time) # A simple stationary semi-analytical wake model Gunner C. Larsen (2009) Meand_Mann = meand_mann() if MannBox.CorrectionDelay: # We want to begin the simulation when the first plan go out of the WindFarm Box MannBox.delay = WindFarm.nodim_lenght / MannBox.U print 'delay is:', MannBox.delay # The data do not exceed the simulation time defined in class object (cMeand or cMann) T = [ti for ti in MannBox.ti[:] if ti < MannBox.SimulationTime] ############ OLD LOOP for Debug only ################### # This is a really crude approach of the algorithm to handle all the wake! So more computation time. if MannBox.loop_debug: start_time = time.time() WAKES = [] # list holding all wakes generated by each turbines for WT_index in range(len(WindFarm.stream_location_z)): # creates the list ld of interest # all the distances are calculate for reference WT, we delete WT upstream to the WT ref ld_ref = WindFarm.stream_location_z[WT_index] Ld = [abs(ld-ld_ref) for ld in WindFarm.stream_location_z[WT_index:]] # For each ld in Ld, we get a data matrix structured like this: column 1: time(s), column 2: yc, column 3: zc # we store these matrixs in a list along Ld Wake = [] tho_ref = ld_ref / MannBox.U for ld in Ld: print 'Ld: ', ld ts_vc_wc =[] # as x_b = U*tho, tho = x_b/U (here x_b = ld) tho_rel = ld / MannBox.U # time for the first wake release to reach the studied plan at ld # Get Wake radius function of the transportation time (seems at this distance) if MannBox.WakeExpansion: # ----# Get the wake radius #----# Rw = get_Rw(x=ld, R=1., TI=MannBox.TI, CT=WindFarm.CT) # resulted Rw is no dimensionalized MannBox.WakeRadius_for_this_Plan = Rw MannBox.Af = m.pi * (2 * MannBox.WakeRadius_for_this_Plan) ** 2 boolref = False for ts in T: if MannBox.CorrectionDelay: ts = ts + MannBox.delay if ld == 0.: vc_wc = [0., 0.] else: vc_wc = Wake_Dynamic_at_Ld(ld, ts - tho_ref-tho_rel, MannBox, Meand_Mann) #vc_wc = Wake_Dynamic_at_Ld(ld, ts, MannBox, Meand_Mann) ts_vc_wc.append([ts-MannBox.delay] + vc_wc) else: if ts - tho_ref-tho_rel< 0: ts_vc_wc.append([ts, np.nan, np.nan]) else: vc_wc = Wake_Dynamic_at_Ld(ld, ts - tho_ref-tho_rel, MannBox, Meand_Mann) if not boolref: boolref = True vc_wc_ref = vc_wc ts_vc_wc.append([ts]+vc_wc) ts_vc_wc = np.array(ts_vc_wc) ts_yc_zc = ts_vc_wc if not MannBox.CorrectionDelay: NaN_index = np.isnan(ts_yc_zc[:, 1]) ts_yc_zc[NaN_index, 1] = vc_wc_ref[0] ts_yc_zc[NaN_index, 2] = vc_wc_ref[1] ts_yc_zc[:, 1:3] = ld / MannBox.U * ts_yc_zc[:, 1:3] Wake.append(ts_yc_zc) WAKES.append(Wake) print 'Computation time for crude approach: ', time.time() - start_time ######NEW Loops # 2 kinds of loop possible: One wake can be use for every wake in the WF (big assumption) (Mannbox considered for one WT) # or multiple wake created as the first wake with wake expansion and constant WF CT (Mannbox considered for the entire WF) if not MannBox.loop_debug: ################################################################################################################ ################################################################################################################ if MannBox.multiplewake_build_on_first_wake: print '------------------------- MULTIPLE WAKE BUILD ON THE FIRST WAKE METHOD PROCESSING ------------------' if MannBox.SimulationTime != None: T_Mannbox = [ti for ti in MannBox.ti[:] if ti < MannBox.SimulationTime+MannBox.delay] else: T = [ti for ti in MannBox.ti[:] if ti < MannBox.ti[-1]- MannBox.delay] T_Mannbox = [ti for ti in MannBox.ti[:] if ti < MannBox.ti[-1]] # You should admit a constant spacing between turbines # ------------------------ # INTERPOLATION LOOP # -------------------------------------------------------- # print '------------------------- TURB BOX INTERPOLATION PROCESSING ----------------------------------------' tstart = time.time() Interpo_Integrate = interpo_integrate() Interpo_Integrate.F_tm_fvc_fwc = [] for t_M in T_Mannbox: tm_vc_wc = [] for char in ['vfluct', 'wfluct']: Meand_Mann.wake_center_location = (0, 0) # due to simplification MannBox.plan_of_interest = get_plan_of_interest(MannBox, ti=t_M, component_char=char) # ----# Interpolation Part (WakeCentered) #----# Interpo_Integrate = Interpolate_plan(MannBox, Interpo_Integrate, Meand_Mann) tm_vc_wc.append(Interpo_Integrate.f_cart) Interpo_Integrate.F_tm_fvc_fwc.append(tm_vc_wc) print 'computation time for interpo: ', time.time()- tstart print np.shape(Interpo_Integrate.F_tm_fvc_fwc) # --------------------- # INTREGRATION PROCESS FOR FirST WAKE # ------------------------------------- # print '------------------------- INTREGRATION FOR FirST WAKE PROCESSING -----------------------------------' start_time = time.time() # same spacing & same wake expansion behaviour for each wake, so we can calcutate just one wake to build the other WAKES = [] # list holding all wakes generated by each turbines #Computation for the first wake only. tho ref =0 Wake = [] tho_ref = 0 for ld in WindFarm.stream_location_z: print 'Ld: ', ld ts_vc_wc = [] # as x_b = U*tho, tho = x_b/U (here x_b = ld) tho_rel = ld / MannBox.U # time for the first wake release to reach the studied plan at ld # Get Wake radius function of the transportation time (seems at this distance) if MannBox.WakeExpansion: # ----# Get the wake radius #----# Rw = get_Rw(x=ld, R=1., TI=MannBox.TI, CT=WindFarm.CT) # resulted Rw is no dimensionalized MannBox.WakeRadius_for_this_Plan = Rw MannBox.Af = m.pi * (2 * MannBox.WakeRadius_for_this_Plan) ** 2 boolref = False for ts in T: # print 'ts: ', ts if MannBox.CorrectionDelay: ts = ts + MannBox.delay if ld == 0.: # and ld_ref!=WindFarm.stream_location_z[-1]: vc_wc = [0., 0.] else: vc_wc = Wake_Dynamic_at_Ld_optim(ts - tho_ref - tho_rel, MannBox, Meand_Mann, Interpo_Integrate) # vc_wc = Wake_Dynamic_at_Ld(ld, ts, MannBox, Meand_Mann) ts_vc_wc.append([ts - MannBox.delay] + vc_wc) else: if ts - tho_ref-tho_rel < 0: ts_vc_wc.append([ts, np.nan, np.nan]) else: vc_wc = Wake_Dynamic_at_Ld(ld, ts - tho_ref-tho_rel, MannBox, Meand_Mann) if not boolref: boolref = True vc_wc_ref = vc_wc ts_vc_wc.append([ts] + vc_wc) ts_vc_wc = np.array(list(ts_vc_wc)) if not MannBox.CorrectionDelay: NaN_index = np.isnan(ts_yc_zc[:, 1]) ts_yc_zc[NaN_index, 1] = vc_wc_ref[0] ts_yc_zc[NaN_index, 2] = vc_wc_ref[1] Wake.append(ts_vc_wc) WAKES.append(list(Wake)) print 'Computation time for integrate: ', time.time() - start_time # --------------------- # POST PROCESSING TO BUILD OTHER WAKEs # ------------------------------------- # print '------------------------- POST PROCESSING TO BUILD OTHER WAKEs -------------------------------------' # Built other wake with first one start_time = time.time() for WT_index in range(1, len(WindFarm.stream_location_z)): # creates the list ld of interest # all the distances are calculate for reference WT, we delete WT upstream to the WT ref ld_ref = WindFarm.stream_location_z[WT_index] Ld = np.array([abs(ld - ld_ref) for ld in WindFarm.stream_location_z[WT_index:]]) # For each ld in Ld, we get a data matrix structured like this: column 1: time(s), column 2: yc, column 3: zc # we store these matrixs in a list along Ld wake_to_add = copy.deepcopy(WAKES[0][WT_index:]) # ------------ # POST PROCESSING TO apply OTHER WAKEs ld/U from simplification # ----------------- # for i_ld in range(len(Ld)): ld = float(Ld[i_ld]) wake_to_add[i_ld][:][:, 1:3] = ld / WindFarm.U_mean * wake_to_add[i_ld][:][:, 1:3] WAKES.append(wake_to_add) # --------------------- # Post Processing apply ld/U to first wake # --------------------------------- # wake_to_change = copy.deepcopy(WAKES[0]) for i_ld in range(len(WindFarm.stream_location_z)): ld = float(WindFarm.stream_location_z[i_ld]) wake_to_change[i_ld][:][:, 1:3] = ld / MannBox.U * wake_to_change[i_ld][:][:, 1:3] WAKES[0] = wake_to_change print 'Computation time for Post Process: ', time.time()-start_time if not MannBox.multiplewake_build_on_first_wake: if MannBox.SimulationTime != None: T_Mannbox = [ti for ti in MannBox.ti[:] if ti < MannBox.SimulationTime+MannBox.delay] else: T = [ti for ti in MannBox.ti[:] if ti < MannBox.ti[-1]- MannBox.delay] T_Mannbox = [ti for ti in MannBox.ti[:] if ti < MannBox.ti[-1]] # ---------------------------- # INTERPOLATION LOOP # -------------------------------------------------------- # print '------------------------- TURB BOX INTERPOLATION PROCESSING ----------------------------------------' Interpo_Integrate = interpo_integrate() Interpo_Integrate.F_tm_fvc_fwc = [] tstart = time.time() for t_M in T_Mannbox: tm_vc_wc = [] for char in ['vfluct', 'wfluct']: Meand_Mann.wake_center_location = (0, 0) # due to simplification MannBox.plan_of_interest = get_plan_of_interest(MannBox, ti=t_M, component_char=char) # ----# Interpolation Part (WakeCentered) #----# Interpo_Integrate = Interpolate_plan(MannBox, Interpo_Integrate, Meand_Mann) tm_vc_wc.append(Interpo_Integrate.f_cart) Interpo_Integrate.F_tm_fvc_fwc.append(tm_vc_wc) print 'computation time for interpo: ', time.time() - tstart print np.shape(Interpo_Integrate.F_tm_fvc_fwc) # ---------------------------- # INTEGRATION LOOP # ---------------------------------------------------------- # print '------------------------- TURB BOX INTEGRATION PROCESSING ----------------------------------------' tstart = time.time() WAKES = [] for WAKE_id in range(len(WindFarm.stream_location_z)): Wake = [] for i_ld in range(len(LD[WAKE_id])): ld = LD[WAKE_id][i_ld] Rw = RW[WAKE_id][i_ld] MannBox.WakeRadius_for_this_Plan = Rw MannBox.Af = m.pi * (2 * MannBox.WakeRadius_for_this_Plan) ** 2 tho_ref = LD[0][WAKE_id]/MannBox.U print 'Ld: ', ld ts_vc_wc = [] # as x_b = U*tho, tho = x_b/U (here x_b = ld) tho_rel = ld / MannBox.U # time for the first wake release to reach the studied plan at ld # Get Wake radius function of the transportation time (seems at this distance) boolref = False for ts in T: if MannBox.CorrectionDelay: ts = ts + MannBox.delay #print 'ts: ', ts if ld == 0.: # and ld_ref!=WindFarm.stream_location_z[-1]: vc_wc = [0., 0.] else: #print 'tho_ref', tho_ref #print 'tho_rel', tho_rel vc_wc = Wake_Dynamic_at_Ld_optim(ts - tho_ref - tho_rel, MannBox, Meand_Mann, Interpo_Integrate) ts_vc_wc.append([ts - MannBox.delay] + vc_wc) else: if ts - tho_ref-tho_rel < 0: ts_vc_wc.append([ts, np.nan, np.nan]) else: vc_wc = Wake_Dynamic_at_Ld(ld, ts - tho_ref-tho_rel, MannBox, Meand_Mann) if not boolref: boolref = True vc_wc_ref = vc_wc ts_vc_wc.append([ts] + vc_wc) #print 'tsvcwc shape: ',np.shape(ts_vc_wc) ts_vc_wc = np.array(ts_vc_wc) ts_yc_zc = ts_vc_wc if not MannBox.CorrectionDelay: NaN_index = np.isnan(ts_yc_zc[:, 1]) ts_yc_zc[NaN_index, 1] = vc_wc_ref[0] ts_yc_zc[NaN_index, 2] = vc_wc_ref[1] ts_yc_zc[:, 1:3] = ld / MannBox.U * ts_yc_zc[:, 1:3] Wake.append(ts_vc_wc) WAKES.append(Wake) print np.shape(WAKES) print 'Computation time to integrate: ', time.time() - tstart #raw_input('....') # Not Implemented ####NEW LOOP FOR FAST RESULT BASED ON WAKE EXPANSION #Plot Part # Plot each Wake if MannBox.RESULT_plot: Plot_each_Wake(WAKES, WindFarm) Plot_Wakes_at_each_ld(WAKES, WindFarm) #Plot_Wakes_at_each_ld_in_MannBox_referential(WAKES, WindFarm, MannBox) DATA = WAKES np.save('WAKES',DATA) print 'Wake Radius Data saved...' return WAKES