Skip to content

Commit

Permalink
Instantiate Turbine objects only once for each different type of turb…
Browse files Browse the repository at this point in the history
…ine.
  • Loading branch information
misi9170 committed Aug 20, 2024
1 parent a6f0f2f commit 7a1a0d3
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions floris/core/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ class Farm(BaseClass):

internal_turbine_library: Path = field(init=False, default=default_turbine_library_path)

# Private attributes
_turbine_types: List = field(init=False, validator=iter_validator(list, str))
_turbine_definition_cache: dict = field(init=False)

def __attrs_post_init__(self) -> None:
# Turbine definitions can be supplied in three ways:
# - A string selecting a turbine in the floris turbine library
Expand All @@ -134,21 +138,27 @@ def __attrs_post_init__(self) -> None:
# This allows to read the yaml input files once rather than every time they're given.
# In other words, if the turbine type is already in the cache, skip that iteration of
# the for-loop.

# TODO: How can we give each one a different name, to avoid the issue raised in #864?
turbine_definition_cache = {}
# Is this loop slow if turbine_type is long?
for t in self.turbine_type:
# If a turbine type is a dict, then it was either preprocessed by the yaml
# library to resolve the "!include" or it was set in a script as a dict. In either case,
# add an entry to the cache
if isinstance(t, dict):
# TODO: If this check was more robust, could avoid needing to change the name of
# each turbine. Would then need to update the name somehow to handle the case where
# the "turbine_type" key is the same
if t["turbine_type"] in turbine_definition_cache:
continue
continue # Skip t if already loaded
turbine_definition_cache[t["turbine_type"]] = t

# If a turbine type is a string, then it is expected in the internal or external
# turbine library
if isinstance(t, str):
if t in turbine_definition_cache:
continue
continue # Skip t if already loaded

# Check if the file exists in the internal and/or external library
internal_fn = (self.internal_turbine_library / t).with_suffix(".yaml")
Expand Down Expand Up @@ -184,25 +194,28 @@ def __attrs_post_init__(self) -> None:
# types must be used. If we modify that directly and change its shape, recreating this
# class with a different layout but not a new self.turbine_type could cause the data
# to be out of sync.
_turbine_types = [
self._turbine_types = [
copy.deepcopy(t["turbine_type"]) if isinstance(t, dict) else t
for t in self.turbine_type
]

# If 1 turbine definition is given, expand to N turbines; this covers a 1-turbine
# farm and 1 definition for multiple turbines
if len(_turbine_types) == 1:
_turbine_types *= self.n_turbines
if len(self._turbine_types) == 1:
self._turbine_types *= self.n_turbines

# Check that turbine definitions contain any v3 keys
for t in _turbine_types:
check_turbine_definition_for_v3_keys(turbine_definition_cache[t])
for _, v in turbine_definition_cache.items():
check_turbine_definition_for_v3_keys(v)

# Map each turbine definition to its index in this list
self.turbine_definitions = [
copy.deepcopy(turbine_definition_cache[t]) for t in _turbine_types
copy.deepcopy(turbine_definition_cache[t]) for t in self._turbine_types
]

# Save the turbine_definition_cache for faster operation when generating the turbine_map
self._turbine_definition_cache = turbine_definition_cache

@layout_x.validator
def check_x(self, attribute: attrs.Attribute, value: Any) -> None:
if len(value) != len(self.layout_y):
Expand Down Expand Up @@ -285,7 +298,13 @@ def construct_turbine_correct_cp_ct_for_tilt(self):
)

def construct_turbine_map(self):
self.turbine_map = [Turbine.from_dict(turb) for turb in self.turbine_definitions]
# The line below is slow and often unnecessary. We should just be loading
# each different turbine type, _not_ each turbine.
#self.turbine_map = [Turbine.from_dict(turb) for turb in self.turbine_definitions]
turbine_map_unique = {
k: Turbine.from_dict(v) for k, v in self._turbine_definition_cache.items()
}
self.turbine_map = [turbine_map_unique[k] for k in self._turbine_types]

def construct_turbine_thrust_coefficient_functions(self):
self.turbine_thrust_coefficient_functions = {
Expand Down

0 comments on commit 7a1a0d3

Please sign in to comment.