Source code for foxes.models.model_book

import foxes.models as fm
import foxes.variables as FV
from foxes.utils import Dict

from foxes.core import (
    PointDataModel,
    FarmDataModel,
    FarmController,
    RotorModel,
    TurbineType,
    TurbineModel,
    PartialWakesModel,
    WakeFrame,
    WakeSuperposition,
    WakeModel,
    AxialInductionModel,
)


[docs]class ModelBook: """ Container for all kinds of models. Attributes ---------- point_models: foxes.utils.Dict The point models. Keys: model name str, values: foxes.core.PointDataModel rotor_models: foxes.utils.Dict The rotor models. Keys: model name str, values: foxes.core.RotorModel turbine_types: foxes.utils.Dict The turbine type models. Keys: model name str, values: foxes.core.TurbineType turbine_models: foxes.utils.Dict The turbine models. Keys: model name str, values: foxes.core.TurbineModel farm_models: foxes.utils.Dict The farm models. Keys: model name str, values: foxes.core.FarmModel farm_controllers: foxes.utils.Dict The farm controllers. Keys: model name str, values: foxes.core.FarmController partial_wakes: foxes.utils.Dict The partial wakes. Keys: model name str, values: foxes.core.PartialWakeModel wake_frames: foxes.utils.Dict The wake frames. Keys: model name str, values: foxes.core.WakeFrame wake_superpositions: foxes.utils.Dict The wake superposition models. Keys: model name str, values: foxes.core.WakeSuperposition wake_models: foxes.utils.Dict The wake models. Keys: model name str, values: foxes.core.WakeModel induction_models: foxes.utils.Dict The induction models. Keys: model name str, values: foxes.core.AxialInductionModel sources: foxes.utils.Dict All sources dict base_classes: foxes.utils.Dict The base classes for all model types :group: models """
[docs] def __init__(self, Pct_file=None): """ Constructor. Parameters ---------- Pct_file: str, optional Path to power/ct curve file, for creation of default turbine type model """ self.point_models = Dict(name="point_models") self.point_models["tke2ti"] = fm.point_models.TKE2TI() self.rotor_models = Dict(name="rotor_models") rvars = [FV.REWS, FV.REWS2, FV.REWS3, FV.TI, FV.RHO] self.rotor_models["centre"] = fm.rotor_models.CentreRotor(calc_vars=rvars) nlist = list(range(2, 11)) + [20] for n in nlist: self.rotor_models[f"grid{n**2}"] = fm.rotor_models.GridRotor( calc_vars=rvars, n=n, reduce=True ) self.rotor_models[f"level{n}"] = fm.rotor_models.LevelRotor( calc_vars=rvars, n=n, reduce=True ) self.turbine_types = Dict(name="turbine_types") self.turbine_types["null_type"] = fm.turbine_types.NullType() self.turbine_types["NREL5MW"] = fm.turbine_types.PCtFile( "NREL-5MW-D126-H90.csv" ) self.turbine_types["DTU10MW"] = fm.turbine_types.PCtFile( "DTU-10MW-D178d3-H119.csv" ) self.turbine_types["IEA15MW"] = fm.turbine_types.PCtFile( "IEA-15MW-D240-H150.csv" ) self.turbine_types["IWT7.5MW"] = fm.turbine_types.PCtFile( "IWT-7d5MW-D164-H100.csv" ) if Pct_file is not None: self.turbine_types["Pct"] = fm.turbine_types.PCtFile(Pct_file) self.turbine_models = Dict( name="turbine_models", kTI=fm.turbine_models.kTI(), kTI_02=fm.turbine_models.kTI(kTI=0.2), kTI_04=fm.turbine_models.kTI(kTI=0.4), kTI_05=fm.turbine_models.kTI(kTI=0.5), kTI_amb=fm.turbine_models.kTI(ti_var=FV.AMB_TI), kTI_amb_02=fm.turbine_models.kTI(ti_var=FV.AMB_TI, kTI=0.2), kTI_amb_04=fm.turbine_models.kTI(ti_var=FV.AMB_TI, kTI=0.4), kTI_amb_05=fm.turbine_models.kTI(ti_var=FV.AMB_TI, kTI=0.5), thrust2ct=fm.turbine_models.Thrust2Ct(), PMask=fm.turbine_models.PowerMask(), yaw2yawm=fm.turbine_models.YAW2YAWM(), yawm2yaw=fm.turbine_models.YAWM2YAW(), ) self.turbine_models["hubh_data"] = fm.turbine_models.RotorCentreCalc( { f"{FV.WD}_HH": FV.WD, f"{FV.WS}_HH": FV.WS, f"{FV.TI}_HH": FV.TI, f"{FV.RHO}_HH": FV.RHO, } ) self.farm_models = Dict( name="farm_models", **{ f"farm_{mname}": fm.farm_models.Turbine2FarmModel(m) for mname, m in self.turbine_models.items() }, ) self.farm_controllers = Dict( name="farm_controllers", basic_ctrl=fm.farm_controllers.BasicFarmController(), ) self.partial_wakes = Dict( name="partial_wakes", rotor_points=fm.partial_wakes.RotorPoints(), top_hat=fm.partial_wakes.PartialTopHat(), distsliced=fm.partial_wakes.PartialDistSlicedWake(), centre=fm.partial_wakes.PartialCentre(), auto=fm.partial_wakes.Mapped(), ) nlst = list(range(2, 11)) + [20] for n in nlst: self.partial_wakes[f"axiwake{n}"] = fm.partial_wakes.PartialAxiwake(n) for n in nlist: self.partial_wakes[f"distsliced{n**2}"] = ( fm.partial_wakes.PartialDistSlicedWake(n) ) for n in nlist: self.partial_wakes[f"grid{n**2}"] = fm.partial_wakes.PartialGrid(n) self.wake_frames = Dict( name="wake_frames", rotor_wd=fm.wake_frames.RotorWD(var_wd=FV.WD), rotor_wd_farmo=fm.wake_frames.FarmOrder(), yawed=fm.wake_frames.YawedWakes(), ) stps = [1.0, 5.0, 10.0, 50.0, 100.0, 500.0] for s in stps: self.wake_frames[f"streamlines_{int(s)}"] = fm.wake_frames.Streamlines2D( step=s ) for s in stps: self.wake_frames[f"streamlines_{int(s)}_yawed"] = fm.wake_frames.YawedWakes( base_frame=fm.wake_frames.Streamlines2D(step=s) ) for s in stps: self.wake_frames[f"streamlines_{int(s)}_farmo"] = fm.wake_frames.FarmOrder( base_frame=fm.wake_frames.Streamlines2D(step=s) ) dtlist = [ ("1s", 1 / 60), ("10s", 1 / 6), ("30s", 0.5), ("1min", 1), ("10min", 10), ("30min", 30), ] self.wake_frames["timelines"] = fm.wake_frames.Timelines() for s, t in dtlist: self.wake_frames[f"timelines_{s}"] = fm.wake_frames.Timelines(dt_min=t) self.wake_frames["timelines_1km"] = fm.wake_frames.Timelines( max_wake_length=1000.0 ) self.wake_frames["seq_dyn_wakes"] = fm.wake_frames.SeqDynamicWakes() for s, t in dtlist: self.wake_frames[f"seq_dyn_wakes_{s}"] = fm.wake_frames.SeqDynamicWakes( dt_min=t ) self.wake_superpositions = Dict( name="wake_superpositions", ws_linear=fm.wake_superpositions.WSLinear(scale_amb=False), ws_linear_lim=fm.wake_superpositions.WSLinear( scale_amb=False, lim_low=1e-4 ), ws_linear_amb=fm.wake_superpositions.WSLinear(scale_amb=True), ws_linear_amb_lim=fm.wake_superpositions.WSLinear( scale_amb=True, lim_low=1e-4 ), ws_quadratic=fm.wake_superpositions.WSQuadratic(scale_amb=False), ws_quadratic_lim=fm.wake_superpositions.WSQuadratic( scale_amb=False, lim_low=1e-4 ), ws_quadratic_amb=fm.wake_superpositions.WSQuadratic(scale_amb=True), ws_quadratic_amb_lim=fm.wake_superpositions.WSQuadratic( scale_amb=True, lim_low=1e-4 ), ws_cubic=fm.wake_superpositions.WSPow(pow=3, scale_amb=False), ws_cubic_amb=fm.wake_superpositions.WSPow(pow=3, scale_amb=True), ws_quartic=fm.wake_superpositions.WSPow(pow=4, scale_amb=False), ws_quartic_amb=fm.wake_superpositions.WSPow(pow=4, scale_amb=True), ws_max=fm.wake_superpositions.WSMax(scale_amb=False), ws_max_amb=fm.wake_superpositions.WSMax(scale_amb=True), ws_product=fm.wake_superpositions.WSProduct(), ws_product_lim=fm.wake_superpositions.WSProduct(lim_low=1e-4), ti_linear=fm.wake_superpositions.TILinear(superp_to_amb="quadratic"), ti_quadratic=fm.wake_superpositions.TIQuadratic(superp_to_amb="quadratic"), ti_cubic=fm.wake_superpositions.TIPow(pow=3, superp_to_amb="quadratic"), ti_quartic=fm.wake_superpositions.TIPow(pow=4, superp_to_amb="quadratic"), ti_max=fm.wake_superpositions.TIMax(superp_to_amb="quadratic"), ) self.axial_induction = Dict(name="induction_models") self.axial_induction["Betz"] = fm.axial_induction_models.BetzAxialInduction() self.axial_induction["Madsen"] = ( fm.axial_induction_models.MadsenAxialInduction() ) self.wake_models = Dict(name="wake_models") slist = [ "linear", "linear_lim", "linear_amb", "linear_amb_lim", "quadratic", "wquadratic_lim", "quadratic_amb", "quadratic_amb_lim", "cubic", "cubic_amb", "quartic", "quartic_amb", "wmax", "max_amb", "product", "product_lim", ] for s in slist: self.wake_models[f"Jensen_{s}"] = fm.wake_models.wind.JensenWake( superposition=f"ws_{s}" ) self.wake_models[f"Jensen_{s}_k002"] = fm.wake_models.wind.JensenWake( k=0.02, superposition=f"ws_{s}" ) self.wake_models[f"Jensen_{s}_k004"] = fm.wake_models.wind.JensenWake( k=0.04, superposition=f"ws_{s}" ) self.wake_models[f"Jensen_{s}_k007"] = fm.wake_models.wind.JensenWake( k=0.07, superposition=f"ws_{s}" ) self.wake_models[f"Jensen_{s}_k0075"] = fm.wake_models.wind.JensenWake( k=0.075, superposition=f"ws_{s}" ) self.wake_models[f"Bastankhah2014_{s}"] = ( fm.wake_models.wind.Bastankhah2014( superposition=f"ws_{s}", sbeta_factor=0.2 ) ) self.wake_models[f"Bastankhah2014_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2014( k=0.02, sbeta_factor=0.2, superposition=f"ws_{s}" ) ) self.wake_models[f"Bastankhah2014_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2014( k=0.04, sbeta_factor=0.2, superposition=f"ws_{s}" ) ) self.wake_models[f"Bastankhah2014B_{s}"] = ( fm.wake_models.wind.Bastankhah2014( superposition=f"ws_{s}", sbeta_factor=0.2, induction="Betz" ) ) self.wake_models[f"Bastankhah2014B_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2014( k=0.02, sbeta_factor=0.2, superposition=f"ws_{s}", induction="Betz" ) ) self.wake_models[f"Bastankhah2014B_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2014( k=0.04, sbeta_factor=0.2, superposition=f"ws_{s}", induction="Betz" ) ) self.wake_models[f"Bastankhah025_{s}"] = fm.wake_models.wind.Bastankhah2014( superposition=f"ws_{s}", sbeta_factor=0.25 ) self.wake_models[f"Bastankhah025_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2014( k=0.02, superposition=f"ws_{s}", sbeta_factor=0.25 ) ) self.wake_models[f"Bastankhah025_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2014( k=0.04, superposition=f"ws_{s}", sbeta_factor=0.25 ) ) self.wake_models[f"Bastankhah025B_{s}"] = ( fm.wake_models.wind.Bastankhah2014( superposition=f"ws_{s}", sbeta_factor=0.25, induction="Betz" ) ) self.wake_models[f"Bastankhah025B_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2014( k=0.02, superposition=f"ws_{s}", sbeta_factor=0.25, induction="Betz" ) ) self.wake_models[f"Bastankhah025B_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2014( k=0.04, superposition=f"ws_{s}", sbeta_factor=0.25, induction="Betz" ) ) self.wake_models[f"Bastankhah2016_{s}"] = ( fm.wake_models.wind.Bastankhah2016(superposition=f"ws_{s}") ) self.wake_models[f"Bastankhah2016_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2016(superposition=f"ws_{s}", k=0.02) ) self.wake_models[f"Bastankhah2016_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2016(superposition=f"ws_{s}", k=0.04) ) self.wake_models[f"Bastankhah2016B_{s}"] = ( fm.wake_models.wind.Bastankhah2016( superposition=f"ws_{s}", induction="Betz" ) ) self.wake_models[f"Bastankhah2016B_{s}_k002"] = ( fm.wake_models.wind.Bastankhah2016( superposition=f"ws_{s}", k=0.02, induction="Betz" ) ) self.wake_models[f"Bastankhah2016B_{s}_k004"] = ( fm.wake_models.wind.Bastankhah2016( superposition=f"ws_{s}", k=0.04, induction="Betz" ) ) self.wake_models[f"TurbOPark_{s}_A002"] = fm.wake_models.wind.TurbOParkWake( A=0.02, superposition=f"ws_{s}" ) self.wake_models[f"TurbOPark_{s}_A004"] = fm.wake_models.wind.TurbOParkWake( A=0.04, superposition=f"ws_{s}" ) self.wake_models[f"TurbOParkB_{s}_A002"] = ( fm.wake_models.wind.TurbOParkWake( A=0.02, superposition=f"ws_{s}", induction="Betz" ) ) self.wake_models[f"TurbOParkB_{s}_A004"] = ( fm.wake_models.wind.TurbOParkWake( A=0.04, superposition=f"ws_{s}", induction="Betz" ) ) As = [0.02, 0.04] dxs = [0.01, 1.0, 5.0, 10.0, 50.0, 100.0] for A in As: for dx in dxs: a = str(A).replace(".", "") d = str(dx).replace(".", "") if dx < 1 else int(dx) self.wake_models[f"TurbOParkIX_{s}_A{a}_dx{d}"] = ( fm.wake_models.wind.TurbOParkWakeIX( A=A, superposition=f"ws_{s}", dx=dx ) ) slist = ["linear", "quadratic", "cubic", "quartic", "max"] for s in slist: self.wake_models[f"CrespoHernandez_{s}"] = ( fm.wake_models.ti.CrespoHernandezTIWake(superposition=f"ti_{s}") ) self.wake_models[f"CrespoHernandez_ambti_{s}"] = ( fm.wake_models.ti.CrespoHernandezTIWake( superposition=f"ti_{s}", use_ambti=True ) ) self.wake_models[f"CrespoHernandez_{s}_k002"] = ( fm.wake_models.ti.CrespoHernandezTIWake(k=0.02, superposition=f"ti_{s}") ) self.wake_models[f"IECTI2005_{s}"] = fm.wake_models.ti.IECTIWake( superposition=f"ti_{s}", iec_type="2005" ) self.wake_models[f"IECTI2019_{s}"] = fm.wake_models.ti.IECTIWake( superposition=f"ti_{s}", iec_type="2019" ) self.wake_models[f"RHB"] = fm.wake_models.induction.RankineHalfBody() self.wake_models[f"SelfSimilar"] = fm.wake_models.induction.SelfSimilar() self.wake_models[f"SelfSimilar2020"] = ( fm.wake_models.induction.SelfSimilar2020() ) self.wake_models[f"Rathmann"] = fm.wake_models.induction.Rathmann() self.sources = Dict( name="sources", point_models=self.point_models, rotor_models=self.rotor_models, turbine_types=self.turbine_types, turbine_models=self.turbine_models, farm_models=self.farm_models, farm_controllers=self.farm_controllers, partial_wakes=self.partial_wakes, wake_frames=self.wake_frames, wake_superpositions=self.wake_superpositions, wake_models=self.wake_models, axial_induction=self.axial_induction, ) self.base_classes = Dict( name="base_classes", point_models=PointDataModel, rotor_models=RotorModel, turbine_types=TurbineType, turbine_models=TurbineModel, farm_models=FarmDataModel, farm_controllers=FarmController, partial_wakes=PartialWakesModel, wake_frames=WakeFrame, wake_superpositions=WakeSuperposition, wake_models=WakeModel, axial_induction=AxialInductionModel, ) for s in self.sources.values(): for k, m in s.items(): m.name = k
[docs] def __getitem__(self, key): return self.sources.__getitem__(key)
[docs] def print_toc(self, subset=None, search=None): """ Print the contents. Parameters ---------- subset: list of str, optional Selection of model types search: str, optional String that has to be part of the model name """ for k in sorted(list(self.sources.keys())): ms = self.sources[k] if subset is None or k in subset: print(k) print("-" * len(k)) if len(ms): for mname in sorted(list(ms.keys())): if search is None or search in mname: print(f"{mname}: {ms[mname]}") else: print("(none)") print()
[docs] def get(self, model_type, name, class_name=None, *args, **kwargs): """ Gets a model object. If not found, dynamically creates it (given the class name) Parameters ---------- model_type: str The model type name: str The model name class_name: str, optinal Name of the model class args: tuple, optional Arguments for the model class kwargs: dict, optional Arguments for the model class Returns ------- model: mclass The model object """ if name not in self.sources[model_type]: if class_name is None: raise KeyError( f"Model '{name}' of type '{model_type}' not found in model book. Available: {sorted(list(self.sources[model_type].keys()))}" ) bclass = self.base_classes[model_type] self.sources[model_type][name] = bclass.new(class_name, *args, **kwargs) return self.sources[model_type][name]
[docs] def finalize(self, algo, verbosity=0): """ Finalizes the model. Parameters ---------- algo: foxes.core.Algorithm The calculation algorithm verbosity: int The verbosity level, 0 = silent """ for ms in self.sources.values(): if isinstance(ms, Dict): for m in ms.values(): if m.initialized: m.finalize(algo, verbosity)