Skip to content

Commit 140fd89

Browse files
committed
[added] Added docstrings to algorithms/ship.py Boat class
1 parent 792c961 commit 140fd89

1 file changed

Lines changed: 128 additions & 3 deletions

File tree

WeatherRoutingTool/ship/ship.py

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,35 @@
1616
# Tanker: implements interface to mariPower package which is used for power estimation.
1717

1818
class Boat:
19+
"""
20+
Base class representing a vessel used by the Weather Routing Tool.
21+
22+
- Sub-classes (for example `MariPowerTanker`, `DirectPowerBoat` or `SailingBoat`) implement
23+
vessel-specific power and fuel estimation methods. This class provides shared
24+
functionality used by all boat types such as keeping basic ship parameters
25+
(draught, under-keel clearance), handling weather data access and helper
26+
methods for extracting weather fields from a NetCDF file.
27+
- Sub-classes should implement vessel-specific behaviour by overriding
28+
``get_ship_parameters``. Individual methods are documented on the method
29+
itself.
30+
31+
:param weather_path: Path to the NetCDF file that contains
32+
weather/oceanographic variables.
33+
:type weather_path: str
34+
:param under_keel_clearance: Minimum clearance below the hull as defined in
35+
the ship configuration.
36+
:type under_keel_clearance: astropy.units.Quantity
37+
:param draught_aft: Aft draught read from the ship configuration.
38+
:type draught_aft: astropy.units.Quantity
39+
:param draught_fore: Fore draught read from the ship configuration.
40+
:type draught_fore: astropy.units.Quantity
41+
:param time_min_max: Cached min/max time values available in the weather file.
42+
:type time_min_max: list
43+
:param lat_min_max: Cached min/max latitude values available in the weather file.
44+
:type lat_min_max: list
45+
:param lon_min_max: Cached min/max longitude values available in the weather file.
46+
:type lon_min_max: list
47+
"""
1948
weather_path: str # path to netCDF containing weather data
2049

2150
def __init__(self, ship_config: ShipConfig):
@@ -28,16 +57,70 @@ def __init__(self, ship_config: ShipConfig):
2857
self.lon_min_max = [None, None]
2958

3059
def get_required_water_depth(self):
60+
"""Return required water depth in metres.
61+
62+
The required water depth is computed as the maximum of fore and aft
63+
draught plus the under-keel clearance.
64+
65+
:return: required water depth in metres (float)
66+
:rtype: float
67+
"""
3168
needs_water_depth = max(self.draught_aft, self.draught_fore) + self.under_keel_clearance
3269
return needs_water_depth.value
3370

3471
def get_ship_parameters(self, courses, lats, lons, time, speed, unique_coords=False):
35-
pass
72+
"""Return `ShipParams` for the requested positions and times.
73+
74+
Sub-classes must override this method to provide vessel-specific power,
75+
RPM and fuel estimations.
76+
77+
:param courses: course angles for each routing segment (radians or degrees
78+
depending on caller conventions).
79+
:type courses: array-like
80+
:param lats: latitudes of start points for each routing segment.
81+
:type lats: array-like
82+
:param lons: longitudes of start points for each routing segment.
83+
:type lons: array-like
84+
:param time: start times for each routing segment (array of datetimes).
85+
:type time: array-like
86+
:param speed: speeds to evaluate at (one per segment).
87+
:type speed: array-like
88+
:param unique_coords: if True, the implementation may assume coordinates
89+
are unique and optimise lookups accordingly.
90+
:type unique_coords: bool
91+
:return: a `ShipParams` instance populated for each requested segment.
92+
:rtype: ShipParams
93+
"""
94+
raise NotImplementedError()
3695

3796
def print_init(self):
38-
pass
97+
"""Log basic boat initialisation information.
98+
99+
Implementations should use the project's logging/formatting helpers to
100+
print relevant initialisation values (e.g. fuel rate or geometry).
101+
"""
102+
return None
39103

40104
def evaluate_weather(self, ship_params, lats, lons, time):
105+
"""Populate weather-related fields of a `ShipParams` object.
106+
107+
This method reads the NetCDF file referenced by ``self.weather_path`` and
108+
interpolates (nearest) the required variables to the provided
109+
coordinates and times. The populated fields on ``ship_params`` include
110+
wave height, wave period, wave direction, wind and current components,
111+
pressure, temperatures and salinity.
112+
113+
:param ship_params: `ShipParams` instance to populate.
114+
:type ship_params: ShipParams
115+
:param lats: latitudes for the lookups.
116+
:type lats: array-like
117+
:param lons: longitudes for the lookups.
118+
:type lons: array-like
119+
:param time: times for the lookups (array-like, datetime-like objects).
120+
:type time: array-like
121+
:return: the same ``ship_params`` instance populated with weather fields.
122+
:rtype: ShipParams
123+
"""
41124
weather_data = xr.open_dataset(self.weather_path)
42125
n_coords = len(lats)
43126

@@ -108,6 +191,22 @@ def evaluate_weather(self, ship_params, lats, lons, time):
108191
return ship_params
109192

110193
def check_value_in_range(self, lats, lons, time):
194+
"""Raise `ValueError` if any requested coordinate or time is outside
195+
the cached weather data ranges.
196+
197+
The method uses the cached ``lat_min_max``, ``lon_min_max`` and
198+
``time_min_max`` values populated when ``evaluate_weather`` was first
199+
called. If a value is out of range, the corresponding available range is
200+
printed and a ``ValueError`` is raised.
201+
202+
:param lats: latitudes to check.
203+
:type lats: array-like
204+
:param lons: longitudes to check.
205+
:type lons: array-like
206+
:param time: times to check.
207+
:type time: array-like
208+
:raises ValueError: if any coordinate/time lies outside the available data.
209+
"""
111210
if (lats > self.lat_min_max[1] or lats < self.lat_min_max[0]).any():
112211
weather_data = xr.open_dataset(self.weather_path)
113212
print(f'lat: {weather_data["latitude"].min().to_numpy()} - {weather_data["latitude"].max().to_numpy()}')
@@ -122,6 +221,27 @@ def check_value_in_range(self, lats, lons, time):
122221
raise ValueError(f'Time {time} is out of weather range.')
123222

124223
def approx_weather(self, var, lats, lons, time, height=None, depth=None):
224+
"""Select nearest values from an xarray Variable and return as NumPy.
225+
226+
Uses ``xarray.DataArray.sel`` with ``method='nearest'`` and fills
227+
missing values with zero. Optionally selects by ``height_above_ground``
228+
or ``depth`` where available.
229+
230+
:param var: xarray variable (DataArray) to sample from.
231+
:type var: xarray.DataArray
232+
:param lats: latitude values for the lookup.
233+
:type lats: array-like
234+
:param lons: longitude values for the lookup.
235+
:type lons: array-like
236+
:param time: time values for the lookup.
237+
:type time: array-like
238+
:param height: optional height above ground to select (e.g. wind levels).
239+
:type height: float or None
240+
:param depth: optional depth to select (e.g. ocean fields).
241+
:type depth: float or None
242+
:return: sampled values as a NumPy array with NaNs replaced by 0.
243+
:rtype: numpy.ndarray
244+
"""
125245

126246
# self.check_value_in_range(lats, lons, time)
127247

@@ -135,7 +255,12 @@ def approx_weather(self, var, lats, lons, time, height=None, depth=None):
135255
return ship_var
136256

137257
def load_data(self):
138-
pass
258+
"""Optional hook to (re)load vessel-specific data.
259+
260+
Child classes may implement this to load auxiliary data (e.g. lookup
261+
tables) required for power/fuel computations.
262+
"""
263+
return None
139264

140265
def check_data_meaningful(self):
141266
"""

0 commit comments

Comments
 (0)