Skip to content

Commit

Permalink
Update UncertainFlorisModel to work with new Parallel framework (#983)
Browse files Browse the repository at this point in the history
* Update uncertain floris model to accept par floris

* Raise an error in old parallel floris model blocking passing in uncertain floris model

* Add an example of parallelized uncertain floris
  • Loading branch information
paulf81 authored Sep 27, 2024
1 parent 28a5cff commit a88fc87
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""Example: Uncertain Model With Parallelization
This example demonstrates how to combined the parallelized model with the uncertain model
"""

import matplotlib.pyplot as plt
import numpy as np

from floris import (
FlorisModel,
TimeSeries,
UncertainFlorisModel,
)
from floris.parallel_floris_model_2 import ParallelFlorisModel


# Following the refactoring of ParallelFlorisModel, the UncertainFlorisModel can be
# parallelized by passing the ParallelFlorisModel as the model to be run. This example
# demonstrates the usage. Demonstrating the result obtained from the UncertainFlorisModel
# with and without parallelization is the same. The results are compared to the nomimal
# results.

# Instantiate a FlorisModel and ParallelFlorisModel using the GCH model
fmodel = FlorisModel("../inputs/gch.yaml")
pfmodel = ParallelFlorisModel("../inputs/gch.yaml")

# Use the above model to declare a serial and parallel UncertainFlorisModel
ufmodel = UncertainFlorisModel(fmodel)
pufmodel = UncertainFlorisModel(pfmodel)


# Define an inflow where wind direction is swept while
# wind speed and turbulence intensity are held constant
wind_directions = np.arange(240.0, 300.0, 1.0)
time_series = TimeSeries(
wind_directions=wind_directions,
wind_speeds=8.0,
turbulence_intensities=0.06,
)

# Define a two turbine farm and apply the inflow
D = 126.0
layout_x = np.array([0, D * 6])
layout_y = [0, 0]

# Apply to fmodel, ufmodel, and pufmodel
fmodel.set(
layout_x=layout_x,
layout_y=layout_y,
wind_data=time_series,
)

ufmodel.set(
layout_x=layout_x,
layout_y=layout_y,
wind_data=time_series,
)

pufmodel.set(
layout_x=layout_x,
layout_y=layout_y,
wind_data=time_series,
)

# Run the models
fmodel.run()
ufmodel.run()
pufmodel.run()

# Collect the farm power results from each model
farm_powers_nom = fmodel.get_farm_power() / 1e3
farm_powers_unc = ufmodel.get_farm_power() / 1e3
farm_powers_punc = pufmodel.get_farm_power() / 1e3

# Compare the results
fig, ax = plt.subplots()
ax.plot(wind_directions, farm_powers_nom.flatten(), 'k-', label="Nominal power")
ax.plot(wind_directions, farm_powers_unc.flatten(), 'bs-', label="Uncertain power")
ax.plot(wind_directions, farm_powers_punc.flatten(), 'r.--', label="Parallel uncertain power")
ax.grid(True)
ax.legend()
ax.set_xlabel("Wind Direction (deg)")
ax.set_ylabel("Power (kW)")

plt.show()
8 changes: 8 additions & 0 deletions floris/parallel_floris_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ def __init__(
"Please use 'concurrent', 'multiprocessing' or 'mpi4py'."
)

# Raise error if uncertain model is passed in and refer to new parallel_floris_model_2
if isinstance(fmodel, UncertainFlorisModel):
raise UserWarning(
"UncertainFlorisModel is not supported in this version of ParallelFlorisModel. "
"Please use the new version of ParallelFlorisModel (parallel_floris_model_2) "
"for UncertainFlorisModel."
)

# Initialize floris object and copy common properties
if isinstance(fmodel, FlorisModel):
self.fmodel = fmodel.copy()
Expand Down
25 changes: 14 additions & 11 deletions floris/uncertain_floris_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from floris import FlorisModel
from floris.core import State
from floris.logging_manager import LoggingManager
from floris.parallel_floris_model_2 import ParallelFlorisModel
from floris.type_dec import (
floris_array_converter,
NDArrayBool,
Expand Down Expand Up @@ -46,13 +47,10 @@ class UncertainFlorisModel(LoggingManager):
conditions from within the expanded set of conditions are run.
Args:
configuration (:py:obj:`dict`): The Floris configuration dictionary or YAML file.
The configuration should have the following inputs specified.
- **flow_field**: See `floris.simulation.flow_field.FlowField` for more details.
- **farm**: See `floris.simulation.farm.Farm` for more details.
- **turbine**: See `floris.simulation.turbine.Turbine` for more details.
- **wake**: See `floris.simulation.wake.WakeManager` for more details.
- **logging**: See `floris.simulation.core.Core` for more details.
configuration (dict | str | Path | FlorisModel | ParallelFlorisModel): The configuration
for the wind farm. This can be a dictionary, a path to a yaml file, or a FlorisModel
or ParallelFlorisModel object. If dict, str or Path, a new FlorisModel object is
created. If a FlorisModel or ParallelFlorisModel object a copy of the object is made.
wd_resolution (float, optional): The resolution of wind direction for generating
gaussian blends, in degrees. Defaults to 1.0.
ws_resolution (float, optional): The resolution of wind speed, in m/s. Defaults to 1.0.
Expand All @@ -75,7 +73,7 @@ class UncertainFlorisModel(LoggingManager):

def __init__(
self,
configuration: dict | str | Path,
configuration: dict | str | Path | FlorisModel | ParallelFlorisModel,
wd_resolution=1.0, # Degree
ws_resolution=1.0, # m/s
ti_resolution=0.01,
Expand Down Expand Up @@ -109,13 +107,18 @@ def __init__(
self.weights = self._get_weights(self.wd_std, self.wd_sample_points)

# Instantiate the un-expanded FlorisModel
self.fmodel_unexpanded = FlorisModel(configuration)
if isinstance(configuration, (FlorisModel, ParallelFlorisModel)):
self.fmodel_unexpanded = configuration.copy()
elif isinstance(configuration, (dict, str, Path)):
self.fmodel_unexpanded = FlorisModel(configuration)
else:
raise ValueError(
"configuration must be a FlorisModel, ParallelFlorisModel, dict, str, or Path"
)

# Call set at this point with no arguments so ready to run
self.set()

# Instantiate the expanded FlorisModel
# self.core_interface = FlorisModel(configuration)

def set(
self,
Expand Down

0 comments on commit a88fc87

Please sign in to comment.