-
Notifications
You must be signed in to change notification settings - Fork 19
Feature/wind consolidation #172
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
Closed
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Example 02c: Wind Farm Realistic Inflow (Direct - No Wake Modeling) | ||
|
|
||
| ## Description | ||
|
|
||
| This example demonstrates the `Wind_MesoToPowerNoAddedWakes` wake model, which assumes that wake effects are already included in the input wind data and performs no additional wake modeling. | ||
|
|
||
| The `Wind_MesoToPowerNoAddedWakes` component type uses `wake_model="no_added_wakes"` internally, which means: | ||
| - No FLORIS calculations are performed during the simulation (only at initialization to read turbine properties) | ||
| - `wind_speeds_withwakes` equals `wind_speeds_background` at all times | ||
| - Wake deficits are always zero | ||
| - Turbine dynamics (filter model or DOF1 model) still operate normally | ||
|
|
||
| This example automatically generates the necessary input files in the centralized `examples/inputs/` folder when first run. | ||
|
|
||
| ## 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 | ||
| ``` | ||
|
|
||
|
|
42 changes: 42 additions & 0 deletions
42
examples/02c_wind_farm_realistic_inflow_direct/hercules_input.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Input YAML for hercules | ||
|
|
||
| # Name | ||
| name: example_02c | ||
|
|
||
| ### | ||
| # Describe this simulation setup | ||
| description: Wind Only Realistic Inflow (Direct - No Wake Modeling) | ||
|
|
||
| dt: 1.0 | ||
| starttime_utc: "2024-06-24T16:59:08Z" # Jun 24, 2024 16:59:08 UTC (Zulu time) | ||
| endtime_utc: "2024-06-26T16:59:00Z" # ≈48 hours later (Jun 26, 2024 16:59:00 UTC) | ||
| verbose: False | ||
|
|
||
| plant: | ||
| interconnect_limit: 45000 # kW | ||
|
|
||
| wind_farm: | ||
|
|
||
| component_type: Wind_MesoToPowerNoAddedWakes | ||
| floris_input_file: ../inputs/floris_input_large.yaml | ||
| wind_input_filename: ../inputs/wind_input_large.ftr | ||
| turbine_file_name: ../inputs/turbine_filter_model.yaml | ||
| log_file_name: outputs/log_wind_sim.log | ||
| log_channels: | ||
| - power | ||
| - wind_speed_mean_background | ||
| - wind_speed_mean_withwakes | ||
| - wind_direction_mean | ||
| - turbine_powers | ||
| - wind_speeds_withwakes | ||
| - wind_speeds_background | ||
| - turbine_power_setpoints | ||
| floris_update_time_s: 300.0 # Not used but kept for interface consistency | ||
|
|
||
|
|
||
| controller: | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
53 changes: 53 additions & 0 deletions
53
examples/02c_wind_farm_realistic_inflow_direct/hercules_runscript.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| 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 power setpoints to full rating | ||
| class ControllerFullRating: | ||
| """A simple controller that sets all turbines to full rating. | ||
|
|
||
| This controller is appropriate for the direct wake model where | ||
| wake effects are already included in the input wind data. | ||
| """ | ||
|
|
||
| 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 all turbines to full rating | ||
| h_dict["wind_farm"]["turbine_power_setpoints"] = 5000 * np.ones( | ||
| h_dict["wind_farm"]["n_turbines"] | ||
| ) | ||
|
|
||
| return h_dict | ||
|
|
||
|
|
||
| # Assign the controller to the Hercules model | ||
| hmodel.assign_controller(ControllerFullRating(hmodel.h_dict)) | ||
|
|
||
| # Run the simulation | ||
| hmodel.run() | ||
|
|
||
| hmodel.logger.info("Process completed successfully") |
79 changes: 79 additions & 0 deletions
79
examples/02c_wind_farm_realistic_inflow_direct/plot_outputs.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # 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 | ||
|
|
||
| # Limit to the first 4 hours | ||
| df = df.iloc[: 3600 * 4] | ||
|
|
||
| # Set number of turbines | ||
| turbines_to_plot = [0, 8] | ||
|
|
||
| # Define a consistent color map with 9 | ||
| colors = [ | ||
| "tab:blue", | ||
| "tab:orange", | ||
| "tab:green", | ||
| "tab:red", | ||
| "tab:purple", | ||
| "tab:brown", | ||
| "tab:pink", | ||
| "tab:gray", | ||
| "tab:olive", | ||
| ] | ||
|
|
||
| fig, axarr = plt.subplots(2, 1, sharex=True) | ||
|
|
||
| # Plot the wind speeds | ||
| ax = axarr[0] | ||
| for t_idx in turbines_to_plot: | ||
| ax.plot( | ||
| df["time"], | ||
| df[f"wind_farm.wind_speeds_background.{t_idx:03}"], | ||
| label=f"Wind Speed {t_idx}", | ||
| color=colors[t_idx], | ||
| ) | ||
|
|
||
| # Note: In direct mode, wind_speeds_withwakes == wind_speeds_background | ||
|
|
||
| # Plot the mean wind speed | ||
| ax.plot( | ||
| df["time"], | ||
| df["wind_farm.wind_speed_mean_background"], | ||
| label="Mean Wind Speed", | ||
| color="black", | ||
| lw=2, | ||
| ) | ||
|
|
||
| ax.grid(True) | ||
| ax.legend() | ||
| ax.set_ylabel("Wind Speed [m/s]") | ||
| ax.set_title("Direct Wake Model (No Wake Modeling)") | ||
|
|
||
|
|
||
| # Plot the power | ||
| ax = axarr[1] | ||
| for t_idx in turbines_to_plot: | ||
| ax.plot( | ||
| df["time"], | ||
| df[f"wind_farm.turbine_powers.{t_idx:03}"], | ||
| label=f"Turbine {t_idx}", | ||
| color=colors[t_idx], | ||
| ) | ||
|
|
||
| ax.grid(True) | ||
| ax.legend() | ||
| ax.set_xlabel("Time [s]") | ||
| ax.set_ylabel("Power [kW]") | ||
| plt.show() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Requiring
floris_update_time_sfor theWind_MesoToPowerNoAddedWakescomponent type when it's explicitly not used creates unnecessary configuration burden. Consider making this parameter optional for wake models that don't use it, or document in the code why this design decision was made for interface consistency.