feat: AR-Shipdesign initial commit

This commit is contained in:
2026-07-03 12:23:25 -04:00
parent 588735ea64
commit 9a08526361
16 changed files with 4431 additions and 394 deletions
+32 -6
View File
@@ -47,11 +47,27 @@ class OffsetsTable:
lpp: float = 0.0
beam: float = 0.0
draft: float = 0.0
# Altura de la quilla por estación [m]. Permite quillas inclinadas
# (rise of keel / rocker) y quillas con perfil curvo sin alterar la
# cuadrícula de líneas de agua que permanece compartida.
# Default: cero en todas las estaciones (quilla plana sobre baseline).
keel_z: np.ndarray = field(default_factory=lambda: np.array([]))
# Desviación vertical per-nodo [m]. shape (n_sta, n_wl).
# La Z efectiva del nodo (i, j) = z_waterlines[j] + z_offsets[i, j].
# Default: ceros → todos los nodos en los planos horizontales de referencia.
z_offsets: np.ndarray = field(default_factory=lambda: np.zeros((0, 0)))
# Desviación longitudinal per-nodo [m]. shape (n_sta, n_wl).
# La X efectiva del nodo (i, j) = x_stations[i] + x_offsets[i, j].
# x_stations es la referencia paramétrica FIJA; nunca se modifica en drag.
x_offsets: np.ndarray = field(default_factory=lambda: np.zeros((0, 0)))
def __post_init__(self) -> None:
self.x_stations = np.asarray(self.x_stations, dtype=float)
self.z_waterlines = np.asarray(self.z_waterlines, dtype=float)
self.data = np.asarray(self.data, dtype=float)
self.keel_z = np.asarray(self.keel_z, dtype=float)
self.z_offsets = np.asarray(self.z_offsets, dtype=float)
self.x_offsets = np.asarray(self.x_offsets, dtype=float)
n_sta = len(self.x_stations)
n_wl = len(self.z_waterlines)
@@ -61,6 +77,15 @@ class OffsetsTable:
)
if not self.station_labels:
self.station_labels = [str(i) for i in range(n_sta)]
# Inicializar keel_z si no se proporcionó o tiene dimensión incorrecta
if self.keel_z.shape != (n_sta,):
self.keel_z = np.zeros(n_sta)
# Inicializar z_offsets si no se proporcionó o tiene dimensiones incorrectas
if self.z_offsets.shape != (n_sta, n_wl):
self.z_offsets = np.zeros((n_sta, n_wl))
# Inicializar x_offsets si no se proporcionó o tiene dimensiones incorrectas
if self.x_offsets.shape != (n_sta, n_wl):
self.x_offsets = np.zeros((n_sta, n_wl))
# ------------------------------------------------------------------
# Fábrica: casco Wigley analítico
@@ -127,7 +152,7 @@ class OffsetsTable:
station=sta,
x=float(x),
half_breadths=self.data[i, :].copy(),
z_positions=self.z_waterlines.copy(),
z_positions=(self.z_waterlines + self.z_offsets[i, :]).copy(),
label=f"x={x:.3f} m",
)
sections.append(sec)
@@ -139,13 +164,14 @@ class OffsetsTable:
def half_breadth(self, x: float, z: float) -> float:
"""Interpola la semi-manga en cualquier (x, z) [m]."""
# Interpolar en x
# Para cada estación: interpola la semi-manga a la altura z usando las
# z efectivas per-nodo (z_waterlines[j] + z_offsets[i, j]).
col_y = np.array([
float(np.interp(x, self.x_stations, self.data[:, j]))
for j in range(len(self.z_waterlines))
float(np.interp(z, self.z_waterlines + self.z_offsets[i, :], self.data[i, :]))
for i in range(len(self.x_stations))
])
# Interpolar en z
return float(np.interp(z, self.z_waterlines, col_y))
# Interpolar el resultado en x
return float(np.interp(x, self.x_stations, col_y))
@property
def n_stations(self) -> int: