Source code for foxes.models.partial_wakes.top_hat

import numpy as np

from foxes.models.wake_models.top_hat import TopHatWakeModel
from foxes.utils.two_circles import calc_area
import foxes.variables as FV
import foxes.constants as FC

from .centre import PartialCentre


[docs] class PartialTopHat(PartialCentre): """ Partial wakes for top-hat models. The wake effect is weighted by the overlap of the wake circle and the rotor disc circle. Attributes ---------- rotor_model: foxes.core.RotorModel The rotor model, default is the one from the algorithm :group: models.partial_wakes """
[docs] def check_wmodel(self, wmodel, error=True): """ Checks the wake model type Parameters ---------- wmodel: foxes.core.WakeModel The wake model to be tested error: bool Flag for raising TypeError Returns ------- chk: bool True if wake model is compatible """ if not isinstance(wmodel, TopHatWakeModel): if error: raise TypeError( f"Partial wakes '{self.name}': Cannot be applied to wake model '{wmodel.name}', since not a TopHatWakeModel" ) return False return True
[docs] def __init__(self, rotor_model=None): """ Constructor. Parameters ---------- rotor_model: foxes.core.RotorModel, optional The rotor model, default is the one from the algorithm """ super().__init__() self.rotor_model = rotor_model
[docs] def initialize(self, algo, verbosity=0): """ Initializes the model. Parameters ---------- algo: foxes.core.Algorithm The calculation algorithm verbosity: int The verbosity level, 0 = silent """ if self.rotor_model is None: self.rotor_model = algo.rotor_model super().initialize(algo, verbosity) self.WCOOS_ID = self.var("WCOOS_ID") self.WCOOS_X = self.var("WCOOS_X") self.WCOOS_R = self.var("WCOOS_R")
[docs] def sub_models(self): """ List of all sub-models Returns ------- smdls: list of foxes.core.Model Names of all sub models """ return super().sub_models() + [self.rotor_model]
[docs] def contribute( self, algo, mdata, fdata, tdata, downwind_index, wake_deltas, wmodel, ): """ Modifies wake deltas at target points by contributions from the specified wake source turbines. Parameters ---------- algo: foxes.core.Algorithm The calculation algorithm mdata: foxes.core.MData The model data fdata: foxes.core.FData The farm data tdata: foxes.core.TData The target point data downwind_index: int The index of the wake causing turbine in the downwind order wake_deltas: dict The wake deltas. Key: variable name, value: numpy.ndarray with shape (n_states, n_targets, n_tpoints, ...) wmodel: foxes.core.WakeModel The wake model """ self.check_wmodel(wmodel, error=True) wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index) x = wcoos[:, :, 0, 0] yz = wcoos[:, :, 0, 1:3] del wcoos ct = self.get_data( FV.CT, FC.STATE_TARGET, lookup="w", fdata=fdata, tdata=tdata, downwind_index=downwind_index, algo=algo, upcast=True, ) sel0 = (ct > 1e-8) & (x > 1e-8) if np.any(sel0): R = np.linalg.norm(yz, axis=-1) del yz D = self.get_data( FV.D, FC.STATE_TARGET, lookup="w", fdata=fdata, tdata=tdata, downwind_index=downwind_index, algo=algo, upcast=True, ) wr = wmodel.calc_wake_radius( algo, mdata, fdata, tdata, downwind_index, x, ct ) st_sel = sel0 & (wr > R - D / 2) if np.any(st_sel): x = x[st_sel] ct = ct[st_sel] wr = wr[st_sel] R = R[st_sel] D = D[st_sel] clw = wmodel.calc_centreline( algo, mdata, fdata, tdata, downwind_index, st_sel, x, wr, ct ) weights = calc_area(D / 2, wr, R) / (np.pi * (D / 2) ** 2) for v, d in clw.items(): try: superp = wmodel.superp[v] except KeyError: raise KeyError( f"Model '{self.name}': Missing wake superposition entry for variable '{v}' in wake model '{wmodel.name}', found {sorted(list(wmodel.superp.keys()))}" ) wake_deltas[v] = superp.add_wake( algo, mdata, fdata, tdata, downwind_index, st_sel, v, wake_deltas[v], weights[:, None] * d[:, None], )