Skip to content
This repository was archived by the owner on Nov 27, 2023. It is now read-only.

Commit 5b836be

Browse files
committed
IO/Postpro/tools: updates from welib
1 parent cd94e85 commit 5b836be

File tree

105 files changed

+11354
-494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+11354
-494
lines changed

pyFAST/airfoils/DynamicStall.py

+506
Large diffs are not rendered by default.

pyFAST/airfoils/Polar.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class Polar(object):
4242
"""
4343

4444
def __init__(self, filename=None, alpha=None, cl=None, cd=None, cm=None, Re=None,
45-
compute_params=False, radians=None, fformat='auto', verbose=False):
45+
compute_params=False, radians=None, cl_lin_method='max',
46+
fformat='auto', verbose=False):
4647
"""Constructor
4748
4849
Parameters
@@ -118,9 +119,9 @@ def __init__(self, filename=None, alpha=None, cl=None, cd=None, cm=None, Re=None
118119

119120
# NOTE: method needs to be in harmony for linear_slope and the one used in cl_fully_separated
120121
if compute_params:
121-
self._linear_slope, self._alpha0 = self.cl_linear_slope(method="max")
122+
self._linear_slope, self._alpha0 = self.cl_linear_slope(method=cl_lin_method)
122123
if not self._cl_fs_lock:
123-
self.cl_fully_separated()
124+
self.cl_fully_separated(method=cl_lin_method)
124125
if not self._cl_inv_lock:
125126
self.cl_inv = self._linear_slope * (self.alpha - self._alpha0)
126127

@@ -136,6 +137,9 @@ def __repr__(self):
136137
s+=' - _alpha0: {} [{}]\n'.format(self._alpha0, sunit)
137138
s+=' - _linear_slope: {} [1/{}]\n'.format(self._linear_slope, sunit)
138139
s+='Derived parameters:\n'
140+
s+=' * cl_inv : array of size {} \n'.format(len(self.alpha))
141+
s+=' * cl_fs : array of size {} \n'.format(len(self.alpha))
142+
s+=' * fs : array of size {} \n'.format(len(self.alpha))
139143
s+=' * cl_lin (UNSURE) : array of size {} \n'.format(len(self.alpha))
140144
s+='Functional parameters:\n'
141145
s+=' * alpha0 : {} [{}]\n'.format(self.alpha0(),sunit)
@@ -280,10 +284,6 @@ def cl_lin(self): # TODO consider removing
280284
# self._linear_slope,self._alpha0=self.cl_linear_slope()
281285
#return self._linear_slope*(self.alpha-self._alpha0)
282286

283-
284-
285-
286-
287287
@classmethod
288288
def fromfile(cls, filename, fformat='auto', compute_params=False, to_radians=False):
289289
"""Constructor based on a filename
@@ -1058,6 +1058,7 @@ def cl_fully_separated(self, method='max'):
10581058
if not self._fs_lock:
10591059
fs = (self.cl - cl_fs) / (cl_inv - cl_fs + 1e-10)
10601060
fs[np.where(fs < 1e-15)] = 0
1061+
fs[np.where(fs > 1)] = 1
10611062
# Storing
10621063
self.fs = fs
10631064
self.cl_fs = cl_fs
@@ -1534,6 +1535,7 @@ def cl_linear_slope(alpha, cl, window=None, method="max", nInterp=721, inputInRa
15341535
- alpha: angle of attack in radians
15351536
- Cl : lift coefficient
15361537
- window: [alpha_min, alpha_max]: region when linear slope is sought
1538+
- method: 'max', 'optim', 'leastsquare', 'leastsquare_constraint'
15371539
15381540
OUTPUTS:
15391541
- Cl_alpha, alpha0: lift slope (1/rad) and angle of attack (rad) of zero lift

pyFAST/airfoils/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .Polar import *
2+
from .DynamicStall import *

pyFAST/airfoils/examples/correction3D.py

+20-14
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,33 @@
1111
def main_correction3D(test=False):
1212
polarFile_in = os.path.join(MyDir,'../data/DU21_A17.csv')
1313

14-
r_over_R = 0.2
15-
chord_over_r = 3./5.
16-
tsr = 10
14+
r_over_R = 0.2 # spanwise location [-]
15+
chord_over_r = 3./5. # chord divided by local radius [-]
16+
tsr = 10 # tip speed ratio [-]
1717

1818
polar = Polar(polarFile_in, compute_params=True, verbose=False)
19-
#ADpol = polar.toAeroDyn(polarFile_AD)
19+
#ADpol = polar.toAeroDyn(polarFile_AD) # Optional, write to AeroDyn format
2020
polar3D= polar.correction3D(r_over_R, chord_over_r, tsr)
2121

22+
# --- Plot
23+
fig,ax = plt.subplots(1, 1, sharey=False, figsize=(6.4,4.8)) # (6.4,4.8)
24+
fig.subplots_adjust(left=0.12, right=0.95, top=0.95, bottom=0.11, hspace=0.20, wspace=0.20)
25+
ax.plot(polar.alpha, polar.cl ,'k-' , label= r'2D polar')
26+
ax.plot(polar3D.alpha, polar3D.cl , '-' , label= r'3D corrected')
27+
ax.plot(polar.alpha, polar.cl_inv ,'k--' , label= r'inviscid')
28+
ax.tick_params(direction='in', top=True, right=True)
29+
ax.set_xlabel(r'Angle of attack, $\alpha$ [deg]')
30+
ax.set_ylabel(r'Lift coefficient, $C_l$ [-]')
31+
ax.set_title(r'Airfoils - 3D correction')
32+
ax.set_xlim([-50,50])
33+
ax.set_ylim([-1.5,2])
34+
ax.legend()
35+
2236
return polar, polar3D
2337

38+
polar,polar3D = main_correction3D()
2439

2540
if __name__ == '__main__':
26-
polar,polar3D = main_correction3D()
27-
28-
import matplotlib.pyplot as plt
29-
plt.plot(polar.alpha, polar.cl , label= 'cl')
30-
plt.plot(polar3D.alpha, polar3D.cl , label= 'cl 3d')
31-
plt.plot(polar.alpha, polar.cl_inv , label= 'cl inv')
32-
plt.ylim([-1.5,2])
33-
plt.legend()
3441
plt.show()
35-
3642
if __name__ == '__test__':
37-
polar,polar3D = main_correction3D()
43+
pass

pyFAST/case_generation/case_gen.py

+20-20
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import pyFAST.input_output.fast_input_file as fi
1212
import pyFAST.case_generation.runner as runner
1313
import pyFAST.input_output.postpro as postpro
14-
from pyFAST.input_output.fast_wind_file import FASTWndFile
15-
from pyFAST.input_output.rosco_performance_file import ROSCOPerformanceFile
16-
from pyFAST.input_output.csv_file import CSVFile
17-
14+
from pyFAST.input_output.fast_wind_file import FASTWndFilefrom pyFAST.input_output.rosco_performance_file import ROSCOPerformanceFilefrom pyFAST.input_output.csv_file import CSVFile
1815
# --------------------------------------------------------------------------------}
1916
# --- Template replace
2017
# --------------------------------------------------------------------------------{
@@ -150,11 +147,7 @@ def replaceRecurse(templatename_or_newname, FileKey, ParamKey, ParamValue, Files
150147
ext = os.path.splitext(templatefilename)[-1]
151148
newfilename_full = os.path.join(wd,strID+ext)
152149
newfilename = strID+ext
153-
if dryRun:
154-
newfilename = os.path.join(workDir, newfilename)
155-
obj=type('DummyClass', (object,), {'filename':newfilename})
156-
return newfilename, {'Root':obj}
157-
else:
150+
if dryRun: newfilename = os.path.join(workDir, newfilename) obj=type('DummyClass', (object,), {'filename':newfilename}) return newfilename, {'Root':obj} else:
158151
newfilename, newfilename_full = rebaseFileName(templatefilename, workDir, strID)
159152
#print('--------------------------------------------------------------')
160153
#print('TemplateFile :', templatefilename)
@@ -172,8 +165,12 @@ def replaceRecurse(templatename_or_newname, FileKey, ParamKey, ParamValue, Files
172165
Key = NewFileKey_or_Key
173166
#print('Setting', FileKey, '|',Key, 'to',ParamValue)
174167
if Key=='OutList':
175-
OutList=f[Key]
176-
f[Key] = addToOutlist(OutList, ParamValue)
168+
if len(ParamValue)>0:
169+
if len(ParamValue[0])==0:
170+
f[Key] = ParamValue # We replace
171+
else:
172+
OutList=f[Key]
173+
f[Key] = addToOutlist(OutList, ParamValue) # we insert
177174
else:
178175
f[Key] = ParamValue
179176
else:
@@ -229,14 +226,21 @@ def replaceRecurse(templatename_or_newname, FileKey, ParamKey, ParamValue, Files
229226
removeFASTOuputs(wd)
230227
if os.path.exists(wd) and removeAllowed:
231228
shutil.rmtree(wd, ignore_errors=False, onerror=handleRemoveReadonlyWin)
232-
copyTree(templateDir, wd)
233-
if removeAllowed:
234-
removeFASTOuputs(wd)
229+
templateDir = os.path.normpath(templateDir)
230+
wd = os.path.normpath(wd)
231+
# NOTE: need some special handling if path are the sames
232+
if templateDir!=wd:
233+
copyTree(templateDir, wd)
234+
if removeAllowed:
235+
removeFASTOuputs(wd)
235236

236237

237238
TemplateFiles=[]
238239
files=[]
240+
nTot=len(PARAMS)
239241
for ip,(wd,p) in enumerate(zip(workDirS,PARAMS)):
242+
if np.mod(ip+1,1000)==0:
243+
print('File {:d}/{:d}'.format(ip,nTot))
240244
if '__index__' not in p.keys():
241245
p['__index__']=ip
242246

@@ -248,16 +252,12 @@ def replaceRecurse(templatename_or_newname, FileKey, ParamKey, ParamValue, Files
248252
if k =='__index__' or k=='__name__':
249253
continue
250254
new_mainFile, Files = replaceRecurse(main_file_base, '', k, v, Files, strID, wd, TemplateFiles)
251-
if dryRun:
252-
break
253-
255+
if dryRun: break
254256
# --- Writting files
255257
for k,f in Files.items():
256258
if k=='Root':
257259
files.append(f.filename)
258-
if not dryRun:
259-
f.write()
260-
260+
if not dryRun: f.write()
261261
# --- Remove extra files at the end
262262
if removeRefSubFiles:
263263
TemplateFiles, nCounts = np.unique(TemplateFiles, return_counts=True)

pyFAST/case_generation/runner.py

+71-5
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,40 @@ def run_fast(input_file, fastExe=None, wait=True, showOutputs=False, showCommand
195195
return run_cmd(input_file, fastExe, wait=wait, showOutputs=showOutputs, showCommand=showCommand)
196196

197197

198-
def writeBatch(batchfile, fastfiles, fastExe=None, nBatches=1, pause=False, flags='', flags_after=''):
199-
""" Write batch file, everything is written relative to the batch file"""
198+
def writeBatch(batchfile, fastfiles, fastExe=None, nBatches=1, pause=False, flags='', flags_after='',
199+
run_if_ext_missing=None,
200+
discard_if_ext_present=None,
201+
dispatch=False,
202+
stdOutToFile=False,
203+
echo=True):
204+
""" Write one or several batch file, all paths are written relative to the batch file directory.
205+
The batch file will consist of lines of the form:
206+
[CONDITION] EXE [FLAGS] FILENAME [FLAGS_AFTER]
207+
208+
INPUTS:
209+
- batchfile: path of the batch file to be written.
210+
If several files are requested (using nBatches) _i is inserted before the extension
211+
- nBatches: split into nBatches files.
212+
- pause: insert a pause statement at the end so that batch file is not closed after execution
213+
- flags: flags (string) to be placed between the executable and the filename
214+
- flags_after: flags (string) to be placed after the filename
215+
- run_if_ext_missing: add a line in the batch file so that the command is only run if
216+
the file `f.EXT` is missing, where .EXT is specified in run_if_ext_missing
217+
If None, the command is always run
218+
- discard_if_ext_present: similar to run_if_ext_missing, but this time, the lines are not written to the batch file
219+
The test for existing outputs is done before writing the batch file
220+
- dispatch: if True, the input files are dispatched (the first nBatches files are dispathced on the nBatches)
221+
- stdOutToFile: if True, the output of the command is redirected to filename.stdout
222+
223+
example:
224+
writeBatch('dir/MyBatch.bat', ['dir/c1.fst','dir/c2.fst'], 'op.exe', flags='-v', run_if_ext_missing='.outb')
225+
226+
will generate a file with the following content:
227+
if not exist c1.outb (../of.exe c1.fst) else (echo "Skipping c1.fst")
228+
if not exist c2.outb (../of.exe c2.fst) else (echo "Skipping c2.fst")
229+
230+
231+
"""
200232
if fastExe is None:
201233
fastExe=FAST_EXE
202234
fastExe_abs = os.path.abspath(fastExe)
@@ -207,20 +239,54 @@ def writeBatch(batchfile, fastfiles, fastExe=None, nBatches=1, pause=False, flag
207239
flags=' '+flags
208240
if len(flags_after)>0:
209241
flags_after=' '+flags_after
242+
243+
# Remove commandlines if outputs are already present
244+
if discard_if_ext_present:
245+
outfiles = [os.path.splitext(f)[0] + discard_if_ext_present for f in fastfiles]
246+
nIn=len(fastfiles)
247+
fastfiles =[f for f,o in zip(fastfiles,outfiles) if not os.path.exists(o)]
248+
nMiss=len(fastfiles)
249+
if nIn>nMiss:
250+
print('[INFO] WriteBatch: discarding simulations, only {}/{} needed'.format(nMiss, nIn))
251+
252+
210253
def writeb(batchfile, fastfiles):
211254
with open(batchfile,'w') as f:
255+
if not echo:
256+
if os.name == 'nt':
257+
f.write('@echo off\n')
212258
for ff in fastfiles:
213259
ff_abs = os.path.abspath(ff)
214260
ff_rel = os.path.relpath(ff_abs, batchdir)
215-
l = fastExe_rel + flags + ' '+ ff_rel + flags_after
216-
f.write("{:s}\n".format(l))
261+
cmd = fastExe_rel + flags + ' '+ ff_rel + flags_after
262+
if stdOutToFile:
263+
stdout = os.path.splitext(ff_rel)[0]+'.stdout'
264+
cmd += ' > ' +stdout
265+
if run_if_ext_missing is not None:
266+
# TODO might be windows only
267+
ff_out = os.path.splitext(ff_rel)[0] + run_if_ext_missing
268+
if os.name == 'nt':
269+
cmd = 'if not exist {} ({}) else (echo Skipping {})'.format(ff_out, cmd, ff_rel)
270+
else:
271+
cmd = 'if [[ ! -f {} ]] ; then {}; else echo Skipping {} ; fi'.format(ff_out, cmd, ff_rel)
272+
f.write("{:s}\n".format(cmd))
217273
if pause:
218-
f.write("pause\n") # windows only..
274+
f.write("pause\n") # might be windows only..
275+
276+
219277

220278
if nBatches==1:
221279
writeb(batchfile, fastfiles)
222280
return batchfile
223281
else:
282+
283+
if dispatch:
284+
# TODO this can probably be done with a one liner
285+
fastfiles2=[]
286+
for i in range(nBatches):
287+
fastfiles2+=fastfiles[i::nBatches]
288+
fastfiles = fastfiles2
289+
224290
splits = np.array_split(fastfiles,nBatches)
225291
base, ext = os.path.splitext(batchfile)
226292
batchfiles=[]

0 commit comments

Comments
 (0)