Source code for ard.offshore.mooring_design_constant_depth

import numpy as np

import openmdao.api as om

import math

import ard.geographic


[docs] def generate_anchor_points( center: np.ndarray, length: float, rotation_deg: float, N: int ) -> np.ndarray: """Generates anchor points equally spaced around the platform Args: center (np.ndarray): x and y of platform in km length (float): desired horizontal anchor length in km rotation_deg (float): rotation in deg. counter-clockwise from east N (int): number of anchors Returns: np.ndarray: array of size N by 2 containing the x and y positions of each anchor """ cx, cy = center angle_step = 360 / N lines = np.zeros([N, 2]) for i in range(N): angle_deg = rotation_deg + i * angle_step angle_rad = math.radians(angle_deg) x = cx + length * math.cos(angle_rad) y = cy + length * math.sin(angle_rad) lines[i, 0] = x lines[i, 1] = y return lines
[docs] def simple_mooring_design( phi_platform: np.ndarray, x_turbines: np.ndarray, y_turbines: np.ndarray, length: float, N_turbines: int, N_anchors: int, ) -> tuple[np.ndarray]: """_summary_ Args: phi_platform (np.ndarray): counterclockwise rotation from east in deg. for each platform x_turbines (np.ndarray): list of platform/turbine easting in km y_turbines (np.ndarray): list of platform/turbine northing in km length (float): desired horizontal anchor length in km N_turbines (int): number of wind turbines in the farm N_anchors (int): number of anchors per turbine/platform Returns: tuple[np.ndarray]: x locations of anchors, y locations of anchors, each array of shape N_turbines by N_anchors """ x_anchors = np.zeros([N_turbines, N_anchors]) y_anchors = np.zeros_like(x_anchors) for i, (x, y) in enumerate(zip(x_turbines, y_turbines)): center = (x, y) anchors = generate_anchor_points( center=center, length=length, rotation_deg=phi_platform[i], N=N_anchors ) for j in range(N_anchors): x_anchors[i, j] = anchors[j, 0] y_anchors[i, j] = anchors[j, 1] return x_anchors, y_anchors
[docs] class ConstantDepthMooringDesign(om.ExplicitComponent): """ A class to create a constant-depth simplified mooring design for a floating offshore wind farm. This is a class that should be used to generate a floating offshore wind farm's collective mooring system. Options ------- modeling_options : dict a modeling options dictionary (inherited from `FarmAeroTemplate`) wind_query : floris.wind_data.WindRose a WindQuery objects that specifies the wind conditions that are to be computed bathymetry_data : ard.geographic.BathymetryData a BathymetryData object to specify the bathymetry mesh/sampling Inputs ------ phi_platform : np.ndarray a 1D numpy array indicating the cardinal direction angle of the mooring orientation, with length `N_turbines` x_turbines : np.ndarray a 1D numpy array indicating the x-dimension locations of the turbines, with length `N_turbines` (mirrored w.r.t. `FarmAeroTemplate`) y_turbines : np.ndarray a 1D numpy array indicating the y-dimension locations of the turbines, with length `N_turbines` (mirrored w.r.t. `FarmAeroTemplate`) thrust_turbines : np.ndarray an array of the wind turbine thrust for each of the turbines in the farm across all of the conditions that have been queried on the wind rose (`N_turbines`, `N_wind_conditions`) Outputs ------- x_anchors : np.ndarray a 1D numpy array indicating the x-dimension locations of the mooring system anchors, with shape `N_turbines` x `N_anchors` y_anchors : np.ndarray a 1D numpy array indicating the y-dimension locations of the mooring system anchors, with shape `N_turbines` x `N_anchors` """
[docs] def initialize(self): """Initialization of the OpenMDAO component.""" self.options.declare("modeling_options") # farm power wind conditions query (not necessarily a full wind rose) self.options.declare("wind_query") # currently I'm thinking of sea bed conditions as a class, see above self.options.declare("bathymetry_data") # BatyhmetryData object
[docs] def setup(self): """Setup of the OpenMDAO component.""" # load modeling options self.modeling_options = self.options["modeling_options"] self.N_turbines = self.modeling_options["layout"]["N_turbines"] self.N_anchors = self.modeling_options["platform"]["N_anchors"] self.min_mooring_line_length_m = self.modeling_options["platform"][ "min_mooring_line_length_m" ] # get the number of wind conditions (for thrust measurements) if self.options["wind_query"] is not None: self.N_wind_conditions = self.options["wind_query"].N_conditions # MANAGE ADDITIONAL LATENT VARIABLES HERE!!!!! # set up inputs and outputs for mooring system self.add_input( "phi_platform", np.zeros((self.N_turbines,)), units="deg" ) # cardinal direction of the mooring platform orientation self.add_input( "x_turbines", np.zeros((self.N_turbines,)), units="km" ) # x location of the mooring platform in km w.r.t. reference coordinates self.add_input( "y_turbines", np.zeros((self.N_turbines,)), units="km" ) # y location of the mooring platform in km w.r.t. reference coordinates if self.options["wind_query"] is not None: self.add_input( "thrust_turbines", np.zeros((self.N_turbines, self.N_wind_conditions)), units="kN", ) # turbine thrust coming from each wind direction # ADD ADDITIONAL (DESIGN VARIABLE) INPUTS HERE!!!!! self.add_output( "x_anchors", np.zeros((self.N_turbines, self.N_anchors)), units="km", ) # x location of the mooring platform in km w.r.t. reference coordinates self.add_output( "y_anchors", np.zeros((self.N_turbines, self.N_anchors)), units="km", ) # y location of the mooring platform in km w.r.t. reference coordinates
[docs] def setup_partials(self): """Derivative setup for the OpenMDAO component.""" # the default (but not preferred!) derivatives are FDM self.declare_partials("*", "*", method="fd")
[docs] def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): """Computation for the OpenMDAO component.""" # unpack the working variables phi_platform = inputs["phi_platform"] x_turbines = inputs["x_turbines"] y_turbines = inputs["y_turbines"] # thrust_turbines = inputs["thrust_turbines"] # # BEGIN: REPLACE ME x_anchors, y_anchors = simple_mooring_design( phi_platform=phi_platform, x_turbines=x_turbines, y_turbines=y_turbines, length=self.min_mooring_line_length_m * 1e-3, # convert to km N_turbines=self.N_turbines, N_anchors=self.N_anchors, ) # END REPLACE ME # replace the below with the final anchor locations... outputs["x_anchors"] = x_anchors outputs["y_anchors"] = y_anchors