@@ -88,7 +88,7 @@ class FFCaseCreation:
8888 def __init__ (self ,
8989 path ,
9090 wts ,
91- tmax_desired ,
91+ tmax ,
9292 zbot ,
9393 vhub ,
9494 shear ,
@@ -123,8 +123,9 @@ def __init__(self,
123123 Full path for the target case directory
124124 wts: dictionary
125125 Wind farm layout and turbine parameters in dictionary form
126- tmax_desired: scalar
127- Max desired simulation time given in seconds. OF toolbox makes small adjustments to ensure compatibility to dT
126+ tmax: scalar
127+ Max FAST.Farm simulation time given in seconds. Small adjustments for TurbSim
128+ simulations are made to ensure compatibility with both high- and low-res boxes
128129 vhub: list of scalars or single scalar
129130 Wind speeds at hub height to sweep on. Accepts a list or single value
130131 shear: list of scalars or single scalar
@@ -190,7 +191,7 @@ def __init__(self,
190191
191192 self .path = path
192193 self .wts = wts
193- self .tmax_desired = tmax_desired
194+ self .tmax = tmax
194195 self .zbot = zbot
195196 self .vhub = vhub
196197 self .shear = shear
@@ -325,9 +326,6 @@ def _checkInputs(self):
325326 self .fmax = self .wts [0 ]['fmax' ]
326327 self .Cmeander = self .wts [0 ]['Cmeander' ]
327328
328- if self .inflowType == 'TS' and self .dt_high == None :
329- self .dt_high = 1. / (2. * self .fmax )
330-
331329 # Check the platform heading and initialize as zero if needed
332330 if 'phi_deg' not in self .wts [0 ]: # check key for first turbine
333331 for i in self .wts :
@@ -374,7 +372,7 @@ def _checkInputs(self):
374372 if self .cmax <= 0 : raise ValueError ('cmax cannot be negative' )
375373 if self .fmax <= 0 : raise ValueError ('fmax cannot be negative' )
376374 if self .Cmeander <= 0 : raise ValueError ('Cmeander cannot be negative' )
377- if self .tmax_desired <= 0 : raise ValueError ('A positive tmax_desired should be requested' )
375+ if self .tmax <= 0 : raise ValueError ('A positive tmax should be requested' )
378376 if self .zbot <= 0 : raise ValueError ('zbot should be greater than 0 (recommended 1)' )
379377
380378 # Ensure quantities are list
@@ -414,7 +412,6 @@ def _checkInputs(self):
414412 raise ValueError (f'The extent of high boxes is not enough to cover the rotor diameter. ' \
415413 'The extent high is given as the total extent, and it needs to be greater than 1.' )
416414
417-
418415 # Check the FAST.Farm binary
419416 if self .ffbin is None :
420417 self .ffbin = shutil .which ('FAST.Farm' )
@@ -436,7 +433,6 @@ def _checkInputs(self):
436433 elif not os .path .isfile (self .tsbin ):
437434 raise ValueError (f'The TurbSim binary given does not exist.' )
438435
439-
440436 # Check turbine conditions arrays for consistency
441437 if len (self .inflow_deg ) != len (self .yaw_init ):
442438 raise ValueError (f'One row for each inflow angle should be given in yaw_init. ' \
@@ -499,30 +495,27 @@ def _checkInputs(self):
499495 else :
500496 raise ValueError (f"Inflow type `inflowType` should be 'TS' or 'LES'. Received { self .inflowType } ." )
501497
502-
503498 # Check the wake model (1:Polar; 2:Curl; 3:Cartesian)
504499 if self .mod_wake not in [1 ,2 ,3 ]:
505500 raise ValueError (f'Wake model `mod_wake` should be 1 (Polar), 2 (Curl), or 3 (Cartesian). Received { self .mod_wake } .' )
506501
507-
508502 # Check the ds and dt for the high- and low-res boxes. If not given, call the
509503 # AMR-Wind auxiliary function with dummy domain limits.
510- if None in (self .dt_high , self .ds_high , self .dt_low , self .ds_low ) and self . inflowType == 'LES' :
504+ if None in (self .dt_high , self .ds_high , self .dt_low , self .ds_low ):
511505 mod_wake_str = ['' ,'polar' , 'curled' , 'cartesian' ]
512506 print (f'WARNING: One or more temporal or spatial resolution for low- and high-res domains were not given.' )
513507 print (f' Estimated values for { mod_wake_str [self .mod_wake ]} wake model shown below.' )
514508 self ._determine_resolutions_from_dummy_amrwind_grid ()
515509
516- # Check the domain extents when values are provided by the user:
510+ # Check the temporal and spatial resolutions if provided
517511 if self .dt_low != None and self .dt_high != None :
518512 if self .dt_low % (self .dt_high - 1e-15 ) > 1e-12 :
519- raise ValueError (f'The temporal resolution dT_Low should be a multiple of dT_High' )
513+ raise ValueError (f'The temporal resolution dT_Low should be a multiple of dT_High. ' )
520514 if self .dt_low < self .dt_high :
521- raise ValueError (f'The temporal resolution dT_High should not be greater than dT_Low on the LES side ' )
515+ raise ValueError (f'The temporal resolution dT_High should not be greater than dT_Low. ' )
522516 if self .ds_low != None and self .ds_high != None :
523517 if self .ds_low < self .ds_high :
524- raise ValueError (f'The grid resolution dS_High should not be greater than dS_Low on the LES side' )
525-
518+ raise ValueError (f'The grid resolution dS_High should not be greater than dS_Low.' )
526519
527520 # Check the reference turbine for rotation
528521 if self .refTurb_rot >= self .nTurbines :
@@ -1663,19 +1656,19 @@ def TS_low_setup(self, writeFiles=True, runOnce=False):
16631656 # Create and write new Low.inp files creating the proper box with proper resolution
16641657 # By passing low_ext, manual mode for the domain size is activated, and by passing ds_low,
16651658 # manual mode for discretization (and further domain size) is also activated
1666- currentTS = TSCaseCreation (D_ , HubHt_ , Vhub_ , tivalue_ , shear_ , x = xlocs_ , y = ylocs_ , zbot = self .zbot , cmax = self . cmax ,
1667- fmax = self .fmax , Cmeander = self .Cmeander , boxType = boxType , low_ext = self .extent_low , ds_low = self . ds_low )
1668- self .TSlowbox = currentTS
1669-
1670- # Ensure that dt low is a multiple of dt high and that tmax is a multiple of both dt low and dt high, and that tmax is larger than tmax_desired
1671- currentTS . dt = getMultipleOf ( currentTS . dt , multipleof = self . dt_high )
1672- self . tmax = getMultipleOf ( self . tmax_desired , multipleof = currentTS . dt )
1673- if self . tmax < self . tmax_desired :
1674- self . tmax += currentTS . dt
1675-
1676- if runOnce :
1677- return
1678- currentTS . writeTSFile ( self . turbsimLowfilepath , currentTSLowFile , tmax = self . tmax , verbose = self . verbose )
1659+ self . TSlowbox = TSCaseCreation (D_ , HubHt_ , Vhub_ , tivalue_ , shear_ , x = xlocs_ , y = ylocs_ , zbot = self .zbot ,
1660+ cmax = self . cmax , fmax = self .fmax , Cmeander = self .Cmeander , boxType = 'lowres' , extent = self .extent_low ,
1661+ ds_low = self .ds_low , dt_low = self . dt_low , ds_high = self . ds_high , dt_high = self . dt_high )
1662+
1663+ if runOnce : return
1664+
1665+ # Write the actual TurbSim input file. Here we set the total simulation time to one time-step
1666+ # longer than the requested value. When executing the high-res boxes, sometimes the resulting
1667+ # flowfield is shorter than the requested total simulation time. So if we ask for the low-res
1668+ # with the exact length we want, the high-res boxes might be shorter than tmax. Note that the
1669+ # total FAST.Farm simulation time remains unmodified from what the user requested.
1670+ self . TSlowbox . writeTSFile ( self . turbsimLowfilepath , currentTSLowFile , tmax = self . tmax + self . dt_low , verbose = self . verbose )
1671+
16791672 # Modify some values and save file (some have already been set in the call above)
16801673 Lowinp = FASTInputFile (currentTSLowFile )
16811674 Lowinp ['RandSeed1' ] = self .seedValues [seed ]
@@ -1853,7 +1846,6 @@ def getDomainParameters(self):
18531846 def TS_high_get_time_series (self ):
18541847
18551848 # Loop on all conditions/seeds extracting time series from the Low box at turbines location
1856- boxType = 'highres'
18571849 for cond in range (self .nConditions ):
18581850 for seed in range (self .nSeeds ):
18591851 condSeedPath = os .path .join (self .path , self .condDirList [cond ], f'Seed_{ seed } ' )
@@ -1887,9 +1879,11 @@ def TS_high_get_time_series(self):
18871879 jMid , kMid = bts .iMid
18881880
18891881 # Get time series at the box center to get mean vhub and create time array.
1890- #Vhub = bts['u'][0,:,jTurb,kTurb]
18911882 Vmid = bts ['u' ][0 ,:,jMid ,kMid ]
18921883 time = bts .t
1884+
1885+ # Given the nature of how TS decides on the total time, let's get the actual tmax from the low-res
1886+ self .tmax_low = time [- 1 ]
18931887
18941888 # The time-series need to be shifted depending on the turbine location, so we need to find how many
18951889 # grid points (time steps) the data have convected. We use the mean streamwise component for that
@@ -1901,7 +1895,7 @@ def TS_high_get_time_series(self):
19011895 wvel = np .roll (bts ['u' ][2 , :, jTurb , kTurb ], start_time_step )
19021896
19031897 # Map it to high-res time and dt (both)
1904- time_hr = np .arange (bts . t [0 ], self . tmax + self .dt_high , self .dt_high )
1898+ time_hr = np .arange (time [0 ], time [ - 1 ] + self .dt_high , self .dt_high )
19051899 uvel_hr = np .interp (time_hr , time , uvel )
19061900 vvel_hr = np .interp (time_hr , time , vvel )
19071901 wvel_hr = np .interp (time_hr , time , wvel )
@@ -1946,7 +1940,6 @@ def TS_high_setup(self, writeFiles=True):
19461940 self .TS_high_get_time_series ()
19471941
19481942 # Loop on all conditions/cases/seeds setting up the High boxes
1949- boxType = 'highres'
19501943 highFilesName = []
19511944 for cond in range (self .nConditions ):
19521945 for case in range (self .nHighBoxCases ):
@@ -1977,13 +1970,15 @@ def TS_high_setup(self, writeFiles=True):
19771970
19781971 # Create and write new Low.inp files creating the proper box with proper resolution
19791972 currentTS = TSCaseCreation (D_ , HubHt_ , Vhub_ , tivalue_ , shear_ , x = xloc_ , y = yloc_ , zbot = self .zbot ,
1980- cmax = self .cmax , fmax = self .fmax , Cmeander = self .Cmeander , boxType = boxType , high_ext = self .extent_high )
1981- currentTS .writeTSFile (self .turbsimHighfilepath , currentTSHighFile , tmax = self .tmax , turb = t , verbose = self .verbose )
1973+ cmax = self .cmax , fmax = self .fmax , Cmeander = self .Cmeander , boxType = 'highres' , extent = self .extent_high ,
1974+ ds_low = self .ds_low , dt_low = self .dt_low , ds_high = self .ds_high , dt_high = self .dt_high )
1975+
1976+ currentTS .writeTSFile (self .turbsimHighfilepath , currentTSHighFile , tmax = self .tmax_low , turb = t , verbose = self .verbose )
19821977
19831978 # Modify some values and save file (some have already been set in the call above)
19841979 Highinp = FASTInputFile (currentTSHighFile )
19851980 Highinp ['RandSeed1' ] = self .seedValues [seed ]
1986- Highinp ['TimeStep' ] = 1. / (2. * self .fmax )
1981+ # Highinp['TimeStep'] = 1/(2*self.fmax)
19871982 Highinp ['TurbModel' ] = f'"TIMESR"'
19881983 Highinp ['UserFile' ] = f'"USRTimeSeries_T{ t + 1 } .txt"'
19891984 Highinp ['RefHt' ] = HubHt_
0 commit comments