Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 27 additions & 0 deletions examples/00b_wind_farm_scada_power/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Example 00b: Wind farm SCADA power

## Description

Demonstrate the use of `WindFarmSCADAPower` to simulate a wind farm using SCADA power data. `WindFarmSCADAPower` is useful when the input available is not wind speeds but rather SCADA power data.

## Setup

As in example 00, the wind farm is a small 3 turbine farm and the input is automatically generated. For `WindFarmSCADAPower` this input is a history of pre-recorded turbine power data in `inputs/scada_input.ftr`.

Also as in example 00, turbine 0's power is toggled every 100 seconds. This means it will sometimes follow the pre-recorded power data and sometimes be curtailed below it.

## Running

To run the example, execute the following command in the terminal:

```bash
python hercules_runscript.py
```

## Outputs

To plot the outputs run the following command in the terminal:

```bash
python plot_outputs.py
```
35 changes: 35 additions & 0 deletions examples/00b_wind_farm_scada_power/hercules_input.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Input YAML for hercules

# Name
name: example_00b

###
# Describe this simulation setup
description: Wind Farm SCADA Power, Logging All Turbine Data

dt: 1.0
starttime_utc: "2020-01-01T00:00:00Z" # Midnight Jan 1, 2020 UTC (Zulu time)
endtime_utc: "2020-01-01T00:15:50Z" # 15 minutes 50 seconds later
verbose: False

plant:
interconnect_limit: 15000 # kW

wind_farm:
component_type: WindFarmSCADAPower
scada_filename: ../inputs/scada_input.ftr
log_file_name: outputs/log_wind_sim.log
log_channels:
- power
- turbine_powers
- turbine_power_setpoints


controller:







58 changes: 58 additions & 0 deletions examples/00b_wind_farm_scada_power/hercules_runscript.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import numpy as np
from hercules.hercules_model import HerculesModel
from hercules.utilities_examples import ensure_example_inputs_exist, prepare_output_directory

prepare_output_directory()

# Ensure example inputs exist
ensure_example_inputs_exist()

# Initialize the Hercules model
hmodel = HerculesModel("hercules_input.yaml")


# Define a simple controller that sets all deratings to full rating
# and then sets the derating of turbine 000 to 500, toggling every other 100 seconds.
class ControllerToggleTurbine000:
"""A simple controller that toggles the derating of turbine 000 every other 100 seconds.

This controller sets all turbines to full rating (5000) and then lowers
the derating of turbine 000 to 500 every other 100 seconds.
"""

def __init__(self, h_dict):
"""Initialize the controller.

Args:
h_dict (dict): The hercules input dictionary.
"""
pass

def step(self, h_dict):
"""Execute one control step.

Args:
h_dict (dict): The hercules input dictionary.

Returns:
dict: The updated hercules input dictionary.
"""
# Set deratings to full rating
h_dict["wind_farm"]["turbine_power_setpoints"] = 5000 * np.ones(
h_dict["wind_farm"]["n_turbines"]
)

# Lower t0 derating to 500 every other 100 seconds
if h_dict["time"] % 200 < 100:
h_dict["wind_farm"]["turbine_power_setpoints"][0] = 500

return h_dict


# Instantiate the controller and assign to the Hercules model
hmodel.assign_controller(ControllerToggleTurbine000(hmodel.h_dict))

# Run the simulation
hmodel.run()

hmodel.logger.info("Process completed successfully")
51 changes: 51 additions & 0 deletions examples/00b_wind_farm_scada_power/plot_outputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Plot the outputs of the simulation

import matplotlib.pyplot as plt
from hercules import HerculesOutput

# Read the Hercules output file using HerculesOutput
ho = HerculesOutput("outputs/hercules_output.h5")

# Print metadata information
print("Simulation Metadata:")
ho.print_metadata()
print()

# Create a shortcut to the dataframe
df = ho.df

# Set number of turbines
n_turbines = 3

# Define a consistent color map with 3 entries
colors = ["tab:blue", "tab:orange", "tab:green"]

fig, ax = plt.subplots(1, 1, sharex=True)


# Plot the power
for t_idx in range(3):
if f"wind_farm.turbine_powers.{t_idx:03}" in df.columns:
ax.plot(
df["time"],
df[f"wind_farm.turbine_powers.{t_idx:03}"],
label=f"Turbine {t_idx}",
color=colors[t_idx],
)

# Check if derating columns exist and plot them if they do
for t_idx in range(3):
if f"wind_farm.turbine_power_setpoints.{t_idx:03}" in df.columns:
ax.plot(
df["time"],
df[f"wind_farm.turbine_power_setpoints.{t_idx:03}"],
label=f"Power Setpoint {t_idx}",
linestyle="--",
color=colors[t_idx],
)

ax.grid(True)
ax.legend()
ax.set_xlabel("Time [s]")
ax.set_ylabel("Power [kW]")
plt.show()
19 changes: 19 additions & 0 deletions examples/inputs/00_generate_wind_history_small.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# # Generate wind history for a small farm for early examples
# Generate a small demonstration wind history using the example FLORIS model
# Additionally, generate a history of wind power data for a small farm for use
# in the example with WindFarmSCADAPower.
import floris.layout_visualization as layoutviz
import matplotlib.pyplot as plt
import numpy as np
Expand Down Expand Up @@ -100,5 +102,22 @@
print(f"First time (UTC): {df['time_utc'].iloc[0]}")
print(f"Last time (UTC): {df['time_utc'].iloc[-1]}")

# Now generate rough wind power approximations
pow_000 = 4 * ws_0**3
pow_001 = 4 * ws_1**3
pow_002 = 4 * ws_2**3

# Clip the powers to be less than the rated power
rated_power = 5000
pow_000 = np.minimum(pow_000, rated_power)
pow_001 = np.minimum(pow_001, rated_power)
pow_002 = np.minimum(pow_002, rated_power)

df["pow_000"] = pow_000
df["pow_001"] = pow_001
df["pow_002"] = pow_002

df.to_feather("scada_input.ftr")

if show_plots:
plt.show()
2 changes: 2 additions & 0 deletions hercules/utilities_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def generate_example_inputs():
produced under `examples/inputs`:

- examples/inputs/00_generate_wind_history_small.py -> wind_input_small.ftr
and scada_input.ftr
- examples/inputs/01_generate_wind_history_large.py -> wind_input_large.ftr
- examples/inputs/02_generate_solar_history.py -> solar_input.ftr

Expand Down Expand Up @@ -53,6 +54,7 @@ def ensure_example_inputs_exist():
inputs_dir / "wind_input_small.ftr",
inputs_dir / "wind_input_large.ftr",
inputs_dir / "solar_input.ftr",
inputs_dir / "scada_input.ftr",
]

if not all(p.exists() for p in expected_files):
Expand Down