• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

WISDEM / WEIS / 12283078613

11 Dec 2024 06:59PM UTC coverage: 78.249% (-0.6%) from 78.802%
12283078613

Pull #308

github

dzalkind
Merge remote-tracking branch 'origin/DLC_RefactorCaseInputs' into DLC_RefactorCaseInputs
Pull Request #308: DLC Generation - Refactor and New Cases

446 of 665 new or added lines in 9 files covered. (67.07%)

3 existing lines in 3 files now uncovered.

21416 of 27369 relevant lines covered (78.25%)

0.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.48
/weis/aeroelasticse/turbsim_util.py
1
import os
1✔
2
import shutil
1✔
3
import subprocess
1✔
4
from weis.aeroelasticse.IEC_CoeherentGusts import IEC_CoherentGusts
1✔
5

6
class TurbsimReader(object):
1✔
7

8
    def read_input_file(self, input_file_name):
1✔
9
        inpf = open(input_file_name, 'r')
1✔
10

11
        # Runtime Options
12
        inpf.readline()
1✔
13
        inpf.readline()
1✔
14
        inpf.readline()
1✔
15
        self.Echo = inpf.readline().split()[0]
1✔
16
        self.RandSeed1 = inpf.readline().split()[0]
1✔
17
        self.RandSeed2 = inpf.readline().split()[0]
1✔
18
        self.WrBHHTP = inpf.readline().split()[0]
1✔
19
        self.WrFHHTP = inpf.readline().split()[0]
1✔
20
        self.WrADHH = inpf.readline().split()[0]
1✔
21
        self.WrADFF = inpf.readline().split()[0]
1✔
22
        self.WrBLFF = inpf.readline().split()[0]
1✔
23
        self.WrADTWR = inpf.readline().split()[0]
1✔
24
        self.WrFMTFF = inpf.readline().split()[0]
1✔
25
        self.WrACT = inpf.readline().split()[0]
1✔
26
        self.Clockwise = inpf.readline().split()[0]
1✔
27
        self.ScaleIEC = inpf.readline().split()[0]
1✔
28

29
        # Turbine/Model Specifications
30
        inpf.readline()
1✔
31
        inpf.readline()
1✔
32
        self.NumGrid_Z = inpf.readline().split()[0]
1✔
33
        self.NumGrid_Y = inpf.readline().split()[0]
1✔
34
        self.TimeStep = inpf.readline().split()[0]
1✔
35
        self.AnalysisTime = inpf.readline().split()[0]
1✔
36
        self.UsableTime = inpf.readline().split()[0]
1✔
37
        self.HubHt = inpf.readline().split()[0]
1✔
38
        self.GridHeight = inpf.readline().split()[0]
1✔
39
        self.GridWidth = inpf.readline().split()[0]
1✔
40
        self.VFlowAng = inpf.readline().split()[0]
1✔
41
        self.HFlowAng = inpf.readline().split()[0]
1✔
42

43
        # Meteorological Boundary Conditions 
44
        inpf.readline()
1✔
45
        inpf.readline()
1✔
46
        self.TurbModel = inpf.readline().split()[0]
1✔
47
        self.UserFile = inpf.readline().split()[0].replace("'","").replace('"','')
1✔
48
        self.IECstandard = inpf.readline().split()[0]
1✔
49
        self.IECturbc = inpf.readline().split()[0]
1✔
50
        self.IEC_WindType = inpf.readline().split()[0]
1✔
51
        self.ETMc = inpf.readline().split()[0]
1✔
52
        self.WindProfileType = inpf.readline().split()[0]
1✔
53
        self.ProfileFile = inpf.readline().split()[0].replace("'","").replace('"','')
1✔
54
        self.RefHt = inpf.readline().split()[0]
1✔
55
        self.URef = inpf.readline().split()[0]
1✔
56
        self.ZJetMax = inpf.readline().split()[0]
1✔
57
        self.PLExp = inpf.readline().split()[0]
1✔
58
        self.Z0 = inpf.readline().split()[0]
1✔
59

60

61
        # Meteorological Boundary Conditions 
62
        inpf.readline()
1✔
63
        inpf.readline()
1✔
64
        self.Latitude = inpf.readline().split()[0]
1✔
65
        self.RICH_NO = inpf.readline().split()[0]
1✔
66
        self.UStar = inpf.readline().split()[0]
1✔
67
        self.ZI = inpf.readline().split()[0]
1✔
68
        self.PC_UW = inpf.readline().split()[0]
1✔
69
        self.PC_UV = inpf.readline().split()[0]
1✔
70
        self.PC_VW = inpf.readline().split()[0]
1✔
71

72
        # Spatial Coherence Parameters
73
        inpf.readline()
1✔
74
        inpf.readline()
1✔
75
        self.SCMod1 = inpf.readline().split()[0]
1✔
76
        self.SCMod2 = inpf.readline().split()[0]
1✔
77
        self.SCMod3 = inpf.readline().split()[0]
1✔
78
        self.InCDec1 = inpf.readline().split()[0]
1✔
79
        self.InCDec2 = inpf.readline().split()[0]
1✔
80
        self.InCDec3 = inpf.readline().split()[0]
1✔
81
        self.CohExp = inpf.readline().split()[0]
1✔
82

83
        # Spatial Coherence Parameters
84
        inpf.readline()
1✔
85
        inpf.readline()
1✔
86
        self.CTEventPath = inpf.readline().split()[0]
1✔
87
        self.CTEventFile = inpf.readline().split()[0]
1✔
88
        self.Randomize = inpf.readline().split()[0]
1✔
89
        self.DistScl = inpf.readline().split()[0]
1✔
90
        self.CTLy = inpf.readline().split()[0]
1✔
91
        self.CTLz = inpf.readline().split()[0]
1✔
92
        self.CTStartTime = inpf.readline().split()[0]
1✔
93

94

95
class TurbsimWriter(object):
1✔
96

97
    def __init__(self, turbsiminputs):
1✔
98

99
        self.turbsiminputs = turbsiminputs
1✔
100
        
101
    def execute(self, turbsim_input_file):
1✔
102

103
         tsinp = open(turbsim_input_file, 'w')
1✔
104
         tsinp.write("---------TurbSim v2.00.* Input File------------------------\n")
1✔
105
         tsinp.write(" Turbsim input file\n")
1✔
106
         tsinp.write("---------Runtime Options-----------------------------------\n")
1✔
107

108
         # runtime options
109
         tsinp.write('{!s:<12}   Echo            - Echo input data to <RootName>.ech (flag)\n'.format(self.turbsiminputs.Echo))
1✔
110
         tsinp.write('{!s:<12}   RandSeed1       - First random seed  (-2147483648 to 2147483647)\n'.format(int(self.turbsiminputs.RandSeed1)))
1✔
111
         tsinp.write('{!s:<12}   RandSeed2       - Second random seed (-2147483648 to 2147483647) for intrinsic pRNG, or an alternative pRNG: "RanLux" or "RNSNLW"\n'.format(self.turbsiminputs.RandSeed2))
1✔
112
         tsinp.write('{!s:<12}   WrBHHTP         - Output hub-height turbulence parameters in binary form?  (Generates RootName.bin)\n'.format(self.turbsiminputs.WrBHHTP))
1✔
113
         tsinp.write('{!s:<12}   WrFHHTP         - Output hub-height turbulence parameters in formatted form?  (Generates RootName.dat)\n'.format(self.turbsiminputs.WrFHHTP))
1✔
114
         tsinp.write('{!s:<12}   WrADHH          - Output hub-height time-series data in AeroDyn form?  (Generates RootName.hh)\n'.format(self.turbsiminputs.WrADHH))
1✔
115
         tsinp.write('{!s:<12}   WrADFF          - Output full-field time-series data in TurbSim/AeroDyn form? (Generates RootName.bts)\n'.format(self.turbsiminputs.WrADFF))
1✔
116
         tsinp.write('{!s:<12}   WrBLFF          - Output full-field time-series data in BLADED/AeroDyn form?  (Generates RootName.wnd)\n'.format(self.turbsiminputs.WrBLFF))
1✔
117
         tsinp.write('{!s:<12}   WrADTWR         - Output tower time-series data? (Generates RootName.twr)\n'.format(self.turbsiminputs.WrADTWR))
1✔
118
         tsinp.write('{!s:<12}   WrFMTFF         - Output full-field time-series data in formatted (readable) form?  (Generates RootName.u, RootName.v, RootName.w)\n'.format(self.turbsiminputs.WrFMTFF))
1✔
119
         tsinp.write('{!s:<12}   WrACT           - Output coherent turbulence time steps in AeroDyn form? (Generates RootName.cts)\n'.format(self.turbsiminputs.WrACT))
1✔
120
         tsinp.write('{!s:<12}   Clockwise       - Clockwise rotation looking downwind? (used only for full-field binary files - not necessary for AeroDyn)\n'.format(self.turbsiminputs.Clockwise))
1✔
121
         tsinp.write('{!s:<12}   ScaleIEC        - Scale IEC turbulence models to exact target standard deviation? [0=no additional scaling; 1=use hub scale uniformly; 2=use individual scales]\n'.format(self.turbsiminputs.ScaleIEC))
1✔
122

123
         # Turbine/Model Specifications
124
         tsinp.write("\n")
1✔
125
         tsinp.write("--------Turbine/Model Specifications-----------------------\n")
1✔
126
         tsinp.write('{!s:<12}   NumGrid_Z       - Vertical grid-point matrix dimension\n'.format(self.turbsiminputs.NumGrid_Z))
1✔
127
         tsinp.write('{!s:<12}   NumGrid_Y       - Horizontal grid-point matrix dimension\n'.format(self.turbsiminputs.NumGrid_Y))
1✔
128
         tsinp.write('{!s:<12}   TimeStep        - Time step [seconds]\n'.format(self.turbsiminputs.TimeStep))
1✔
129
         tsinp.write('{!s:<12}   AnalysisTime    - Length of analysis time series [seconds] (program will add time if necessary: AnalysisTime = MAX(AnalysisTime, UsableTime+GridWidth/MeanHHWS) )\n'.format(self.turbsiminputs.AnalysisTime))
1✔
130
         tsinp.write('{!s:<12}   UsableTime      - Usable length of output time series [seconds] (program will add GridWidth/MeanHHWS seconds unless UsableTime is "ALL")\n'.format(self.turbsiminputs.UsableTime))
1✔
131
         tsinp.write('{!s:<12}   HubHt           - Hub height [m] (should be > 0.5*GridHeight)\n'.format(self.turbsiminputs.HubHt))
1✔
132
         tsinp.write('{!s:<12}   GridHeight      - Grid height [m]\n'.format(self.turbsiminputs.GridHeight))
1✔
133
         tsinp.write('{!s:<12}   GridWidth       - Grid width [m] (should be >= 2*(RotorRadius+ShaftLength))\n'.format(self.turbsiminputs.GridWidth))
1✔
134
         tsinp.write('{!s:<12}   VFlowAng        - Vertical mean flow (uptilt) angle [degrees]\n'.format(self.turbsiminputs.VFlowAng))
1✔
135
         tsinp.write('{!s:<12}   HFlowAng        - Horizontal mean flow (skew) angle [degrees]\n'.format(self.turbsiminputs.HFlowAng))
1✔
136

137
         # Meteorological Boundary Conditions
138
         tsinp.write("\n")
1✔
139
         tsinp.write("--------Meteorological Boundary Conditions-------------------\n")
1✔
140
         tsinp.write('{!s:<12}   TurbModel       - Turbulence model ("IECKAI","IECVKM","GP_LLJ","NWTCUP","SMOOTH","WF_UPW","WF_07D","WF_14D","TIDAL","API","USRINP","TIMESR", or "NONE")\n'.format(self.turbsiminputs.TurbModel))
1✔
141
         tsinp.write('{!s:<12}   UserFile        - Name of the file that contains inputs for user-defined spectra or time series inputs (used only for "USRINP" and "TIMESR" models)\n'.format(self.turbsiminputs.UserFile))
1✔
142
         tsinp.write('{!s:<12}   IECstandard     - Number of IEC 61400-x standard (x=1,2, or 3 with optional 61400-1 edition number (i.e. "1-Ed2") )\n'.format(self.turbsiminputs.IECstandard))
1✔
143
         tsinp.write('{!s:<12}   IECturbc        - IEC turbulence characteristic ("A", "B", "C" or the turbulence intensity in percent) ("KHTEST" option with NWTCUP model, not used for other models)\n'.format(self.turbsiminputs.IECturbc))
1✔
144
         tsinp.write('{!s:<12}   IEC_WindType    - IEC turbulence type ("NTM"=normal, "xETM"=extreme turbulence, "xEWM1"=extreme 1-year wind, "xEWM50"=extreme 50-year wind, where x=wind turbine class 1, 2, or 3)\n'.format(self.turbsiminputs.IEC_WindType))
1✔
145
         tsinp.write('{!s:<12}   ETMc            - IEC Extreme Turbulence Model "c" parameter [m/s]\n'.format(self.turbsiminputs.ETMc))
1✔
146
         tsinp.write('{!s:<12}   WindProfileType - Velocity profile type ("LOG";"PL"=power law;"JET";"H2L"=Log law for TIDAL model;"API";"USR";"TS";"IEC"=PL on rotor disk, LOG elsewhere; or "default")\n'.format(self.turbsiminputs.WindProfileType))
1✔
147
         tsinp.write('{!s:<12}   ProfileFile     - Name of the file that contains input profiles for WindProfileType="USR" and/or TurbModel="USRVKM" [-]\n'.format(self.turbsiminputs.ProfileFile))
1✔
148
         tsinp.write('{!s:<12}   RefHt           - Height of the reference velocity (URef) [m]\n'.format(self.turbsiminputs.RefHt))
1✔
149
         tsinp.write('{!s:<12}   URef            - Mean (total) velocity at the reference height [m/s] (or "default" for JET velocity profile) [must be 1-hr mean for API model; otherwise is the mean over AnalysisTime seconds]\n'.format(self.turbsiminputs.URef))
1✔
150
         tsinp.write('{!s:<12}   ZJetMax         - Jet height [m] (used only for JET velocity profile, valid 70-490 m)\n'.format(self.turbsiminputs.ZJetMax))
1✔
151
         tsinp.write('{!s:<12}   PLExp           - Power law exponent [-] (or "default")\n'.format(self.turbsiminputs.PLExp))
1✔
152
         tsinp.write('{!s:<12}   Z0              - Surface roughness length [m] (or "default")\n'.format(self.turbsiminputs.Z0))
1✔
153

154
         # Non-IEC Meteorological Boundary Conditions
155
         tsinp.write("\n")
1✔
156
         tsinp.write("--------Non-IEC Meteorological Boundary Conditions------------\n")
1✔
157
         tsinp.write('{!s:<12}   Latitude        - Site latitude [degrees] (or "default")\n'.format(self.turbsiminputs.Latitude))
1✔
158
         tsinp.write('{!s:<12}   RICH_NO         - Gradient Richardson number [-]\n'.format(self.turbsiminputs.RICH_NO))
1✔
159
         tsinp.write('{!s:<12}   UStar           - Friction or shear velocity [m/s] (or "default")\n'.format(self.turbsiminputs.UStar))
1✔
160
         tsinp.write('{!s:<12}   ZI              - Mixing layer depth [m] (or "default")\n'.format(self.turbsiminputs.ZI))
1✔
161
         tsinp.write('{!s:<12}   PC_UW           - Hub mean uw Reynolds stress [m^2/s^2] (or "default" or "none")\n'.format(self.turbsiminputs.PC_UW))
1✔
162
         tsinp.write('{!s:<12}   PC_UV           - Hub mean uv Reynolds stress [m^2/s^2] (or "default" or "none")\n'.format(self.turbsiminputs.PC_UV))
1✔
163
         tsinp.write('{!s:<12}   PC_VW           - Hub mean vw Reynolds stress [m^2/s^2] (or "default" or "none")\n'.format(self.turbsiminputs.PC_VW))
1✔
164

165
         # Spatial Coherence Parameters
166
         tsinp.write('\n')
1✔
167
         tsinp.write(
1✔
168
             '--------Spatial Coherence Parameters----------------------------\n')
169
         tsinp.write('{!s:<12}   SCMod1           - u-component coherence model ("GENERAL", "IEC", "API", "NONE", or "default")\n'.format(
1✔
170
             self.turbsiminputs.SCMod1))
171
         tsinp.write('{!s:<12}   SCMod2           - v-component coherence model ("GENERAL", "IEC", "NONE", or "default")\n'.format(
1✔
172
             self.turbsiminputs.SCMod2))
173
         tsinp.write('{!s:<12}   SCMod3           - w-component coherence model ("GENERAL", "IEC", "NONE", or "default")\n'.format(
1✔
174
             self.turbsiminputs.SCMod3))
175
         if not type(self.turbsiminputs.InCDec1) is str:
1✔
176
            tsinp.write('{:<5.2f}  {:<5.2f}   InCDec1        - u-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
×
177
                float(self.turbsiminputs.InCDec1[0]), float(self.turbsiminputs.InCDec1[1])))
178
         else:
179
            tsinp.write('{!s:<12}   InCDec1        - u-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
1✔
180
                self.turbsiminputs.InCDec1))
181
         if not type(self.turbsiminputs.InCDec2) is str:
1✔
182
            tsinp.write('{:<5.2f}  {:<5.2f}   InCDec2        - v-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
×
183
                float(self.turbsiminputs.InCDec2[0]), float(self.turbsiminputs.InCDec2[1])))
184
         else:
185
            tsinp.write('{!s:<12}   InCDec2        - v-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
1✔
186
                self.turbsiminputs.InCDec2))
187
         if not type(self.turbsiminputs.InCDec3) is str:
1✔
188
            tsinp.write('{:<5.2f}  {:<5.2f}   InCDec3        - w-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
×
189
                float(self.turbsiminputs.InCDec3[0]), float(self.turbsiminputs.InCDec3[1])))
190
         else:
191
            tsinp.write('{!s:<12}   InCDec3        - w-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0  0.3e-3" in quotes) (or "default")\n'.format(
1✔
192
                self.turbsiminputs.InCDec3))
193
         tsinp.write('{!s:<12}   CohExp           - Coherence exponent for general model [-] (or "default")\n'.format(
1✔
194
             self.turbsiminputs.CohExp))
195

196
         # Coherent Turbulence Scaling Parameters
197
         tsinp.write('\n')
1✔
198
         tsinp.write('--------Coherent Turbulence Scaling Parameters-------------------\n')
1✔
199
         tsinp.write('{!s:<12}   CTEventPath     - Name of the path where event data files are located\n'.format(self.turbsiminputs.CTEventPath))
1✔
200
         tsinp.write('{!s:<12}   CTEventFile     - Type of event files ("LES", "DNS", or "RANDOM")\n'.format(self.turbsiminputs.CTEventFile))
1✔
201
         tsinp.write('{!s:<12}   Randomize       - Randomize the disturbance scale and locations? (true/false)\n'.format(self.turbsiminputs.Randomize))
1✔
202
         tsinp.write('{!s:<12}   DistScl         - Disturbance scale [-] (ratio of event dataset height to rotor disk). (Ignored when Randomize = true.)\n'.format(self.turbsiminputs.DistScl))
1✔
203
         tsinp.write('{!s:<12}   CTLy            - Fractional location of tower centerline from right [-] (looking downwind) to left side of the dataset. (Ignored when Randomize = true.)\n'.format(self.turbsiminputs.CTLy))
1✔
204
         tsinp.write('{!s:<12}   CTLz            - Fractional location of hub height from the bottom of the dataset. [-] (Ignored when Randomize = true.)\n'.format(self.turbsiminputs.CTLz))
1✔
205
         tsinp.write('{!s:<12}   CTStartTime     - Minimum start time for coherent structures in RootName.cts [seconds]\n'.format(self.turbsiminputs.CTStartTime))
1✔
206

207
         tsinp.close()
1✔
208

209

210
class Turbsim_wrapper(object):
1✔
211
    def __init__(self):
1✔
212
        self.turbsim_exe = 'turbsim'
1✔
213
        self.turbsim_input = ""
1✔
214
        self.run_dir = '.'
1✔
215

216
    def execute(self):
1✔
217
        exec_string = [self.turbsim_exe, self.turbsim_input]
1✔
218
        olddir = os.getcwd()
1✔
219
        os.chdir(self.run_dir)
1✔
220
        subprocess.call(exec_string)
1✔
221
        os.chdir(olddir)
1✔
222

223
def generate_wind_files(dlc_generator, FAST_namingOut, wind_directory, rotorD, hub_height, turbsim_exe, i_case):
1✔
224

225
    if dlc_generator.cases[i_case].turbulent_wind:
1✔
226
        # Write out turbsim input file
227
        turbsim_input_file_name = FAST_namingOut + '_' + dlc_generator.cases[i_case].IEC_WindType + (
1✔
228
                                '_U%1.6f'%dlc_generator.cases[i_case].URef +
229
                                '_Seed%1.1f'%dlc_generator.cases[i_case].RandSeed1) + '.in'
230
        turbsim_input_file_path = os.path.join(wind_directory, turbsim_input_file_name)
1✔
231
        wind_file_name = turbsim_input_file_path[:-3] + '.bts'
1✔
232

233

234
        runTS = True
1✔
235
        if os.path.exists(wind_file_name) and os.path.exists(turbsim_input_file_path):
1✔
236
            runTS = False
1✔
237
            ts_reader = TurbsimReader()
1✔
238
            ts_reader.read_input_file(turbsim_input_file_path)
1✔
239
            for key, value in ts_reader.__dict__.items():
1✔
240
                if isinstance(value, float):
1✔
241
                    if abs(value - dlc_generator.cases[i_case].__dict__[key]) > 1.e-6:
×
242
                        runTS = True
×
243
                        break
×
244
                else:
245
                    if str(value) != str(dlc_generator.cases[i_case].__dict__[key]):
1✔
246
                        runTS = True
×
247
                        break
×
248

249

250
        if runTS:
1✔
251
            ts_writer = TurbsimWriter(dlc_generator.cases[i_case])
1✔
252
            ts_writer.execute(turbsim_input_file_path)
1✔
253

254
            # Run TurbSim in sequence
255
            wrapper = Turbsim_wrapper()
1✔
256
            wrapper.run_dir = wind_directory
1✔
257
            #run_dir = os.path.dirname( os.path.dirname( os.path.dirname( os.path.realpath(__file__) ) ) ) + os.sep
258
            wrapper.turbsim_exe = turbsim_exe
1✔
259
            wrapper.turbsim_input = turbsim_input_file_name
1✔
260
            wrapper.execute()
1✔
261

262
        # Pass data to CaseGen_General to call OpenFAST
263
        wind_file_type = 3
1✔
264

265
    else:
266
        if dlc_generator.cases[i_case].label != '12.1':
×
267
            gusts = IEC_CoherentGusts()
×
268
            gusts.D = rotorD
×
269
            gusts.HH = hub_height
×
270
            gusts.dt = dlc_generator.cases[i_case].TimeStep
×
271
            gusts.TStart = dlc_generator.cases[i_case].transient_time + 10.  # start gust 10 seconds after OpenFAST starts recording
×
NEW
272
            gusts.TF = dlc_generator.cases[i_case].total_time
×
273
            gusts.Vert_Slope = dlc_generator.cases[i_case].VFlowAng
×
274
            wind_file_name = gusts.execute(wind_directory, FAST_namingOut, dlc_generator.cases[i_case])
×
275
            wind_file_type = 2
×
276
        else:
277
            wind_file_type = 1
×
278
            wind_file_name = 'unused'
×
279

280
    return wind_file_type, wind_file_name
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc