Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windturbine and additional parameters/function in weather modell #277

Merged
merged 37 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a06a757
more advanced heat pump model, example and tester
Hoppe-J Dec 6, 2023
5a13bda
tester for more advanced heatpump
Hoppe-J Dec 6, 2023
4dad045
units for pressure
Hoppe-J Dec 8, 2023
40db176
weather model ergänzt um druck aus-/übergabe
Hoppe-J Dec 8, 2023
6972232
model ergänzt um druck für ggf zukünftige erweiterung von windkraftan…
Hoppe-J Dec 8, 2023
ea6b147
pressure output angepasst
Hoppe-J Dec 8, 2023
ed75731
pressure ergänzt
Hoppe-J Dec 8, 2023
4bda798
anpassen auf SI-Einheit für Druck
Hoppe-J Dec 11, 2023
193f6f1
anpassen auf SI-Einheit für Druck
Hoppe-J Dec 11, 2023
a3d9598
anpassen auf SI-Einheit für Druck
Hoppe-J Dec 11, 2023
569b9bf
modell ergänzt um pressure output für windkraftanlage,
Hoppe-J Dec 20, 2023
cbd47fa
Merge branch 'JHo_more_advanced_heatpump' into JHo_windpower
Hoppe-J Dec 20, 2023
77225fe
Merge remote-tracking branch 'origin/main'
Hoppe-J Dec 20, 2023
852dd87
test
Hoppe-J Dec 20, 2023
b373f37
wettermodell update
Hoppe-J Dec 20, 2023
da87a62
hisim uodate
Hoppe-J Dec 20, 2023
67ae3f8
Merge branch 'main' into JHo_windpower
Hoppe-J Dec 20, 2023
8793deb
wp modell nicht für diesen Branche!
Hoppe-J Dec 20, 2023
62d0c2b
New Modell of a Windturbine based on windpowerlib https://github.com/…
Hoppe-J Dec 20, 2023
2a0c93f
test for generic windturbine
Hoppe-J Dec 20, 2023
c2bc9c4
gehört nicht zum branche für windkraftanlage
Hoppe-J Dec 20, 2023
f3cab4a
manuell auf aktuelle hisim version kopiert
Hoppe-J Dec 20, 2023
6ca5a89
erst zu mein branche, wenn komplett fertig und abgenommen
Hoppe-J Dec 21, 2023
bef1984
Merge remote-tracking branch 'origin/main'
Hoppe-J Jan 10, 2024
461efdb
Merge branch 'main' into JHo_windpower
Hoppe-J Jan 10, 2024
3aacd12
- implement windpowerlib in requirements.txt
Hoppe-J Jan 10, 2024
f3d99c9
- Preparation for external weather data retrieval of DWD and era5 data
Hoppe-J Jan 12, 2024
4f31254
Merge remote-tracking branch 'origin/main'
Hoppe-J Jan 12, 2024
ebdc8fd
geändert auf original weather model
Hoppe-J Jan 12, 2024
ff5aa3a
Merge branch 'main' into JHo_windpower
Hoppe-J Jan 12, 2024
a7f39ea
NOTE: NEW MODEL FOR WEATHER DATA IMPORT (weather_data_import.py) --> …
Hoppe-J Jan 16, 2024
af42120
a small change to make the variable "name" flexible --> "name" is now…
Hoppe-J Jan 17, 2024
8e19a2f
Merge branch 'main' into JHo_windpower
Hoppe-J Jan 29, 2024
729a19f
update and fix merge conflicts
Hoppe-J Jan 29, 2024
aa7203f
- updated nsrdb_15min files: parameter "pressure" and "wind direction…
Hoppe-J Feb 1, 2024
9084f25
Merge branch 'main' into JHo_windpower
Hoppe-J Feb 7, 2024
70b0e6e
Merge branch 'main' into JHo_windpower
Hoppe-J Feb 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
336 changes: 336 additions & 0 deletions hisim/components/generic_windturbine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
"""Windturbine."""

# clean

from dataclasses import dataclass
from typing import List, Tuple, Optional


import numpy as np
import pandas as pd
from dataclasses_json import dataclass_json
from windpowerlib import ModelChain, WindTurbine


from hisim import component as cp
from hisim import loadtypes as lt
from hisim import utils
from hisim.component import ConfigBase, OpexCostDataClass
from hisim.components.weather import Weather
from hisim.simulationparameters import SimulationParameters


__authors__ = "Jonas Hoppe"
__copyright__ = ""
__credits__ = [" Jonas Hoppe "]
__license__ = ""
__version__ = ""
__maintainer__ = " "
__email__ = ""
__status__ = ""



"""
Based on: https://github.com/wind-python/windpowerlib/tree/dev
Use of windpowerlib for calculation of electrical output power

"""

#todo: predictiv controll ?
#todo: wirkungsgrad einbringen?? ggf über bib direkt?



@dataclass_json
@dataclass
class WindturbineConfig(ConfigBase):

"""PVSystemConfig class."""

@classmethod
def get_main_classname(cls):
"""Returns the full class name of the base class."""
return Windturbine.get_full_classname()

name: str
#Typename of the wind turbine.
turbine_type: str
#Hub height of the wind turbine in m.
hub_height:Optional[float]
#The nominal output of the wind turbine in W
nominal_power: Optional[float]
# Diameter of the rotor in m
rotor_diameter:Optional[float]
#Power coefficient curve of the wind turbine
power_coefficient_curve: None
#Power curve of the wind turbine.
power_curve: None
#Defines which model is used to calculate the wind speed at hub height
wind_speed_model: str
#Defines which model is used to calculate the temperature of air at hub height
temperature_model: str
#Defines which model is used to calculate the density of air at hub height.
density_model: str
#Defines which model is used to calculate the turbine power output.
power_output_model: str
density_correction: bool
obstacle_height: float
hellman_exp: float

source_weight: int
#: CO2 footprint of investment in kg
co2_footprint: float
#: cost for investment in Euro
cost: float
# maintenance cost as share of investment [0..1]
maintenance_cost_as_percentage_of_investment: float
#: lifetime in years
lifetime: float
predictive: bool
predictive_control: bool
prediction_horizon: Optional[int]

@classmethod
def get_default_windturbine_config(cls) -> "WindturbineConfig":
"""Gets a default windturbine."""
return WindturbineConfig(
name="Windturbine",
turbine_type="V126/3300",
hub_height=137,
nominal_power=None,
rotor_diameter=126,
power_coefficient_curve=None,
power_curve=None,

wind_speed_model="logarithmic",#'logarithmic' ,'hellman', 'interpolation_extrapolation' , 'log_interpolation_extrapolation'
temperature_model="linear_gradient", #'linear_gradient','interpolation_extrapolation'
density_model="barometric", #'barometric','ideal_gas','interpolation_extrapolation'
power_output_model="power_curve", #power_curve','power_coefficient_curve'
density_correction=False,
obstacle_height=0,
hellman_exp=None, #This parameter is only used if the parameter `wind_speed_model` is 'hellman'.

source_weight=999,
co2_footprint=0,
cost=0,
maintenance_cost_as_percentage_of_investment=0,
lifetime=0,
predictive=False,
predictive_control=False,
prediction_horizon=None,
)


class Windturbine(cp.Component):



# Inputs
TemperatureOutside = "TemperatureOutside"
WindSpeed = "WindSpeed"
Pressure ="Pressure"

# Outputs
ElectricityOutput = "ElectricityOutput"


@utils.measure_execution_time
def __init__(
self, my_simulation_parameters: SimulationParameters, config: WindturbineConfig
) -> None:
"""Initialize the class."""
self.windturbineconfig = config

super().__init__(
self.windturbineconfig.name + "_w" + str(self.windturbineconfig.source_weight),
my_simulation_parameters=my_simulation_parameters,
my_config=config,
)

self.turbine_type = self.windturbineconfig.turbine_type
self.hub_height = self.windturbineconfig.hub_height
self.rotor_diameter = self.windturbineconfig.rotor_diameter
self.power_coefficient_curve = self.windturbineconfig.power_coefficient_curve
self.power_curve = self.windturbineconfig.power_curve
self.nominal_power = self.windturbineconfig.nominal_power

self.wind_speed_model = self.windturbineconfig.wind_speed_model
self.temperature_model = self.windturbineconfig.temperature_model
self.density_model = self.windturbineconfig.density_model
self.power_output_model = self.windturbineconfig.power_output_model
self.density_correction = self.windturbineconfig.density_correction
self.obstacle_height = self.windturbineconfig.obstacle_height
self.hellman_exp = self.windturbineconfig.hellman_exp


#Inistialisieren Windkraftanlage
self.windturbine_module = WindTurbine(
hub_height=self.hub_height,
nominal_power=self.nominal_power,
path="oedb",
power_curve=self.power_curve,
power_coefficient_curve=self.power_coefficient_curve,
rotor_diameter=self.rotor_diameter,
turbine_type=self.turbine_type, )

#Berechnungsmethoden Winddaten
self.calculation_setup = ModelChain(
power_plant= self.windturbine_module,
wind_speed_model=self.wind_speed_model,
temperature_model=self.temperature_model,
density_model=self.density_model,
power_output_model=self.power_output_model,
density_correction=self.density_correction,
obstacle_height=self.obstacle_height,
hellman_exp=self.hellman_exp,
)


self.t_out_channel: cp.ComponentInput = self.add_input(
self.component_name,
self.TemperatureOutside,
lt.LoadTypes.TEMPERATURE,
lt.Units.CELSIUS,
True,
)

# inputs
self.wind_speed_channel: cp.ComponentInput = self.add_input(
self.component_name,
self.WindSpeed,
lt.LoadTypes.SPEED,
lt.Units.METER_PER_SECOND,
True,
)

self.pressure_channel: cp.ComponentInput = self.add_input(
self.component_name,
self.Pressure,
lt.LoadTypes.PRESSURE,
lt.Units.PASCAL,
True,
)

# outputs
self.electricity_output_channel: cp.ComponentOutput = self.add_output(
object_name=self.component_name,
field_name=self.ElectricityOutput,
load_type=lt.LoadTypes.ELECTRICITY,
unit=lt.Units.WATT,
postprocessing_flag=[lt.InandOutputType.ELECTRICITY_PRODUCTION],
output_description=f"here a description for Windturbine {self.ElectricityOutput} will follow.",
)

self.add_default_connections(self.get_default_connections_from_weather())


def get_default_connections_from_weather(self):
"""Get default connections from weather."""

connections = []
weather_classname = Weather.get_classname()
connections.append(
cp.ComponentConnection(
Windturbine.TemperatureOutside,
weather_classname,
Weather.TemperatureOutside,
)
)

connections.append(
cp.ComponentConnection(
Windturbine.WindSpeed, weather_classname, Weather.WindSpeed
)
)

connections.append(
cp.ComponentConnection(
Windturbine.Pressure, weather_classname, Weather.Pressure
)
)
return connections


def i_save_state(self) -> None:
"""Saves the state."""
pass

def i_restore_state(self) -> None:
"""Restores the state."""
pass

def write_to_report(self):
"""Write to the report."""
return self.windturbineconfig.get_string_dict()

def i_doublecheck(self, timestep: int, stsv: cp.SingleTimeStepValues) -> None:
"""Doublechecks."""
pass

def i_prepare_simulation(self) -> None:
"""Prepares the component for the simulation."""

pass

def i_simulate(
self, timestep: int, stsv: cp.SingleTimeStepValues, force_convergence: bool
) -> None:
"""Simulate the component."""

wind_speed_10m_in_m_per_sec = stsv.get_input_value(self.wind_speed_channel)
temperature_2m_in_GradC = stsv.get_input_value(self.t_out_channel)
pressure_standorthoehe_in_Pa = stsv.get_input_value(self.pressure_channel)

temperature_2m_in_K = temperature_2m_in_GradC + 273.15

roughness_length_in_m=0.15


data = [[wind_speed_10m_in_m_per_sec, temperature_2m_in_K, pressure_standorthoehe_in_Pa, roughness_length_in_m]]

columns = [np.array(['wind_speed', 'temperature', 'pressure', 'roughness_length']),
np.array([10, 2, 125,0])] #höhe der Messstellen --> Aus Wetterdaten


weather_df = pd.DataFrame(data, columns=columns) #dataframe, due to package windpowerlib only work with it

#calculation of windturbine power
windturbine_power=self.calculation_setup.run_model(weather_df)

# write power output time series to WindTurbine object
windturbine_power.power_output=windturbine_power.power_output

power_output_windturbine_in_W=windturbine_power.power_output

df_electric_power_output_windturbine_in_W = pd.DataFrame(power_output_windturbine_in_W)

electric_power_output_windturbine_in_W = df_electric_power_output_windturbine_in_W.iloc[0].iloc[0]


stsv.set_output_value(self.electricity_output_channel, electric_power_output_windturbine_in_W)



@staticmethod
def get_cost_capex(config: WindturbineConfig) -> Tuple[float, float, float]:
"""Returns investment cost, CO2 emissions and lifetime."""
return config.cost, config.co2_footprint, config.lifetime

def get_cost_opex(
self,
all_outputs: List,
postprocessing_results: pd.DataFrame,
) -> OpexCostDataClass:
# pylint: disable=unused-argument
"""Calculate OPEX costs, consisting of maintenance costs for PV."""
opex_cost_data_class = OpexCostDataClass(
opex_cost=self.calc_maintenance_cost(),
co2_footprint=0,
consumption=0,
)

return opex_cost_data_class



Loading