Last updated on Jul 14, 2026.

Source code for netsse.model.ship

# -*- coding: utf-8 -*-
"""
Hydrodynamic models for the linear wave-to-motion **transfer functions of ship responses**.

.. dropdown:: Copyright (C) 2023-2026 Technical University of Denmark, R.E.G. Mounet
    :color: primary
    :icon: law

    *This code is part of the NetSSE software.*

    NetSSE is free software: you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free
    Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    NetSSE is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.

    You should have received a copy of the GNU General Public License along
    with this program.  If not, see https://www.gnu.org/licenses/.

    To credit the author, users are encouraged to use below reference:

    .. code-block:: text

        Mounet, R. E. G., & Nielsen, U. D. NetSSE: An open-source Python package
        for network-based sea state estimation from ships, buoys, and other
        observation platforms (version 2.3). Technical University of Denmark,
        GitLab. July 2026. https://doi.org/10.11583/DTU.26379811.

*Last updated on 05-06-2026 by R.E.G. Mounet*

"""

import warnings

import numpy as np
from scipy.optimize import fsolve

from netsse.config import config
from netsse.dataset import load_keras_model_from_url
from netsse.model.envir_cond import lin_disprel
from netsse.tools.misc_func import re_range

# import warnings


[docs] def heaveCF(om0, beta_deg, U, L, B0, T, C_B=1, gravity=None): """Computes the heave transfer function amplitude, using the closed-form expressions proposed by Jensen et al. (2004), for a box-shaped uniformly-loaded **monohull ship**. Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float, default 1 Block coefficient of the ship [-]. gravity : float, optional Gravitational acceleration [m/s^2]. If None, the default value from the NetSSE configuration is used. Returns ------- heave : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the heave transfer function amplitude [m/m]. See Also -------- pitchCF, rollCF : Computes the pitch/roll transfer function amplitude using closed-form expressions. References ---------- Jensen, J. J., Mansour, A. E., & Olsen, A. S. (2004). Estimation of ship motions using closed-form expressions. Ocean Engineering, 31(1), 61–85. https://doi.org/10.1016/S0029-8018(03)00108-2 Example ------- >>> heave = heaveCF(om0,beta_deg,U,L,B0,T,C_B=1) """ # warnings.filterwarnings("ignore", category=RuntimeWarning) # Gravitational acceleration [m/s^2]: g = gravity if gravity is not None else config.gravity beta = np.array(beta_deg * np.pi / 180).reshape((-1, 1)) Fn = U / np.sqrt(g * L) k = np.square(om0) / g k[np.where(k < 1e-9)] = 1e-9 B = B0 * C_B # correction of the breadth B0 for shape effect of the hull geometry heave = np.zeros((len(om0), len(beta))) for i, beta_i in enumerate(beta): alpha = 1 - Fn * np.sqrt(k * L) * np.cos(beta_i) ome = om0 - k * U * np.cos(beta_i) A = 2 * np.sin(np.square(ome) * B / (2 * g)) * np.exp(-np.square(ome) * T / g) ke = np.abs(k * np.cos(beta_i)) f = np.sqrt((1 - k * T) ** 2 + (A**2 / (k * B * alpha**3)) ** 2) kappa = np.exp(-k * T) F = kappa * f * 2 / (ke * L) * np.sin(ke * L / 2) eta = 1 / np.sqrt( (1 - 2 * k * T * alpha**2) ** 2 + (A**2 / (k * B * alpha**2)) ** 2 ) heave[:, i] = np.reshape(eta * np.abs(F), (-1,)) # warnings.filterwarnings("default", category=RuntimeWarning) return heave
[docs] def pitchCF(om0, beta_deg, U, L, B0, T, C_B=1, gravity=None): """Computes the pitch transfer function amplitude, using the closed-form expressions proposed by Jensen et al. (2004), for a box-shaped uniformly-loaded **monohull ship**. Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequency [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of heading angle [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float, default 1 Block coefficient of the ship [-]. gravity : float, optional Gravitational acceleration [m/s^2]. If None, the default value from the NetSSE configuration is used. Returns ------- pitch : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the pitch transfer function amplitude [rad/m]. See Also -------- heaveCF, rollCF : Computes the heave/roll transfer function amplitude using closed-form expressions. References ---------- Jensen, J. J., Mansour, A. E., & Olsen, A. S. (2004). Estimation of ship motions using closed-form expressions. Ocean Engineering, 31(1), 61–85. https://doi.org/10.1016/S0029-8018(03)00108-2 Example ------- >>> pitch = pitchCF(om0,beta_deg,U,L,B0,T,C_B=1) """ # warnings.filterwarnings("ignore", category=RuntimeWarning) # Gravitational acceleration [m/s^2]: g = gravity if gravity is not None else config.gravity beta = np.array(beta_deg * np.pi / 180).reshape((-1, 1)) Fn = U / np.sqrt(g * L) k = np.square(om0) / g k[np.where(k < 1e-9)] = 1e-9 B = B0 * C_B # correction of the breadth B0 for shape effect of the hull geometry pitch = np.zeros((len(om0), len(beta))) for i, beta_i in enumerate(beta): # In case beta==90 deg or 270 deg, the amplitude of pitch is taken as # 10% of the amplitude at beta==100 deg (would be zero otherwise): # if (beta_i+np.pi/2)%np.pi == 0.: # beta_i += np.pi/180 # eta = 1.0 # else: # eta = 1.0 alpha = 1 - Fn * np.sqrt(k * L) * np.cos(beta_i) ome = om0 - k * U * np.cos(beta_i) A = 2 * np.sin(np.square(ome) * B / (2 * g)) * np.exp(-np.square(ome) * T / g) ke = np.abs(k * np.cos(beta_i)) f = np.sqrt((1 - k * T) ** 2 + (A**2 / (k * B * alpha**3)) ** 2) kappa = np.exp(-k * T) G = ( kappa * f * 24 / ((ke * L) ** 2 * L) * (np.sin(ke * L / 2) - ke * L / 2 * np.cos(ke * L / 2)) ) eta = 1 / np.sqrt( (1 - 2 * k * T * alpha**2) ** 2 + (A**2 / (k * B * alpha**2)) ** 2 ) pitch[:, i] = np.reshape(eta * np.abs(G), (-1,)) # warnings.filterwarnings("default", category=RuntimeWarning) return pitch
[docs] def rollCF( om0, beta_deg, U, L, B0, T, C_B, C_WP, GM_T, kappa, mu, T_N=0, gravity=None, rho=None, ): """Computes the roll transfer function amplitude, using the closed-form expressions proposed by Jensen et al. (2004), for a **monohull ship**. Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float Block coefficient of the ship [-]. C_WP : float Waterplane area coefficient of the ship [-]. GM_T : float Transverse metacentric height [m]. kappa : float Custom parameter (chosen between 0 and ``C_WP``) representing the ratio between the length of the aft beam and the whole ship length in the simplified ship model for roll. mu : float, default 0 Ratio between added viscous damping and critical damping. T_N : float, optional Roll natural period [s]. .. note:: If not specified as input, ``T_N`` is calculated using empirical formulas from ADA147598. gravity : float, optional Gravitational acceleration [m/s^2]. If None, the default value from the NetSSE configuration is used. rho : float, optional Density of seawater [kg/m^3]. If None, the default value from the NetSSE configuration is used. Returns ------- roll : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the roll transfer function amplitude [rad/m]. See Also -------- heaveCF, pitchCF : Computes the heave/pitch transfer function amplitude using closed-form expressions. References ---------- 1. Jensen, J. J., Mansour, A. E., & Olsen, A. S. (2004). Estimation of ship motions using closed-form expressions. Ocean Engineering, 31(1), 61–85. https://doi.org/10.1016/S0029-8018(03)00108-2 2. ADA147598, 1973. Code of Safety for Fishermen and Fishing Vessels. Part B. Safety and Health Requirements for the Construction and Equipment of Fishing Vessels. Inter-Governmental Maritime Consultative Organization, London, England. Example ------- >>> roll = rollCF(om0,beta_deg,U,L,B0,T,C_B,C_WP,GM_T,kappa,mu,T_N=0) """ # warnings.filterwarnings("ignore", category=RuntimeWarning) # Physical quantities: # - Gravitational acceleration [m/s^2]: g = gravity if gravity is not None else config.gravity # - Density of seawater [kg/m^3]: rho = rho if rho is not None else config.rho roll = np.zeros((len(om0), len(beta_deg))) if om0[0,] == 0.0: om0 = om0[1:,] start_om = int(1) else: start_om = int(0) beta = np.radians(beta_deg) k = om0**2 / g k[np.where(k < 1e-100)] = 1e-100 delta = np.amax((C_WP - kappa, 0)) gamma = np.amax((kappa / (1 - delta), 1 / 6)) B1 = gamma * B0 # The ship draught T should be less than B0 and B1, and should not be # lower than B0/6 and B1/6: T = np.amax((np.amin((T, B0, B1)), B0 / 6, B1 / 6)) Delta = L * B0 * T * C_B * rho # Displacement [kg] # Roll natural period [s]: if T_N == 0: # Select the factor for the rolling period (found in IMO A.685(17) # resolution and ADA147598): if L < 45: f = 0.4 else: f = 0.373 + 0.023 * (B0 / T) - 0.043 * (L / 100) T_N = 2 * f * B0 / np.sqrt(GM_T) C44 = g * Delta * GM_T # Restoring moment coefficient B44_crit = C44 * T_N / np.pi # Critical roll damping A0 = C_B * B0 * T / (delta + gamma * (1 - delta)) A1 = gamma * A0 if (B0 / T >= 3) & (B0 / T <= 6): aBT0 = 0.256 * B0 / T - 0.286 bBT0 = -0.11 * B0 / T - 2.55 dBT0 = 0.033 * B0 / T - 1.419 elif (B0 / T >= 0.99) & (B0 / T < 3): aBT0 = -3.94 * B0 / T + 13.69 bBT0 = -2.12 * B0 / T - 1.89 dBT0 = 1.16 * B0 / T - 7.97 if (B1 / T >= 3) & (B1 / T <= 6): aBT1 = 0.256 * B1 / T - 0.286 bBT1 = -0.11 * B1 / T - 2.55 dBT1 = 0.033 * B1 / T - 1.419 elif (B1 / T >= 0.99) & (B1 / T < 3): aBT1 = -3.94 * B1 / T + 13.69 bBT1 = -2.12 * B1 / T - 1.89 dBT1 = 1.16 * B1 / T - 7.97 for i, beta_i in enumerate(beta): ome = np.abs(om0 - k * U * np.cos(beta_i)) ome[np.where(ome < 1e-100)] = 1e-100 ke = np.abs(k * np.cos(beta_i)) ke[np.where(ke < 1e-100)] = 1e-100 b44_0 = ( rho * A0 * B0**2 * np.sqrt(2 * g / B0) * aBT0 * np.exp(bBT0 * ome ** (-1.3)) * ome**dBT0 ) b44_0[np.where(b44_0 < 1e-100)] = 1e-100 b44_1 = ( rho * A1 * B1**2 * np.sqrt(2 * g / B1) * aBT1 * np.exp(bBT1 * ome ** (-1.3)) * ome**dBT1 ) kappa = np.sqrt(1 + (b44_1 - b44_0) / b44_0) B44_invisc = ( L * b44_0 * (delta + kappa**2 * (1 - delta)) ) # Roll hydrodynamic damping B44_tot = B44_invisc + mu * B44_crit # Amplitude of the roll excitation moment: M_abs = ( np.abs(np.sin(beta_i)) * np.sqrt(rho * g**2 / ome) * 2 / ke * np.sqrt(b44_0) * np.sqrt( np.sin(0.5 * delta * L * ke) ** 2 + kappa**2 * np.sin(0.5 * (1 - delta) * L * ke) ** 2 + 2 * kappa * np.sin(0.5 * delta * L * ke) * np.sin(0.5 * (1 - delta) * L * ke) * np.cos(0.5 * L * ke) ) ) roll[start_om:, i] = M_abs / np.sqrt( (-(ome**2) * (T_N / (2 * np.pi)) ** 2 + 1) ** 2 * C44**2 + ome**2 * B44_tot**2 ) # warnings.filterwarnings("default", category=RuntimeWarning) return roll
[docs] def heaveST(om0, beta_deg, U, L, B0, T, C_B): """Computes the heave transfer function amplitude and phase, using an ANN-based surrogate model of a strip theory code. The ANN was trained on data from a linear strip theory solver, the so-called New Strip Method (Takagi and Ganno, 1967), in which the Lewis form approximation of ship cross-sections is adopted. Further details of the implementation can be found in Takami et al. (2026). Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of relative wave heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float, default 1 Block coefficient of the ship [-]. Returns ------- heave_amp : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the heave transfer function amplitude [m/m]. heave_phase : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the heave transfer function phase [rad]. Raises ------ warnings.warn If any of the input parameters are outside the valid ranges for the ANN model. See Also -------- pitchST, vbmST : Computes the pitch/vbm transfer function amplitude and phase using strip theory expressions. format_ANN_input_data : Prepares the input data for the ANN models based on the ship parameters and wave conditions. References ---------- Takagi, M. & Ganno, M. (1967). On the Accuracy of the Strip Theory, Used for a Calculation of Ship Motions in Waves. Journal of Zosen Kiokai, 121, pp. 48–61. https://doi.org/10.2534/jjasnaoe1952.1967.48. Takami, T., Nielsen, U. D., Mounet, R. E. G., Jensen, J. J., Mori, R., & Komoriyama, Y. (2026). Blind identification of incident waves and response transfer functions of a marine vessel based on measured responses. Expert Systems With Applications, 296, 129236. https://doi.org/10.1016/j.eswa.2025.129236. Example ------- >>> heave_amp, heave_phase = heaveST(om0, beta_deg, U, L, B0, T, C_B) """ # Min&max amplitude of the response transfer functions (RAOs) for the ANN models: hmax = 2.0 hmin = 0.0 # Prepare the input data for the ANN models: Nom0 = np.shape(np.array(om0).reshape(-1, 1))[0] Nbeta = np.shape(np.array(beta_deg).reshape(-1, 1))[0] ANN_input_data = format_ANN_input_data(om0, beta_deg, U, L, B0, T, C_B) # Load the .keras files for the ANN-based strip theory models: ANN_url_base = "https://github.com/Tomoki-Tak/ANN-for-ship-transfer-functions/raw/refs/heads/main/" print("Loading ANN models from: " + ANN_url_base[:61]) modelha = load_keras_model_from_url(ANN_url_base + "my_model_heaveamp.keras") modelhp = load_keras_model_from_url(ANN_url_base + "my_model_heavephase.keras") # Estimation of the vessel's RAOs using the ANN models: y_pred_ha = modelha.predict(ANN_input_data) y_pred_hp = modelhp.predict(ANN_input_data) # Heave amplitude [m/m]: hamp = (y_pred_ha + 1.0) * (hmax - hmin) / 2.0 + hmin hamp[hamp < 0] = 0 hamp[np.abs(ANN_input_data[:, 6]) >= 1] = 0 hamp[ANN_input_data[:, 6] >= 1] = 1 # Heave phase [rad]: hphase = np.arctan2(y_pred_hp[:, 1], y_pred_hp[:, 0]) heave_amp = np.reshape(hamp, (Nbeta, Nom0)).T heave_phase = np.reshape(hphase, (Nbeta, Nom0)).T return heave_amp, heave_phase
[docs] def pitchST(om0, beta_deg, U, L, B0, T, C_B): """Computes the pitch transfer function amplitude and phase, using an ANN-based surrogate model of a strip theory code. The ANN was trained on data from a linear strip theory solver, the so-called New Strip Method (Takagi and Ganno, 1967), in which the Lewis form approximation of ship cross-sections is adopted. Further details of the implementation can be found in Takami et al. (2026). Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of relative wave heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float, default 1 Block coefficient of the ship [-]. Returns ------- pitch_amp : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the pitch transfer function amplitude [deg/m]. pitch_phase : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the pitch transfer function phase [rad]. Raises ------ warnings.warn If any of the input parameters are outside the valid ranges for the ANN model. See Also -------- heaveST, vbmST : Computes the heave/vbm transfer function amplitude and phase using strip theory expressions. format_ANN_input_data : Prepares the input data for the ANN models based on the ship parameters and wave conditions. References ---------- Takagi, M. & Ganno, M. (1967). On the Accuracy of the Strip Theory, Used for a Calculation of Ship Motions in Waves. Journal of Zosen Kiokai, 121, pp. 48–61. https://doi.org/10.2534/jjasnaoe1952.1967.48. Takami, T., Nielsen, U. D., Mounet, R. E. G., Jensen, J. J., Mori, R., & Komoriyama, Y. (2026). Blind identification of incident waves and response transfer functions of a marine vessel based on measured responses. Expert Systems With Applications, 296, 129236. https://doi.org/10.1016/j.eswa.2025.129236. Example ------- >>> pitch_amp, pitch_phase = pitchST(om0, beta_deg, U, L, B0, T, C_B) """ # Min&max amplitude of the response transfer functions (RAOs) for the ANN models: pmax = 1.0 pmin = 0.0 # Prepare the input data for the ANN models: Nom0 = np.shape(np.array(om0).reshape(-1, 1))[0] Nbeta = np.shape(np.array(beta_deg).reshape(-1, 1))[0] ANN_input_data = format_ANN_input_data(om0, beta_deg, U, L, B0, T, C_B) # Load the .keras files for the ANN-based strip theory models: ANN_url_base = "https://github.com/Tomoki-Tak/ANN-for-ship-transfer-functions/raw/refs/heads/main/" print("Loading ANN models from: " + ANN_url_base[:61]) modelpa = load_keras_model_from_url(ANN_url_base + "my_model_pitchamp.keras") modelpp = load_keras_model_from_url(ANN_url_base + "my_model_pitchphase.keras") # Estimation of the vessel's RAOs using the ANN models: y_pred_pa = modelpa.predict(ANN_input_data) y_pred_pp = modelpp.predict(ANN_input_data) # Pitch amplitude [deg/m]: pamp = (y_pred_pa + 1.0) * (pmax - pmin) / 2.0 + pmin pamp[pamp < 0] = 0 pamp[np.abs(ANN_input_data[:, 6]) >= 1] = 0 # Pitch phase [rad]: pphase = np.arctan2(y_pred_pp[:, 1], y_pred_pp[:, 0]) pitch_amp = np.reshape(pamp, (Nbeta, Nom0)).T pitch_phase = np.reshape(pphase, (Nbeta, Nom0)).T return pitch_amp, pitch_phase
[docs] def vbmST(om0, beta_deg, U, L, B0, T, C_B, gravity=None): """Computes the Vertical Bending Moment (VBM) transfer function amplitude and phase, using an ANN-based surrogate model of a strip theory code. The ANN was trained on data from a linear strip theory solver, the so-called New Strip Method (Takagi and Ganno, 1967), in which the Lewis form approximation of ship cross-sections is adopted. Further details of the implementation can be found in Takami et al. (2026). Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of relative wave heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float, default 1 Block coefficient of the ship [-]. gravity : float, optional Gravitational acceleration [m/s^2]. If None, the default value from the NetSSE configuration is used. Returns ------- vbm_amp : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the VBM transfer function amplitude [kNm/m]. vbm_phase : numpy.ndarray of shape (Nom0,Nbeta) Coefficients of the VBM transfer function phase [rad]. Raises ------ warnings.warn If any of the input parameters are outside the valid ranges for the ANN model. See Also -------- heaveST, pitchST : Computes the heave/pitch transfer function amplitude and phase using strip theory expressions. format_ANN_input_data : Prepares the input data for the ANN models based on the ship parameters and wave conditions. References ---------- Takagi, M. & Ganno, M. (1967). On the Accuracy of the Strip Theory, Used for a Calculation of Ship Motions in Waves. Journal of Zosen Kiokai, 121, pp. 48–61. https://doi.org/10.2534/jjasnaoe1952.1967.48. Takami, T., Nielsen, U. D., Mounet, R. E. G., Jensen, J. J., Mori, R., & Komoriyama, Y. (2026). Blind identification of incident waves and response transfer functions of a marine vessel based on measured responses. Expert Systems With Applications, 296, 129236. https://doi.org/10.1016/j.eswa.2025.129236. Example ------- >>> vbm_amp, vbm_phase = vbmST(om0, beta_deg, U, L, B0, T, C_B) """ # Gravitational acceleration [m/s^2]: g = gravity if gravity is not None else config.gravity # Min&max amplitude of the response transfer functions (RAOs) for the ANN models: vmax = 0.25 vmin = 0.0 # Prepare the input data for the ANN models: Nom0 = np.shape(np.array(om0).reshape(-1, 1))[0] Nbeta = np.shape(np.array(beta_deg).reshape(-1, 1))[0] ANN_input_data = format_ANN_input_data(om0, beta_deg, U, L, B0, T, C_B) # Load the .keras files for the ANN-based strip theory models: ANN_url_base = "https://github.com/Tomoki-Tak/ANN-for-ship-transfer-functions/raw/refs/heads/main/" print("Loading ANN models from: " + ANN_url_base[:61]) modelva = load_keras_model_from_url(ANN_url_base + "my_model_vbmamp.keras") modelvp = load_keras_model_from_url(ANN_url_base + "my_model_vbmphase.keras") # Estimation of the vessel's RAOs using the ANN models: y_pred_va = modelva.predict(ANN_input_data) y_pred_vp = modelvp.predict(ANN_input_data) # VBM amplitude [kNm/m]: vamptmp = (y_pred_va + 1.0) * (vmax - vmin) / 2.0 + vmin vamptmp_flat = vamptmp.flatten() vamp = ( vamptmp_flat**2 * g * ((ANN_input_data[:, 1] + 1.0) * (50.0 - 10.0) / 2.0 + 10.0) * ((ANN_input_data[:, 0] + 1.0) * (400.0 - 100.0) / 2.0 + 100.0) ** 2 / 1000.0 ) vamp[np.abs(ANN_input_data[:, 6]) >= 1] = 0 vamp[vamp < 0] = 0 # VBM phase [rad]: vphase = np.arctan2(y_pred_vp[:, 1], y_pred_vp[:, 0]) vbm_amp = np.reshape(vamp, (Nbeta, Nom0)).T vbm_phase = np.reshape(vphase, (Nbeta, Nom0)).T return vbm_amp, vbm_phase
[docs] def Lewis_param(C_B): """Computes the Lewis form parameter for a ship, based on its block coefficient. Parameters ---------- C_B : float Block coefficient of the ship [-]. Returns ------- gamma : float Lewis form parameter for the ship [-]. See Also -------- format_ANN_input_data : Prepares the input data for the ANN models based on the ship parameters and wave conditions. References ---------- Takami, T., Nielsen, U. D., Mounet, R. E. G., Jensen, J. J., Mori, R., Komoriyama, Y. (2026). Blind identification of incident waves and response transfer functions of a marine vessel based on measured responses. Expert Systems With Applications, 296, 129236. https://doi.org/10.1016/j.eswa.2025.129236. Example ------- >>> gamma = Lewis_param(C_B) """ if C_B <= 0 or C_B > 1: raise ValueError("Block coefficient C_B must be in the range (0, 1).") x = np.linspace(-0.5, 0.5, 1000) func = lambda gamma: ( # noqa: E731 C_B - np.trapezoid(np.exp(-2 * x**2 / 10 ** (2 * gamma - 2)), x) ) gamma = fsolve(func, 1)[0] # Initial guess of gamma is 1 return gamma
[docs] def format_ANN_input_data(om0, beta_deg, U, L, B0, T, C_B): """Prepares the input data for the ANN models based on the ship parameters and wave conditions. Parameters ---------- om0 : array_like of shape (Nom0,) Vector of absolute wave frequencies [rad/s]. beta_deg : array_like of shape (Nbeta,) Vector of relative wave heading angles [deg]. U : float Vessel forward speed [m/s]. L : float Length of the ship [m]. B0 : float Breadth of the ship [m]. T : float Draft of the ship [m]. C_B : float Block coefficient of the ship [-]. Returns ------- ANN_input_data : numpy.ndarray of shape (Nom0*Nbeta*Nkappas, 7) Normalized input data for the ANN models, including ship parameters and wave conditions. Raises ------ warnings.warn If any of the input parameters are outside the valid ranges for the ANN model. See Also -------- Lewis_param : Computes the Lewis form parameter for a ship, based on its block coefficient. References ---------- Takami, T., Nielsen, U. D., Mounet, R. E. G., Jensen, J. J., Mori, R., Komoriyama, Y. (2026). Blind identification of incident waves and response transfer functions of a marine vessel based on measured responses. Expert Systems With Applications, 296, 129236. https://doi.org/10.1016/j.eswa.2025.129236. Example ------- >>> ANN_input_data = format_ANN_input_data(om0, beta_deg, U, L, B0, T, C_B) """ # The min&max values for each parameter [L, B0, T, U, gamma, betas_TRF, kappa] used for normalization of the ANN input data: ANN_min_vals = np.array([100, 10, 5, 0, 0.7, -180, -1]) ANN_max_vals = np.array([400, 50, 30, 30, 1.3, 180, 1]) # Compute the parameter kappa from the linear dispersion relation: om0_TRF = np.reshape(om0, (1, -1)) k = lin_disprel(om0_TRF, direction="om2k") # Linear dispersion relation lambd = 2 * np.pi / k kappa = np.log10(lambd / L) Nkappas = np.shape(kappa)[1] # Wave encounter conditions: betas_TRF = np.reshape( re_range(beta_deg, start=-180), (-1, 1) ) # Relative wave heading angle [deg] Nbetas_TRF = np.shape(betas_TRF)[0] # Compute the Lewis form parameter gamma based on the block coefficient C_B: gamma = Lewis_param(C_B) print( f"Computed Lewis form parameter gamma={gamma:.3f} for block coefficient C_B={C_B:.3f}" ) # Check that the input parameters are within the valid ranges for the ANN model: if not (ANN_min_vals[0] <= L <= ANN_max_vals[0]): warnings.warn(f"L={L} is out of range [{ANN_min_vals[0]}, {ANN_max_vals[0]}] m") if not (ANN_min_vals[1] <= B0 <= ANN_max_vals[1]): warnings.warn( f"B0={B0} is out of range [{ANN_min_vals[1]}, {ANN_max_vals[1]}] m" ) if not (ANN_min_vals[2] <= T <= ANN_max_vals[2]): warnings.warn(f"T={T} is out of range [{ANN_min_vals[2]}, {ANN_max_vals[2]}] m") if not (ANN_min_vals[3] <= U <= ANN_max_vals[3]): warnings.warn( f"U={U} is out of range [{ANN_min_vals[3]}, {ANN_max_vals[3]}] m/s" ) if not (ANN_min_vals[4] <= gamma <= ANN_max_vals[4]): warnings.warn( f"gamma={gamma} is out of range [{ANN_min_vals[4]}, {ANN_max_vals[4]}]" ) if not ( (ANN_min_vals[5] <= np.amin(betas_TRF)) and (np.amax(betas_TRF) <= ANN_max_vals[5]) ): warnings.warn( f"betas_TRF has values out of range [{ANN_min_vals[5]}, {ANN_max_vals[5]}] deg" ) if not ( (ANN_min_vals[6] <= np.amin(kappa)) and (np.amax(kappa) <= ANN_max_vals[6]) ): warnings.warn( f"kappa has values out of range [{ANN_min_vals[6]}, {ANN_max_vals[6]}]. Consider adjusting the wave frequency range." ) # Normalize the input parameters: betas_norm = ( 2 * (betas_TRF - ANN_min_vals[-2]) / (ANN_max_vals[-2] - ANN_min_vals[-2]) - 1 ) params = np.array([L, B0, T, U, gamma]) params_norm = ( 2 * (params - ANN_min_vals[:-2]) / (ANN_max_vals[:-2] - ANN_min_vals[:-2]) - 1 ) # Prepare the table for the input data of the ANN models: ANN_input_data = np.concatenate( [ np.repeat(params_norm.reshape(1, -1), Nbetas_TRF * Nkappas, axis=0), np.reshape(np.repeat(betas_norm, Nkappas, axis=0), (-1, 1)), np.reshape(np.repeat(kappa, Nbetas_TRF, axis=0), (-1, 1)), ], axis=1, ) return ANN_input_data