""" Integradores numéricos para hidrostáticos navales. Regla de Simpson con fallback a trapecios cuando hay menos de 3 puntos. Conforme con IACS Rec.34 §4.2 — métodos de integración numérica. Autor: Álvaro Romero Módulo 2 — AR-ShipDesign """ from __future__ import annotations import numpy as np from scipy.integrate import simpson as _scipy_simpson # --------------------------------------------------------------------------- # Integración 1D # --------------------------------------------------------------------------- def integrate(y: np.ndarray, x: np.ndarray) -> float: """Integra y(x) usando la regla de Simpson (fallback a trapecios ≤ 2 pts). Parameters ---------- y : array_like, shape (n,) Ordenadas. x : array_like, shape (n,) Abscisas, monótonamente crecientes. Returns ------- float ∫ y dx """ y = np.asarray(y, dtype=float) x = np.asarray(x, dtype=float) n = len(x) if n < 2: return 0.0 if n >= 3: return float(_scipy_simpson(y, x=x)) return float(np.trapz(y, x)) # --------------------------------------------------------------------------- # Primitivas para plano de flotación y secciones # --------------------------------------------------------------------------- def waterplane_strips(offsets_table, draft: float) -> tuple[np.ndarray, np.ndarray]: """Devuelve (x_stations, y_half_breadths) en el calado *draft*. Parameters ---------- offsets_table : OffsetsTable Tabla de offsets del casco. draft : float Calado al que se evalúa el plano de flotación [m]. Returns ------- x : np.ndarray, shape (n_sta,) Posiciones longitudinales de las estaciones [m]. y : np.ndarray, shape (n_sta,) Semi-mangas en el plano draft [m]. """ x = offsets_table.x_stations y = np.array([offsets_table.half_breadth(xi, float(draft)) for xi in x]) return x, y def section_areas_and_centroids( sections: list, draft: float ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """Devuelve (x, areas, centroides_z) para todas las secciones al calado *draft*. Parameters ---------- sections : list[Section] Lista de secciones del casco. draft : float Calado de cálculo [m]. Returns ------- x : np.ndarray, shape (n_sec,) Posiciones longitudinales [m]. areas : np.ndarray, shape (n_sec,) Áreas sumergidas [m²]. cz : np.ndarray, shape (n_sec,) Centroides verticales de cada sección [m desde quilla]. """ x = np.array([s.x for s in sections]) a = np.array([s.area(draft=draft) for s in sections]) cz = np.array([s.centroid_z(draft=draft) for s in sections]) return x, a, cz