# Source code for opentidalfarm.functionals.power_functionals

#"""
#.. module:: Power Functionals
#   :synopsis: This module contains the functional classes which compute the
#       power extracted by an array.
#"""

from dolfin import dot, Constant, dx, assemble, conditional
from ..helpers import smooth_uflmin
from .prototype_functional import PrototypeFunctional

[docs]class PowerFunctional(PrototypeFunctional):
r""" Implements a power functional of the form:

.. math:: J(u, m) = \int \rho  c_t ||sq(u)||^{1.5}~ dx,

where :math:c_t is the friction due to the turbines, and
:math:sq(u) is the squared velocity that takes into account the
cut-in/out behaviour of the turbines, i.e.

.. math:: sq(u) =
\begin{cases}
eps \|u\|^2 & \text{if } \|u\| < {cut\_in\_speed} \\
(cut\_out\_speed)^2 & \text{if } \|u\| > {cut\_out\_speed} \\
\|u\|^2 & \text{else.}
\end{cases}

:param problem: The problem for which the functional is being computed.
:type problem: Instance of the problem class.
:param cut_in_speed: The turbine's cut in speed (Default: None).
:type cut_in_speed: float
:param cut_out_speed: The turbine's cut out speed (Default: None).
:type cut_out_speed: float
:param eps: The turbine's cut in speed slope (Default: 1e-10).
:type esp: float
"""

def __init__(self, problem, cut_in_speed=None, cut_out_speed=None, eps=1e-10):

self.farm = problem.parameters.tidal_farm
self.rho = problem.parameters.rho
self.farm.update()

self._cut_in_speed = cut_in_speed
self._cut_out_speed = cut_out_speed
self._eps = eps

[docs]    def Jt(self, state, turbine_field):
""" Computes the power output of the farm.

:param state: Current solution state
:type state: dolfin.Function
:param turbine_field: Turbine friction field
:type turbine_field: dolfin.Function

"""
return self.power(state, turbine_field)*self.farm.site_dx

[docs]    def power(self, state, turbine_field):
""" Computes the power field over the domain.

:param state: Current solution state.
:type state: dolfin.Function
:param turbine_field: Turbine friction field
:type turbine_field: dolfin.Function

"""
return self.rho * turbine_field * self._speed_squared(state) ** 1.5

[docs]    def Jt_individual(self, state, i):
""" Computes the power output of the i'th turbine.

:param state: Current solution state
:type state: dolfin.Function
:param i: refers to the i'th turbine
:type i: Integer

"""
turbine_field_individual = \
self.farm.turbine_cache['turbine_field_individual'][i]
return assemble(self.power(state, turbine_field_individual) *
self.farm.site_dx)

[docs]    def force(self, state, turbine_field):
""" Computes the force field over turbine field

:param state: Current solution state.
:type state: dolfin.Function
:param turbine_field: Turbine friction field
:type turbine_field: dolfin.Function

"""
return self.rho * turbine_field * self._speed_squared(state)

[docs]    def force_individual(self, state, i):
""" Computes the total force on the i'th turbine

:param state: Current solution state
:type state: dolfin.Function
:param i: refers to the i'th turbine
:type i: Integer

"""
turbine_field_individual = \
self.farm.turbine_cache['turbine_field_individual'][i]
return assemble(self.force(state, turbine_field_individual) * self.farm.site_dx)

def _speed_squared(self, state):
""" The velocity speed with turbine cut in and out speed limits """

speed_sq = dot(state, state) + dot(state, state)

if self._cut_in_speed is not None:
speed_sq *= conditional(speed_sq < self._cut_in_speed**2, self._eps, 1)

if self._cut_out_speed is not None:
speed_sq = conditional(speed_sq > self._cut_out_speed**2,
self._cut_out_speed**2, speed_sq)

return speed_sq