Source code for ard.geographic.geomorphology

from os import PathLike
from pathlib import Path

import numpy as np
from scipy.interpolate import SmoothBivariateSpline

import openmdao.api as om


[docs] class GeomorphologyGridData: """ A class to represent gridded geomorphology data for a given wind farm site domain. Represents either bathymetry data for offshore sites or topography data for onshore sites. """ # alias for meshed data, and promote dimension to 2 x_data = np.atleast_2d([0.0]) # x location in km y_data = np.atleast_2d([0.0]) # y location in km z_data = np.atleast_2d([0.0]) # depth in m # alias for meshed material data, promote dimension to 2 x_material_data = np.atleast_2d([0.0]) # x location in km of material datapoint y_material_data = np.atleast_2d([0.0]) # y location in km of material datapoint material_data = np.atleast_2d(["soil"]) # bed material at each point sea_level = 0.0 # sea level in m _interpolator_device = None # placeholder for interpolator (for depth evaluation)
[docs] def check_valid_geomorphology(self): assert self.x_data.ndim == 2, "data must be 2D" # make sure it's 2D first assert np.all( self.x_data.shape == self.y_data.shape ), "x and y data must be the same shape" assert np.all( self.x_data.shape == self.z_data.shape ), "x and depth data must be the same shape" return True
[docs] def check_valid_material(self): assert ( self.x_material_data.ndim == 2 ), "data must be 2D" # make sure it's 2D first assert np.all( self.x_material_data.shape == self.y_material_data.shape ), "x and y material data must be the same shape" assert np.all(self.x_material_data.shape == self.material_data.shape) or ( self.material_data.size == 1 ), "x and material data must be the same shape or material data must be a singleton" return True
[docs] def get_shape(self): """ Get the shape of the geomorphology data. Returns ------- tuple The shape of the geomorphology data. """ self.check_valid_geomorphology() # ensure that the current data is valid return self.z_data.shape # data shape
[docs] def get_material_shape(self): """ Get the shape of the material data. Returns ------- tuple The shape of the material data. """ self.check_valid_material() # ensure that the current data is valid return self.material_data.shape # data shape
[docs] def set_data_values( self, x_data_in, y_data_in, z_data_in, ): """ Set the values of the geomorphology data. Parameters ---------- x_data_in : np.ndarray A 2D numpy array indicating the x-dimension locations of the points. y_data_in : np.ndarray A 2D numpy array indicating the y-dimension locations of the points. z_data_in : np.ndarray A 2D numpy array indicating the depth at each point. material_data_in : np.ndarray, optional A 2D numpy array indicating the bed material at each point. """ # set the values that are handed in self.x_data = x_data_in.copy() self.y_data = y_data_in.copy() self.z_data = z_data_in.copy() self.check_valid_geomorphology() # ensure that the input data is valid
[docs] def set_material_values( self, x_material_data_in, y_material_data_in, material_data_in, ): """ Set the values of the material data. Parameters ---------- x_material_data_in : np.ndarray A 2D numpy array indicating the x-dimension locations of the points. y_material_data_in : np.ndarray A 2D numpy array indicating the y-dimension locations of the points. material_data_in : np.ndarray A 2D numpy array indicating the bed material at each point. """ # set the values that are handed in self.x_material_data = x_material_data_in.copy() self.y_material_data = y_material_data_in.copy() self.material_data = material_data_in.copy() self.check_valid_material() # ensure that the input data is valid
[docs] def get_z_data(self): """Get the depth at a given location.""" return self.z_data
[docs] def get_material_data(self): """Get the material data at a given location.""" return self.material_data
[docs] def evaluate( self, x_query, y_query, return_derivs=False, interp_method="spline", ): """ Evaluate the depth at a given location. Parameters ---------- x_query : np.array The x locations to sample in km y_query : np.array The y locations to sample in km Returns ------- np.array the depth at the given locations if return_derivs is False tuple the derivatives if return_derivs is True """ x_query = np.atleast_1d(x_query) # ensure x_query is a 1D array y_query = np.atleast_1d(y_query) # ensure y_query is a 1D array if interp_method == "spline": # or, smooth bivariate spline from scipy implementation if self._interpolator_device is None: # create and alias the interpolator object interpolator_sbs = self._interpolator_device = SmoothBivariateSpline( self.x_data.flatten(), self.y_data.flatten(), self.z_data.flatten(), bbox=[ np.min(self.x_data), np.max(self.x_data), np.min(self.y_data), np.max(self.y_data), ], ) else: # assert the interpolator is of the smoothbivariate spline type or its parent class assert isinstance( self._interpolator_device, SmoothBivariateSpline ), "interpolator must be a SmoothBivariateSpline" # alias interpolator_sbs = self._interpolator_device # make interpolation if return_derivs: # and if desired, take its derivatives dz_dx = interpolator_sbs(x_query, y_query, grid=False, dx=1, dy=0) dz_dy = interpolator_sbs(x_query, y_query, grid=False, dx=0, dy=1) return (dz_dx, dz_dy) # and return else: z_query = interpolator_sbs(x_query, y_query, grid=False) return z_query # just return else: raise NotImplementedError( f"{interp_method} interpolation scheme for evaluate not implemented yet. -cfrontin" )
[docs] class BathymetryGridData(GeomorphologyGridData): """ A class to represent gridded bathymetry data for a given wind farm site domain. Represents the bathymetry data for offshore sites. Can be used for floating mooring system anchors or for fixed-bottom foundations. Should specialize geomorphology data for bathymetry-specific considerations. """
[docs] def load_moorpy_soil(self, file_soil: PathLike): """ Load soil data from a MoorPy soil file. Experimental: reader may not be able to read validly formatted file in in the presence of unanticipated comments, whitespace, etc. Parameters ---------- file_soil : PathLike The path to the soil data file """ # create placholder objects in function local scope grid_soil = None x_coord = None y_coord = None with open(file_soil, "r") as f_soil: idx_y = 0 # indexer for y coordinate as file is read # iterate over lines in the soil file for idx_line, line in enumerate(f_soil.readlines()): if idx_line == 0: # moorpy header line must be first assert line.startswith("--- MoorPy Soil Input File ---") continue if idx_line == 1: # next line defines the grid size in x assert line.startswith("nGridX") # guarantee this is the case nGridX = int(line.split()[1]) # extract the number x_coord = np.zeros((nGridX,)) # prepare a coord array continue
[docs] def load_moorpy_bathymetry(self, file_bathymetry: PathLike): """ Load bathymetry data from a MoorPy bathymetry grid file. Experimental: reader may not be able to read validly formatted file in in the presence of unanticipated comments, whitespace, etc. Parameters ---------- file_bathymetry : str The path to the bathymetry data file """ # create placeholder objects in function local scope grid_bathy = None x_coord = None y_coord = None with open(file_bathymetry, "r") as f_bathy: idx_y = 0 # indexer for y coordinate as file is read # iterate over lines in the bathymetry file for idx_line, line in enumerate(f_bathy.readlines()): if idx_line == 0: # moorpy header line must be first assert line.startswith("--- MoorPy Bathymetry Input File ---") continue if idx_line == 1: # next line defines the grid size in x assert line.startswith("nGridX") # guarantee this is the case nGridX = int(line.split()[1]) # extract the number x_coord = np.zeros((nGridX,)) # prepare a coord array continue if idx_line == 2: # next line defines the grid size in y assert line.startswith("nGridY") # guarantee this is the case nGridY = int(line.split()[1]) # extract the number y_coord = np.zeros((nGridY,)) # prepare a coord array grid_bathy = np.zeros((nGridX, nGridY)) # prepare a grid continue if idx_line == 3: # next line should define the x coordinates x_coord_tgt = [float(x) for x in line.split()] # extract assert len(x_coord_tgt) == nGridX # verify length x_coord = np.array(x_coord_tgt) # convert to array continue if ( idx_line > 3 ): # all other lines should be y coordinate then gridpoint data if not line.strip(): continue # if the line is empty or whitespace, skip it y_coord_tgt = float(line.split()[0]) # extract the y coordinate bathy_row_tgt = [ float(b) for b in line.split()[1:] ] # extract the bathymetry data assert len(bathy_row_tgt) == nGridX # verify length y_coord[idx_y] = y_coord_tgt # set the y coordinate grid_bathy[:, idx_y] = bathy_row_tgt # set the bathymetry data idx_y += 1 # increment the y indexer assert idx_y == nGridY # verify that all y coordinates were read # save into the geomorphology data object self.y_data, self.x_data = np.meshgrid(y_coord, x_coord) self.z_data = grid_bathy self.check_valid_geomorphology() # make sure the loaded file is legit before exiting
[docs] class TopographyGridData(GeomorphologyGridData): """ A class to represent gridded terrain data for a given wind farm site domain. Represents the terrain data for onshore sites. Should specialize geomorphology data for topography-specific considerations. """ pass