Source code for ard.wind_query

import numpy as np

from floris.wind_data import WindDataBase
from floris.wind_data import TimeSeries


[docs] class WindQuery: """ A class that manages sets of wind conditions to query that can operate for different types and fidelities of aerodynamic solvers without loss of generality. """ def __init__( self, directions: np.ndarray = None, speeds: np.ndarray = None, TIs: np.ndarray = None, ) -> None: """ WindQuery initialization. A WindQuery object must be initialized with speeds and directions, which must be equal-length numpy arrays, and turbulence intensities can be provided with a same-length array, a single float, or will otherwise be set by default using FLORIS's `assign_ti_using_IEC_method`. Parameters ---------- directions : np.ndarray the directions of the wind resource to be evaluated in degrees speeds : np.ndarray the velocities of the wind resource to be evaluated in meters/second TIs : np.ndarray, optional turbulence intensities of the wind resource (non-dimensional) """ self.directions = np.array([]) self.speeds = np.array([]) self.TIs = np.array([]) if directions is not None: self.set_directions(directions) if speeds is not None: self.set_speeds(speeds) if TIs is not None: self.set_TIs(TIs)
[docs] def set_directions(self, directions: np.ndarray): """ Set the directions on a WindQuery object. Parameters ---------- directions : np.ndarray the directions of the wind resource to be assigned, in degrees """ self.directions = directions self.N_conditions = ( None if self.directions.size != self.speeds.size else self.directions.size )
[docs] def set_speeds(self, speeds: np.ndarray): """ Set the wind speeds on a WindQuery object. Parameters ---------- speeds : np.ndarray the speeds of the wind resource to be assigned, in meters/second """ self.speeds = speeds self.N_conditions = ( None if self.directions.size != self.speeds.size else self.directions.size )
[docs] def set_TIs(self, TIs: float | np.ndarray): """ Set the turbulence intensities on a WindQuery object. Parameters ---------- TIs : float or np.ndarray the turbulence intensity value or values of the wind resource to be assigned, non-dimensionally """ # flip over to using a numpy array and correct size if set as a float TIs = np.array(TIs) if (np.array(TIs).size == 1) and (self.N_conditions is not None): TIs = TIs * np.ones((self.N_conditions,)) else: assert ( TIs.size == self.N_conditions ), "mismatch in TI size vs. direction/speed" self.TIs = TIs
[docs] def set_TI_using_IEC_method(self): """ Re-set the turbulence intensities using the FLORIS IEC method interface. """ assert self.directions is not None, "directions must be set" assert self.speeds is not None, "speeds must be set" # use a temporary FLORIS time series to get the IEC TIs ts_temp = TimeSeries( wind_directions=self.directions, wind_speeds=self.speeds, turbulence_intensities=0.06 * np.ones_like(self.directions), # default value ) ts_temp.assign_ti_using_IEC_method() # re-set all the values _, _, TIs_new, _, _, _ = ts_temp.unpack() self.set_TIs(TIs_new)
[docs] def get_directions(self): """Get the directions from the wind query object.""" assert self.is_valid(), "mismatch in direction/speed vectors" return self.directions
[docs] def get_speeds(self): """Get the wind speeds from the wind query object.""" assert self.is_valid(), "mismatch in direction/speed vectors" return self.speeds
[docs] def get_TIs(self): """Get the turbulence intensities from the wind query object.""" assert self.is_valid(), "mismatch in direction/speed vectors" return self.TIs
[docs] def is_valid(self): """Ensure that the specified wind conditions are valid.""" # first, not a valid query if the directions and speeds aren't specified if (self.directions is None) or (self.speeds is None): return False # next, to be valid the directions and speeds should be the same size and shape if not np.all(np.equal(self.directions.shape, self.speeds.shape)): return False # to be valid, directions should be on [0, 360] if np.any((self.directions < 0.0) | (self.directions > 360.0)): return False # to be valid, velocity should be on [0, +inf) if np.any(self.directions < 0.0): return False return True
[docs] def from_FLORIS_WindData(winddata_FLORIS: WindDataBase): """ Turn a FLORIS WindData object into a (more general) WindQuery object. Parameters ---------- winddata_FLORIS : floris.wind_data.WindDataBase A FLORIS wind data object derived from the WindDataBase base class. Returns ------- WindQuery A WindQuery object that represents that same wind data as the FLORIS wind data object. """ wind_directions, wind_speeds, ti_table, _, _, _ = winddata_FLORIS.unpack() # create the wind query for this condition wq = WindQuery(wind_directions, wind_speeds, TIs=ti_table) assert wq.is_valid() # make sure it's legit return wq # and ship it