Skip to content

Commit

Permalink
Issue alert if calc wake needs to be run (#432)
Browse files Browse the repository at this point in the history
* first pass

* switch to private and check on get_farm_power

* bugfix

* Check BaseClass state for flow control in FI

* Remove failing example

* FIx missing import

* Reduce state-enum to three states

Co-authored-by: Rafael M Mudafort <rafmudaf@gmail.com>
  • Loading branch information
paulf81 and rafmudaf authored Jul 27, 2022
1 parent cb1f54f commit 3cca335
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 4 deletions.
2 changes: 1 addition & 1 deletion floris/simulation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# that should be included in the simulation package.
# Since some of these depend on each other, the order
# that they are listed here does matter.
from .base import BaseClass, BaseModel
from .base import BaseClass, BaseModel, State
from .turbine import Turbine, Ct, power, axial_induction, average_velocity
from .farm import Farm
from .grid import Grid, TurbineGrid, FlowFieldGrid, FlowFieldPlanarGrid
Expand Down
10 changes: 10 additions & 0 deletions floris/simulation/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""

from abc import ABC, abstractmethod
from enum import Enum
from typing import Any, Dict, Final

import attrs
Expand All @@ -26,11 +27,20 @@
from floris.logging_manager import LoggerBase


class State(Enum):
UNINITIALIZED = 0
INITIALIZED = 1
USED = 2


class BaseClass(LoggerBase, FromDictMixin):
"""
BaseClass object class. This class does the logging and MixIn class inheritance.
"""

state = State.UNINITIALIZED


@classmethod
def get_model_defaults(cls) -> Dict[str, Any]:
"""Produces a dictionary of the keyword arguments and their defaults.
Expand Down
4 changes: 3 additions & 1 deletion floris/simulation/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
NDArrayFloat
)
from floris.utilities import Vec3, load_yaml
from floris.simulation import BaseClass
from floris.simulation import BaseClass, State
from floris.simulation import Turbine


Expand Down Expand Up @@ -93,6 +93,7 @@ def initialize(self, sorted_indices):
sorted_indices[:, :, :, 0, 0],
axis=2,
)
self.state = State.INITIALIZED

def construct_hub_heights(self):
self.hub_heights = np.array([turb['hub_height'] for turb in self.turbine_definitions])
Expand Down Expand Up @@ -148,6 +149,7 @@ def finalize(self, unsorted_indices):
self.TSRs = np.take_along_axis(self.TSRs_sorted, unsorted_indices[:,:,:,0,0], axis=2)
self.pPs = np.take_along_axis(self.pPs_sorted, unsorted_indices[:,:,:,0,0], axis=2)
self.turbine_type_map = np.take_along_axis(self.turbine_type_map_sorted, unsorted_indices[:,:,:,0,0], axis=2)
self.state.USED

@property
def n_turbines(self):
Expand Down
7 changes: 5 additions & 2 deletions floris/simulation/floris.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@
from floris.utilities import load_yaml

import floris.logging_manager as logging_manager
from floris.type_dec import FromDictMixin
from floris.simulation import (
BaseClass,
Farm,
WakeModelManager,
FlowField,
Grid,
TurbineGrid,
FlowFieldGrid,
FlowFieldPlanarGrid,
State,
sequential_solver,
cc_solver,
turbopark_solver,
Expand All @@ -40,7 +41,7 @@


@define
class Floris(logging_manager.LoggerBase, FromDictMixin):
class Floris(BaseClass):
"""
Top-level class that describes a Floris model and initializes the
simulation. Use the :py:class:`~.simulation.farm.Farm` attribute to
Expand Down Expand Up @@ -138,6 +139,7 @@ def initialize_domain(self):
# Initialize farm quantities
self.farm.initialize(self.grid.sorted_indices)

self.state.INITIALIZED

def steady_state_atmospheric_condition(self):
"""Perform the steady-state wind farm wake calculations. Note that
Expand Down Expand Up @@ -198,6 +200,7 @@ def finalize(self):
# the user-supplied order of things.
self.flow_field.finalize(self.grid.unsorted_indices)
self.farm.finalize(self.grid.unsorted_indices)
self.state = State.USED

## I/O

Expand Down
12 changes: 12 additions & 0 deletions floris/tools/floris_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from floris.type_dec import NDArrayFloat
from floris.simulation import Floris
from floris.logging_manager import LoggerBase

from floris.simulation import State

from floris.tools.cut_plane import CutPlane
from floris.simulation.turbine import Ct, power, axial_induction, average_velocity

Expand Down Expand Up @@ -568,6 +571,11 @@ def get_turbine_powers(self) -> NDArrayFloat:
Returns:
NDArrayFloat: [description]
"""

# Confirm calculate wake has been run
if self.floris.state is not State.USED:
raise RuntimeError(f"Can't run function `FlorisInterface.get_turbine_powers` without first running `FlorisInterface.calculate_wake`.")

turbine_powers = power(
air_density=self.floris.flow_field.air_density,
velocities=self.floris.flow_field.u,
Expand Down Expand Up @@ -631,6 +639,10 @@ def get_farm_power(
# for turbine in self.floris.farm.turbines:
# turbine.use_turbulence_correction = use_turbulence_correction

# Confirm calculate wake has been run
if self.floris.state is not State.USED:
raise RuntimeError(f"Can't run function `FlorisInterface.get_turbine_powers` without running `FlorisInterface.calculate_wake`.")

turbine_powers = self.get_turbine_powers()
return np.sum(turbine_powers, axis=2)

Expand Down

0 comments on commit 3cca335

Please sign in to comment.