Source code for opentidalfarm.farm.rectangular_farm

from dolfin import FunctionSpace
import dolfin_adjoint
from .farm import Farm

[docs] class RectangularFarm(Farm): """Extends :py:class:`Farm`. Defines a rectangular Farm. This class holds the turbines within a rectangular site. """ def __init__(self, domain, site_x_start, site_x_end, site_y_start, site_y_end, turbine=None, site_ids=None, order=2, n_time_steps=None): """Initializes an empty rectangular farm with the given dimensions. :param mesh: The name of the mesh file to use, e.g. 'mesh.xml' if the file is located at `./mesh.xml`. :type mesh: string :param site_x_start: The minimum x-coordinate for the site. :type site_x_start: float :param site_x_end: The maximum x-coordinate for the site. :type site_x_end: float :param site_y_start: The minimum y-coordinate for the site. :type site_y_start: float :param site_y_end: The maximum y-coordinate for the site. :type site_y_end: float :param n_time_steps: Only used with dynamic friction and should be calculated with problem_parameters.n_time_steps. """ # Initialize the base clas super(RectangularFarm, self).__init__(domain, turbine, site_ids, n_time_steps=n_time_steps) self.n_time_steps = n_time_steps # Create a turbine function space and set the function space in the # cache. self._turbine_function_space = FunctionSpace(self.domain.mesh, "CG", order) self.turbine_cache.set_function_space(self._turbine_function_space) # Store site dimensions. self._site_x_start = site_x_start self._site_y_start = site_y_start self._site_x_end = site_x_end self._site_y_end = site_y_end @property def site_x_start(self): """The minimum x-coordinate of the site. :getter: Returns the minimum x-coordinate of the site. :type: float """ return self._site_x_start @property def site_y_start(self): """The minimum y-coordinate of the site. :getter: Returns the minimum y-coordinate of the site. :type: float """ return self._site_y_start @property def site_x_end(self): """The maximum x-coordinate of the site. :getter: Returns the maximum x-coordinate of the site. :type: float """ return self._site_x_end @property def site_y_end(self): """The maximum y-coordinate of the site. :getter: Returns the maximum y-coordinate of the site. :type: float """ return self._site_y_end
[docs] def add_regular_turbine_layout(self, num_x, num_y, x_start=None, x_end=None, y_start=None, y_end=None): """Adds a rectangular turbine layout to the farm. A rectangular turbine layout with turbines evenly spread out in each direction across the given rectangular site. :param turbine: Defines the type of turbine to add to the farm. :type turbine: Turbine object. :param num_x: The number of turbines placed in the x-direction. :type num_x: int :param num_y: The number of turbines placed in the y-direction. :type num_y: int :param x_start: The minimum x-coordinate of the site. :type x_start: float :param x_end: The maximum x-coordinate of the site. :type x_end: float :param y_start: The minimum y-coordinate of the site. :type y_start: float :param y_end: The maximum y-coordinate of the site. :type y_end: float :raises: ValueError """ # Get default parameters: if x_start is None: x_start = self.site_x_start if y_start is None: y_start = self.site_y_start if x_end is None: x_end = self.site_x_end if y_end is None: y_end = self.site_y_end return super(RectangularFarm, self)._regular_turbine_layout( num_x, num_y, x_start, x_end, y_start, y_end)
[docs] def add_staggered_turbine_layout(self, num_x, num_y, x_start=None, x_end=None, y_start=None, y_end=None): """Adds a rectangular, staggered turbine layout to the farm. A rectangular turbine layout with turbines evenly spread out in each direction across the given rectangular site. :param turbine: Defines the type of turbine to add to the farm. :type turbine: Turbine object. :param num_x: The number of turbines placed in the x-direction. :type num_x: int :param num_y: The number of turbines placed in the y-direction (will be one less on every second row). :type num_y: int :param x_start: The minimum x-coordinate of the site. :type x_start: float :param x_end: The maximum x-coordinate of the site. :type x_end: float :param y_start: The minimum y-coordinate of the site. :type y_start: float :param y_end: The maximum y-coordinate of the site. :type y_end: float :raises: ValueError """ # Get default parameters: if x_start is None: x_start = self.site_x_start if y_start is None: y_start = self.site_y_start if x_end is None: x_end = self.site_x_end if y_end is None: y_end = self.site_y_end return super(RectangularFarm, self)._staggered_turbine_layout( num_x, num_y, x_start, x_end, y_start, y_end)
[docs] def add_lhs_turbine_layout(self, number_turbines, x_start=None, x_end=None, y_start=None, y_end=None): """Adds to the farm a turbine layout based upon a latin hypercube sampling of the turbine area. :param turbine: Defines the type of turbine to add to the farm. :type turbine: Turbine object. :param number_turbines: The number of turbines to be placed. :type number_turbines: int :param x_start: The minimum x-coordinate of the site. :type x_start: float :param x_end: The maximum x-coordinate of the site. :type x_end: float :param y_start: The minimum y-coordinate of the site. :type y_start: float :param y_end: The maximum y-coordinate of the site. :type y_end: float :raises: ValueError """ # Get default parameters: if x_start is None: x_start = self.site_x_start if y_start is None: y_start = self.site_y_start if x_end is None: x_end = self.site_x_end if y_end is None: y_end = self.site_y_end return super(RectangularFarm, self)._lhs_turbine_layout( number_turbines, x_start, x_end, y_start, y_end)
[docs] def site_boundary_constraints(self): """Returns the site boundary constraints for a rectangular site. These constraints ensure that the turbine positions remain within the turbine site during optimisation. :raises: ValueError :returns: Tuple of lists of length equal to the twice the number of turbines. Each list contains dolfin_adjoint.Constant objects of the upper and lower bound coordinates. """ # Check we have deployed some turbines in the farm. n_turbines = len(self.turbine_positions) if (n_turbines < 1): raise ValueError("You must deploy turbines before computing " "position constraints.") radius = self._turbine_specification.radius # Get the lower and upper bounds. lower_x = self.site_x_start+radius lower_y = self.site_y_start+radius upper_x = self.site_x_end-radius upper_y = self.site_y_end-radius # Check the site is large enough. if upper_x < lower_x or upper_y < lower_y: raise ValueError("Lower bound is larger than upper bound. Is your " "domain large enough?") # The control variable is ordered as [t1_x, t1_y, t2_x, t2_y, t3_x, ...] lower_bounds = n_turbines*[dolfin_adjoint.Constant(lower_x), dolfin_adjoint.Constant(lower_y)] upper_bounds = n_turbines*[dolfin_adjoint.Constant(upper_x), dolfin_adjoint.Constant(upper_y)] return lower_bounds, upper_bounds
def friction_constraints(self, lower_bounds=0., upper_bounds=None): if (upper_bounds == None): upper_bounds = upper_bounds = self._turbine_specification.friction n_turbines = len(self.turbine_positions) if (self.n_time_steps == None): self.n_time_steps = 0 elif (not self._turbine_specification.controls.dynamic_friction): self.n_time_steps = 0 lower_bounds = (self.n_time_steps+1)*n_turbines*\ [dolfin_adjoint.Constant(lower_bounds)] upper_bounds = (self.n_time_steps+1)*n_turbines*\ [dolfin_adjoint.Constant(upper_bounds)] return lower_bounds, upper_bounds def constraints(self, lower_friction_bounds=0, upper_friction_bounds=None): lower_bounds = [] upper_bounds = [] if (self._turbine_specification.controls.friction or self._turbine_specification.controls.dynamic_friction): lower_bounds, upper_bounds = self.friction_constraints(lower_friction_bounds, upper_friction_bounds) if (self._turbine_specification.controls.position): lower_pos_bounds, upper_pos_bounds = self.site_boundary_constraints() lower_bounds += lower_pos_bounds upper_bounds += upper_pos_bounds return lower_bounds, upper_bounds