Source code for pyts.runInput.base

"""
The base module for the runInput package. This module defines the
TurbSim input class (tsinput). The tsinput class is a dictionary for
storing data from a TurbSim input file. The class contains several
methods that specify default values for several input variables. Those
defaults documented in the Original-TurbSim documentation:
https://wind.nrel.gov/designcodes/preprocessors/turbsim/TurbSim.pdf

"""
from ..base import np
from numpy import uint32
from ..misc import kappa, InvalidConfig, zL, psiM


[docs]class tsinput(dict): """ The TurbSim input object and 'global defaults' handler. This class works essentially as a dictionary, but with various functions and routines for providing default values in the event that 'input' values are not specified explicitly by the user. Regarding global defaults: The '_dflt_...' functions define 'global' default definitions (used by multiple profModels and/or turbModels). Other, model specific, defaults are defined in the model itself. For further information on the 'defaults' defined here, consult the O-TurbSim documentation: https://wind.nrel.gov/designcodes/preprocessors/turbsim/TurbSim.pdf """ def __getitem__(self, key): """ Gets the item *key* from the dictionary. If there is no value, or it is 'None', and there is a '_dflt_<key>' property in the class, it uses this property to 'set the default'. Otherwise return *None*. """ if key == 'RandSeed': return self.randseed if key in ['IECstandard', 'IECedition'] and \ dict.__getitem__(self, 'IECstandard').__class__ is str: self['IECstandard'], self['IECedition'] = self.parse_IEC_standard(dict.__getitem__(self, 'IECstandard')) # noqa if key not in self or dict.__getitem__(self, key) is None: if hasattr(self, '_dflt_' + key): self[key] = self.__getattribute__('_dflt_' + key) self._dict_isdefault[key] = 2 return self[key] else: return None return dict.__getitem__(self, key) def __setitem__(self, key, val): if key == 'RandSeed': self.randseed = val else: dict.__setitem__(self, key, val) @property def incdec_a(self,): """ The 'a' coherence decrement. """ out = [None, None, None] if self['IncDec1'] is not None: if hasattr(self['IncDec1'], '__len__'): out[0] = self['IncDec1'][0] else: out[0] = self['IncDec1'] if self['IncDec2'] is not None: if hasattr(self['IncDec2'], '__len__'): out[1] = self['IncDec2'][0] else: out[1] = self['IncDec2'] if self['IncDec3'] is not None: if hasattr(self['IncDec3'], '__len__'): out[2] = self['IncDec3'][0] else: out[2] = self['IncDec3'] return out @property def incdec_b(self,): out = [0., 0., 0.] if self['IncDec1'] is not None and hasattr(self['IncDec1'], '__len__'): out[0] = self['IncDec1'][1] if self['IncDec2'] is not None and hasattr(self['IncDec2'], '__len__'): out[1] = self['IncDec2'][1] if self['IncDec3'] is not None and hasattr(self['IncDec3'], '__len__'): out[2] = self['IncDec3'][1] return out
[docs] def parse_IEC_standard(self, iecstd): if iecstd.__class__ is str: iecstd = iecstd.lower() tmp = int(iecstd[0]) if len(iecstd) > 1 and tmp == 1: iecedt = int(iecstd[-1]) else: iecedt = None # There are no editions to the -2 and -3 standards. iecstd = tmp elif iecstd == 1 or iecstd is None: iecstd = 1 if self.turbmodel == 'ieckai': iecedt = 3 else: iecedt = 2 else: iecedt = None # There are no editions to the -2 and -3 standards. if iecedt == 3 and self.turbmodel == 'iecvkm': raise InvalidConfig("The von-Karman spectral model (IECVKM) \ is not valid for IEC standard 61400-1's 3rd edition. Either \ change TurbModel to IECKAI, or change the IECstandard to '1-ed2' \ or simply '1'.") elif iecedt > 1 and self['IEC_WindType'].lower() != 'ntm': raise InvalidConfig("If the IECstandard is 1-ed2 or 1-ed3, \ than the WindType must be 'NTM'.") return (iecstd, iecedt)
def __init__(self, *args, **kwargs): self._dict_isdefault = {} dict.__init__(self, *args, **kwargs)
[docs] def isdefault(self, key): """ Is the given variable a default? True : The value is not specified and there is no '_dflt_...' function. 2 : The value is defined by a '_dflt_...' function. False: The value is specified explicitly in the configuration. """ if self[key] is None: return True if key in self._dict_isdefault: return self._dict_isdefault[key] else: return False
@property def randseed(self,): tmpval = 0 if 'RandSeed1' in self and self['RandSeed1'] is not None: tmpval += uint32(self['RandSeed1']) if 'RandSeed2' in self and self['RandSeed2'] is not None: tmpval += uint32(self['RandSeed2']) << 32 if tmpval == 0: return None return tmpval @randseed.setter def randseed(self, val): if val is None: self['RandSeed1'] = None self['RandSeed2'] = None else: self['RandSeed1'] = np.int32(val & 2 ** 32 - 1) val2 = np.int32(val >> 32) if val2 > 0: self['RandSeed2'] = val2 else: self['RandSeed2'] = None @property def _dflt_WindProfileType(self,): if self.turbmodel == 'gp_llj': return 'JET' elif self.turbmodel in ['river', 'tidal']: return 'H2L' else: return 'IEC' @property def turbmodel(self,): return self['TurbModel'].lower() # These are only called if the key is not in the dictionary: @property def _dflt_Z0(self,): return {'ieckai': 0.03, 'iecvkm': 0.03, 'smooth': 0.01, 'gp_llj': 0.005, 'nwtcup': 0.021, 'wf_upw': 0.018, 'wf_07d': 0.064, 'wf_14d': 0.233, 'tidal': 0.1, 'river': 0.1 }[self.turbmodel] @property def _dflt_UStar(self,): if ('URef' not in self or self['URef'] is None) and \ ('UStar' not in self or self['UStar'] is None): raise InvalidConfig('Either URef or UStar must be defined in the input file.') mdl = self.turbmodel ustar0 = self.ustar0 if mdl == 'smooth': ustar = ustar0 elif mdl == 'nwtcup': ustar = 0.2716 + 0.7573 * ustar0 ** 1.2599 elif mdl == 'gp_llj': ustar = 0.17454 + 0.72045 * ustar0 ** 1.36242 elif mdl == 'wf_upw': if self.zL < 0: ustar = 1.162 * ustar0 ** 0.66666 else: ustar = 0.911 * ustar0 ** 0.66666 elif mdl in ['wf_07d', 'wf_14d']: if self.zL < 0: ustar = 1.484 * ustar0 ** 0.66666 else: ustar = 1.370 * ustar0 ** 0.66666 elif mdl in ['tidal', 'river']: ustar = self['URef'] * 0.05 return ustar @property def _dflt_Latitude(self,): return 45.0 @property def _dflt_ZI(self,): if self['UStar'] < self.ustar0: return 400 * self['URef'] / np.log(self['RefHt'] / self['Z0']) else: return self['UStar'] / (12 * 7.292116e-5 * np.sin(np.pi / 180 * np.abs(self['Latitude']))) # noqa @property def _dflt_PC_UV(self,): return 0.0 @property def _dflt_PC_UW(self,): return 0.0 @property def _dflt_PC_VW(self,): return 0.0 @property def _dflt_PLExp(self,): """ The default Wind Profile power law exponent. """ tm = self.turbmodel Ri = self['RICH_NO'] if tm in ['ieckai', 'iecvkm']: if self['IECstandard'] == 1 and \ self['IEC_WindType'].lower() == 'ewm': plexp = 0.11 elif self['IECstandard'] == 3: plexp = 0.14 plexp = {'ewm': 0.11, 'ntm': 0.14}.get( self['WindProfileType'], 0.2) elif tm in ['wf_upw', 'nwtcup']: if self['IECturbc'].lower() == 'khtest' and \ self.turbmodel == 'nwtcup': plexp = 0.3 if Ri > 0: plexp = 0.14733 else: plexp = 0.087688 + 0.059641 * np.exp(Ri / 0.04717783) elif tm in ['wf_07d', 'wf_14d']: if Ri > 0.04: plexp = 0.17903 else: plexp = 0.1277 + 0.031229 * np.exp(Ri / 0.0805173) else: # ['smooth','gp_llj','tidal','river']: plexp = 0.143 return plexp ### These are helper functions, not 'default input parameters': @property def ustar0(self,): return (kappa * self['URef'] / (np.log(self['RefHt'] / self['Z0']) - self.psiM)) @property def zL(self,): if not hasattr(self, '_val_zL'): self._val_zL = zL(self['RICH_NO'], self['TurbModel']) return self._val_zL @property def psiM(self,): if not hasattr(self, '_val_psiM'): self._val_psiM = psiM(self['RICH_NO'], self['TurbModel']) return self._val_psiM