Source code for opentidalfarm.turbines.thrust_turbine

from .base_turbine import BaseTurbine
from .controls import Controls
from dolfin import *

[docs]class ThrustTurbine(BaseTurbine):
""" Create a turbine that is modelled as a bump of bottom friction.
In addition this turbine implements cut in and out speeds for the
power production.

This turbine introduces a non-linearity, which is handled explicitly. """
def __init__(self,
friction=1.0,
diameter=20.,
swept_diameter=20.,
c_t_design=0.6,
cut_in_speed=1,
cut_out_speed=2.5,
water_depth = None,
upwind_correction=True,
minimum_distance=None,
controls=Controls(position=True)):

# Check for a given minimum distance.
if minimum_distance is None: minimum_distance=diameter*1.5
# Initialize the base class.
super(ThrustTurbine, self).__init__(friction=friction,
diameter=diameter,
minimum_distance=minimum_distance,
controls=controls,
thrust=True)

# To parametrise a square 2D plan-view turbine to characterise a
# realistic tidal turbine with a circular swept area in the section
# plane we assume that the specified 2D turbine diameter is equal to the
# circular swept diameter
self.swept_diameter = swept_diameter
self.c_t_design = c_t_design
self.cut_in_speed = cut_in_speed
self.cut_out_speed = cut_out_speed
self.upwind_correction = upwind_correction

# Check that the parameter choices make some sense - these won't break
# the simulation but may give unexpected results if the choice isn't
# understood.
if self.swept_diameter != self.diameter:
log(INFO, 'Warning - swept_diameter and plan_diameter are not equal')
if self.friction != 1.0:
log(INFO, 'Warning - for accurate parametrisation friction should \
be set to 1')

swept_area = pi * (swept_diameter/2)**2
plan_area = diameter**2
# We can bundle all this up into a constant (i.e. independent of u) in
# a stunning display of imaginative thinking we will call this the
# turbine_parametrisation_constant
self.turbine_parametrisation_constant = 0.5 * swept_area / \
((self._unit_bump_int/4) * plan_area)
if upwind_correction:
# This is a correction for the fact that C_t (c_t_design)
# is defined as the thrust coefficient relative to the *upstream*
# velocity. Since the drag term is computed from the local depth-averaged
# velocity (which is lower) we need to compensate for this. The theory
# behind this is explained in http://arxiv.org/abs/1506.03611

if water_depth is None:
raise ValueError("The water_depth needs to be specifed for the upwind correction")
# the "numerical" cross-section this is the cross section over which
# the drag is effectively applied
effective_area = diameter*water_depth

self.turbine_parametrisation_constant *= 4./(1.+sqrt(1-swept_area/effective_area*self.c_t_design))**2

[docs]    def less_than_cut_out(self, u_mag):
""" The function describing the thrust coefficient for velocities <
cut_out_speed
"""
return self.c_t_design * ((tanh(10*(u_mag-self.cut_in_speed))+1)/2)

[docs]    def greater_than_cut_out(self, u_mag):
""" The function describing the thrust coefficient for velocities >
cut_out_speed
"""
return self.c_t_design * (self.cut_out_speed / u_mag)

[docs]    def compute_C_t(self, u_mag):
""" Return C_t as a function of u_mag
"""
return conditional(gt(u_mag, self.cut_out_speed),
self.greater_than_cut_out(u_mag),
self.less_than_cut_out(u_mag))