WeatherRoutingTool package

Subpackages

Submodules

WeatherRoutingTool.config module

class WeatherRoutingTool.config.Config(*, ALGORITHM_TYPE: ~typing.Literal['dijkstra', 'gcr_slider', 'genetic', 'genetic_shortest_route', 'isofuel', 'speedy_isobased'] = 'genetic', ARRIVAL_TIME: ~datetime.datetime | None = None, BOAT_TYPE: ~typing.Literal['CBT', 'SAL', 'speedy_isobased', 'direct_power_method'] = 'direct_power_method', BOAT_SPEED: float | None = None, BOAT_SPEED_BOUNDARIES: ~typing.Annotated[list[float], ~annotated_types.MinLen(min_length=2), ~annotated_types.MaxLen(max_length=2)] = [1.0, 10.0], CONSTRAINTS_LIST: ~typing.List[~typing.Literal['land_crossing_global_land_mask', 'land_crossing_polygons', 'seamarks', 'water_depth', 'on_map', 'in_time', 'via_waypoints', 'status_error']], DEFAULT_ROUTE: ~typing.Annotated[list[int | float], ~annotated_types.MinLen(min_length=4), ~annotated_types.MaxLen(max_length=4)], DEFAULT_MAP: ~typing.Annotated[list[int | float], ~annotated_types.MinLen(min_length=4), ~annotated_types.MaxLen(max_length=4)], DELTA_FUEL: float = 3000, DELTA_TIME_FORECAST: float = 3, DEPARTURE_TIME: ~datetime.datetime, DIJKSTRA_MASK_FILE: ~pathlib.Path = None, DIJKSTRA_NOF_NEIGHBORS: int = 1, DIJKSTRA_STEP: int = 1, GCR_SLIDER_ANGLE_STEP: float = 30, GCR_SLIDER_DISTANCE_MOVE: float = 10000, GCR_SLIDER_DYNAMIC_PARAMETERS: bool = True, GCR_SLIDER_LAND_BUFFER: float = 1000, GCR_SLIDER_INTERPOLATE: bool = True, GCR_SLIDER_INTERP_DIST: float = 0.1, GCR_SLIDER_INTERP_NORMALIZED: bool = True, GCR_SLIDER_MAX_POINTS: int = 300, GCR_SLIDER_THRESHOLD: float = 10000, GENETIC_NUMBER_GENERATIONS: int = 20, GENETIC_NUMBER_OFFSPRINGS: int = 2, GENETIC_POPULATION_SIZE: int = 20, GENETIC_POPULATION_TYPE: ~typing.Literal['grid_based', 'from_geojson', 'isofuel', 'gcrslider'] = 'grid_based', GENETIC_POPULATION_PATH: ~pathlib.Path | None = None, GENETIC_REPAIR_TYPE: ~typing.List[~typing.Literal['waypoints_infill', 'constraint_violation', 'no_repair']] = ['waypoints_infill', 'constraint_violation'], GENETIC_MUTATION_TYPE: ~typing.Literal['random', 'speed', 'waypoints', 'rndm_walk', 'rndm_plateau', 'route_blend', 'percentage_change_speed', 'gaussian_speed', 'no_mutation'] = 'random', GENETIC_CROSSOVER_TYPE: ~typing.Literal['random', 'speed', 'waypoints'] = 'random', GENETIC_CROSSOVER_PATCHER: ~typing.Literal['gcr', 'isofuel'] = 'isofuel', GENETIC_RANDOM_SEED: int = None, GENETIC_OBJECTIVES: ~typing.Dict[str, float] = {'arrival_time': 1.5, 'fuel_consumption': 1.5}, GENETIC_SYMMETRIC_TIME_OBJECTIVE: bool = True, INTERMEDIATE_WAYPOINTS: list[~typing.Annotated[list[int | float], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=2), MaxLen(max_length=2)])]] = <factory>, ISOCHRONE_MAX_ROUTING_STEPS: int = 100, ISOCHRONE_MINIMISATION_CRITERION: ~typing.Literal['dist', 'squareddist_over_disttodest'] = 'squareddist_over_disttodest', ISOCHRONE_NUMBER_OF_ROUTES: int = 1, ISOCHRONE_PRUNE_GROUPS: ~typing.Literal['courses', 'larger_direction', 'branch', 'multiple_routes'] = 'larger_direction', ISOCHRONE_PRUNE_SECTOR_DEG_HALF: int = 91, ISOCHRONE_PRUNE_SEGMENTS: int = 20, ISOCHRONE_PRUNE_SYMMETRY_AXIS: ~typing.Literal['gcr', 'headings_based'] = 'gcr', ROUTER_HDGS_SEGMENTS: int = 30, ROUTER_HDGS_INCREMENTS_DEG: int = 6, ROUTE_POSTPROCESSING: bool = False, ROUTING_STEPS: int = 60, TIME_FORECAST: float = 90, COURSES_FILE: ~pathlib.Path = None, DEPTH_DATA: ~pathlib.Path = None, WEATHER_DATA: ~pathlib.Path = None, ROUTE_PATH: ~pathlib.Path, CONFIG_PATH: ~pathlib.Path = None)[source]

Bases: BaseModel

Central configuration class of the Weather Routing Tool. Parameters are validated using pydantic.

ALGORITHM_TYPE: Literal['dijkstra', 'gcr_slider', 'genetic', 'genetic_shortest_route', 'isofuel', 'speedy_isobased']
ARRIVAL_TIME: datetime | None
BOAT_SPEED: float | None
BOAT_SPEED_BOUNDARIES: Annotated[list[float], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=2), MaxLen(max_length=2)])]
BOAT_TYPE: Literal['CBT', 'SAL', 'speedy_isobased', 'direct_power_method']
CONFIG_PATH: Path
CONSTRAINTS_LIST: List[Literal['land_crossing_global_land_mask', 'land_crossing_polygons', 'seamarks', 'water_depth', 'on_map', 'in_time', 'via_waypoints', 'status_error']]
COURSES_FILE: Path
DEFAULT_MAP: Annotated[list[int | float], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=4), MaxLen(max_length=4)])]
DEFAULT_ROUTE: Annotated[list[int | float], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=4), MaxLen(max_length=4)])]
DELTA_FUEL: float
DELTA_TIME_FORECAST: float
DEPARTURE_TIME: datetime
DEPTH_DATA: Path
DIJKSTRA_MASK_FILE: Path
DIJKSTRA_NOF_NEIGHBORS: int
DIJKSTRA_STEP: int
GCR_SLIDER_ANGLE_STEP: float
GCR_SLIDER_DISTANCE_MOVE: float
GCR_SLIDER_DYNAMIC_PARAMETERS: bool
GCR_SLIDER_INTERPOLATE: bool
GCR_SLIDER_INTERP_DIST: float
GCR_SLIDER_INTERP_NORMALIZED: bool
GCR_SLIDER_LAND_BUFFER: float
GCR_SLIDER_MAX_POINTS: int
GCR_SLIDER_THRESHOLD: float
GENETIC_CROSSOVER_PATCHER: Literal['gcr', 'isofuel']
GENETIC_CROSSOVER_TYPE: Literal['random', 'speed', 'waypoints']
GENETIC_MUTATION_TYPE: Literal['random', 'speed', 'waypoints', 'rndm_walk', 'rndm_plateau', 'route_blend', 'percentage_change_speed', 'gaussian_speed', 'no_mutation']
GENETIC_NUMBER_GENERATIONS: int
GENETIC_NUMBER_OFFSPRINGS: int
GENETIC_OBJECTIVES: Dict[str, float]
GENETIC_POPULATION_PATH: Path | None
GENETIC_POPULATION_SIZE: int
GENETIC_POPULATION_TYPE: Literal['grid_based', 'from_geojson', 'isofuel', 'gcrslider']
GENETIC_RANDOM_SEED: int
GENETIC_REPAIR_TYPE: List[Literal['waypoints_infill', 'constraint_violation', 'no_repair']]
GENETIC_SYMMETRIC_TIME_OBJECTIVE: bool
INTERMEDIATE_WAYPOINTS: Annotated[list[Annotated[list[int | float], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=2), MaxLen(max_length=2)])]], FieldInfo(annotation=NoneType, required=False, default_factory=list)]
ISOCHRONE_MAX_ROUTING_STEPS: int
ISOCHRONE_MINIMISATION_CRITERION: Literal['dist', 'squareddist_over_disttodest']
ISOCHRONE_NUMBER_OF_ROUTES: int
ISOCHRONE_PRUNE_GROUPS: Literal['courses', 'larger_direction', 'branch', 'multiple_routes']
ISOCHRONE_PRUNE_SECTOR_DEG_HALF: int
ISOCHRONE_PRUNE_SEGMENTS: int
ISOCHRONE_PRUNE_SYMMETRY_AXIS: Literal['gcr', 'headings_based']
ROUTER_HDGS_INCREMENTS_DEG: int
ROUTER_HDGS_SEGMENTS: int
ROUTE_PATH: Path
ROUTE_POSTPROCESSING: bool
ROUTING_STEPS: int
TIME_FORECAST: float
WEATHER_DATA: Path
classmethod assign_config(path: str | Path = None, init_mode='from_file', config_dict=None)[source]

Check input type of config data and run validate_config

Parameters:
  • path (str, optional) – path to json with config data, defaults to None

  • init_mode (str, optional) – _description_, defaults to ‘from_file’

  • config_dict (dict, optional) – dict with config data, defaults to None

Raises:
  • ValueError – Path to json file doesn’t exist although chosen as input type for config

  • ValueError – Dict doesn’t exist although chosen as input type for config

  • ValueError – Mode chosen as input type for config doesn’t exist

Returns:

Validated config

Return type:

WeatherRoutingTool.config.Config

check_boat_algorithm_compatibility() → Self[source]

The boat type ‘speedy_isobased’ is configured to run only with the corresponding algorithm type ‘speedy_isobased’

Raises:

ValueError – BOAT_TYPE is not compatible with ALGORITHM_TYPE

Returns:

Config object with validated BOAT_TYPE-ALGORITHM_TYPE-compatibility

Return type:

WeatherRoutingTool.config.Config

classmethod check_boat_speed(v)[source]
check_boat_speed_boundaries() → Self[source]
classmethod check_constraint_list(v)[source]

Check that the CONSTRAINTS_LIST contains ‘land_crossing_global_land_mask’ else the boat would be allowed to cross land

Raises:

ValueError – CONSTRAINTS_LIST doesn’t contain ‘land_crossing_global_land_mask’

Returns:

Validated CONSTRAINTS_LIST

Return type:

list

classmethod check_genetic_repair_type(v)[source]
classmethod check_numeric_values_positivity(v, info: ValidationInfo)[source]
check_route_depth_data_compatibility() → Self[source]

Check that the route runs inside the map that has depth data available considering only place as the depth data is time independent

Raises:

ValueError – Depth data doesn’t cover map

Returns:

Config object with validated DEPTH_DATA regarding place

Return type:

WeatherRoutingTool.config.Config

check_route_on_map() → Self[source]

Check that the route runs inside the bounds of the defined map

Raises:

ValueError – Route coordinates are outside the DEFAULT_MAP bounds

Returns:

Config object with validated DEFAULT_ROUTE-DEFAULT_MAP-compatibility

Return type:

WeatherRoutingTool.config.Config

check_route_weather_data_compatibility() → Self[source]

Check that the route runs inside the map that has weather data available considering place and time :raises ValueError: Weather data doesn’t cover map :raises ValueError: Weather data doesn’t cover full routing time range :raises ValueError: Weather data has no time dimension :return: Config object with validated WEATHER_DATA regarding place and time :rtype: WeatherRoutingTool.config.Config

classmethod check_router_hdgs_segments_positive_and_even(v)[source]
check_speed_determination() → Self[source]
check_travel_time_feasibility() → Self[source]

Crosscheck the configured time window against the great circle route.

The great circle distance between the start and the destination of ‘DEFAULT_ROUTE’ is calculated with geovectorslib. Assuming a boat speed of 6 m/s the minimum travel time is derived and compared to the time difference between ‘ARRIVAL_TIME’ and ‘DEPARTURE_TIME’. If the travel time exceeds the available time window, the configured arrival time can never be reached and an error is raised.

Raises:

ValueError – Travel time on the great circle route exceeds the configured time window

Returns:

Config object with validated time window

Return type:

WeatherRoutingTool.config.Config

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) → None

This function is meant to behave like a BaseModel method to initialize private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Parameters:
  • self – The BaseModel instance.

  • context – The context.

classmethod parse_and_validate_datetime(v, info: ValidationInfo)[source]
classmethod validate_config(config_data)[source]

Validate the config by creating a Config class object and throw errors if necessary

Parameters:

config_data (dict) – Config data provided by the user in form of a json file or a dict

Returns:

Validated config

Return type:

WeatherRoutingTool.config.Config

classmethod validate_map_coordinates(v, info)[source]

Check if the coordinates of DEFAULT_MAP have values that the program can work with

Raises:
  • ValueError – DEFAULT_MAP doesn’t contain exactly 4 values

  • ValueError – One of the coordinates isn’t in the required range

Returns:

validated DEFAULT_MAP

Return type:

tuple

classmethod validate_path_exists(v, info: ValidationInfo)[source]
classmethod validate_route_coordinates(v)[source]

Check if the coordinates of DEFAULT_ROUTE have values that the program can work with

Raises:
  • ValueError – DEFAULT_ROUTE doesn’t contain exactly 4 values

  • ValueError – One of the coordinates isn’t in the required range

Returns:

Validated DEFAULT_ROUTE

Return type:

tuple

WeatherRoutingTool.config.set_up_logging(info_log_file=None, warnings_log_file=None, debug=False, stream=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, log_format='%(asctime)s - %(name)-12s: %(levelname)-8s %(message)s')[source]

WeatherRoutingTool.execute_routing module

WeatherRoutingTool.execute_routing.execute_routing(config, ship_config)[source]

Execute route optimization based on the user-defined configuration.

Initialises the weather data, the ship, the constraints and the routing algorithm from the configuration and runs the routing. The resulting route is written to <ROUTE_PATH>/<route_type>.json in GeoJSON format. If ROUTE_POSTPROCESSING is enabled, the postprocessed route is additionally written to <ROUTE_PATH>/<route_type>_postprocessed.json. If no weather data is used, the constraint 'in_time' is ignored.

Parameters:
  • config (WeatherRoutingTool.config.Config) – validated configuration

  • ship_config (WeatherRoutingTool.ship.ship_config.ShipConfig) – validated ship configuration

WeatherRoutingTool.execute_routing.merge_figures_to_gif(path, nof_figures)[source]

WeatherRoutingTool.routeparams module

Provide the container class RouteParams for a route and its ship parameters.

The module contains functions to write routes to and read them from GeoJSON files, to read measured routes from parquet and csv files and to plot route properties like power, fuel consumption and speed.

class WeatherRoutingTool.routeparams.RouteParams(count, start, finish, gcr, route_type, time, lats_per_step, lons_per_step, course_per_step, dists_per_step, starttime_per_step, ship_params_per_step)[source]

Bases: object

This is a Container class for route parameters. Parameters are assumed to be constant for every route segment (= distance from one coordinate pair to the following). The parameters for each routing step are tied to the start point of each route segment. Since the number of routing steps is by one smaller than the number of coordinate pairs, the arrays of this container class exhibit different lengths:

  • Type 1: count + 1: dists_per_step, ship_params_per_step, courses_per_step

  • Type 2: count + 2: lats_per_step, lons_per_step, starttime_per_step

When the RouteParams object is written to json file, the full arrays of type 2 are written. The corresponding values from the arrays of type 1 are set to -99 for the last coordinate pair.

Parameters:
  • count (int) – number of routing steps minus one, i.e. the number of route segments is count + 1

  • start (tuple) – latitude and longitude of the start point in degrees

  • finish (tuple) – latitude and longitude of the destination in degrees

  • gcr (astropy.units.Quantity or None) – distance travelled from start to destination in m; None if not determined

  • route_type (str) – name of the route, e.g. 'min_fuel_route'

  • time (astropy.units.Quantity or datetime.timedelta) – travel time from start to destination

  • lats_per_step (numpy.ndarray) – latitude at the beginning of each step and of the destination in degrees (type 2)

  • lons_per_step (numpy.ndarray) – longitude at the beginning of each step and of the destination in degrees (type 2)

  • course_per_step (astropy.units.Quantity) – course of each step in degrees (type 1)

  • dists_per_step (astropy.units.Quantity) – distance travelled on the great circle for every step in m (type 1)

  • starttime_per_step (numpy.ndarray) – time at the beginning of each step and arrival time at the destination (type 2)

  • ship_params_per_step (ShipParams) – ship parameters for every step (type 1)

convert_to_dict()[source]
count: int
course_per_step: tuple
dists_per_step: tuple
finish: tuple
static from_csv_file(filename)[source]

Read a measured route from a csv file.

The first column needs to contain the time. Further required columns are Latitude, Longitude, SOG (speed over ground in m/s), ME_LOAD, ME_FUEL_OIL_CONSUMPTION_CALCULATED (kg/h), draft_fp_interpolated_between_low_speeds and draft_ap_interpolated_between_low_speeds.

Parameters:

filename (str) – path of the csv file

Returns:

tuple of latitudes and longitudes in degrees, times, speed over ground in m/s (without the last value), mean fore and mean aft draught, main engine load and fuel rate in kg/h

Return type:

tuple

classmethod from_file(filename)[source]

Create a RouteParams object from a GeoJSON file.

The start times need to have the format '%Y-%m-%d %H:%M:%S'. The values of the ship parameters are converted to SI units (power in W, fuel rate in kg/s) and the values of the last point are dropped. The distances per step are calculated from the coordinates; courses are not read and set to -99. The route type is set to 'read_from_file' and gcr to -99.

Parameters:

filename (str) – path of the GeoJSON file

Returns:

route read from file

Return type:

RouteParams

static from_gzip_file(filename)[source]

Read a measured route from a gzip file.

The file needs the columns Latitude, Longitude, SOG (speed over ground in knots), ME_LOAD, ME_FUEL_OIL_CONSUMPTION_CALCULATED (kg/h), FORE_DRAUGHT_LEVEL, AFTER_DRAUGHT_LEVEL and POSITION and a time index.

Parameters:

filename (str) – path of the parquet file

Returns:

tuple of latitudes and longitudes in degrees, times, speed over ground in m/s (without the last value), fore and aft draught (pandas.Series), main engine load and fuel rate in kg/h

Return type:

tuple

gcr: tuple
get_dist_from_coords(lats, lons)[source]

Calculate the great circle distances between consecutive coordinate pairs.

Parameters:
  • lats (numpy.ndarray) – latitudes in degrees

  • lons (numpy.ndarray) – longitudes in degrees, same length as lats

Returns:

distance from each point to the following one in m, same length as lats; the last value is -99

Return type:

astropy.units.Quantity

get_fuel_per_dist()[source]

Calculate the fuel consumed in every routing step.

The fuel rate of each step is multiplied with the time between the start of the step and the start of the following step.

Returns:

fuel consumed per step in kg, length count

Return type:

astropy.units.Quantity

get_full_dist()[source]
get_full_fuel()[source]

Calculate the total fuel consumed on the route.

Returns:

sum of the fuel consumed in every step (fuel rate times time between the start times of the steps) in kg

Return type:

astropy.units.Quantity

get_full_travel_time()[source]
get_mean_power()[source]

Calculate the mean engine power over the routing steps (not weighted by time or distance).

Returns:

mean power in the unit of the ship parameters; 0 kW h if the route has no steps

Return type:

astropy.units.Quantity

static get_per_waypoint_coords(route_lons: ndarray, route_lats: ndarray, start_time: datetime, bs: Quantity)[source]

Calculate distances, courses and start times of the route segments between consecutive waypoints.

The start time of each segment is the start time of the previous segment plus its travel time.

Parameters:
  • route_lons (numpy.ndarray) – longitudes of the waypoints in degrees

  • route_lats (numpy.ndarray) – latitudes of the waypoints in degrees, same length as route_lons

  • start_time (datetime.datetime) – departure time at the first waypoint

  • bs (astropy.units.Quantity) – boat speed, either one value or one value per segment

Returns:

dictionary with one entry per segment (length: number of waypoints - 1) for the keys start_lats, start_lons (degrees), dist (great circle distance in m), courses (azimuth at the start of the segment in degrees), start_times and travel_times (Quantity)

Return type:

dict

get_power_type(power_type, norm=1.0)[source]
lats_per_step: tuple
lons_per_step: tuple
plot_acc_power_vs_dist(color, label, power_type)[source]

Plot the accumulated power or fuel consumption against the travel distance on the current pyplot figure.

The values per step are multiplied with the step lengths and summed up along the route. Fuel is plotted in t.

Parameters:
  • color (str) – matplotlib colour

  • label (str) – legend label

  • power_type (str) – 'power' or 'fuel', see get_power_type

plot_power_vs_coord(ax, color, label, coordstring, power_type)[source]

Plot power or fuel consumption per step against the latitude or longitude at the start of each step.

Parameters:
  • ax (matplotlib.axes.Axes) – axes to plot on

  • color (str) – matplotlib colour

  • label (str) – not used; the label is replaced by the name of the coordinate

  • coordstring (str) – 'lat' for latitude, any other value for longitude

  • power_type (str) – 'power' (plotted in kW) or 'fuel', see get_power_type

plot_power_vs_dist(icolor, label, power_type, ax, norm=1.0)[source]

Plot power or fuel consumption per step against the travel distance.

Power is plotted as step function, fuel as bar chart in t/km. The x axis shows the travel distance in km. Labels are set on the current pyplot figure.

Parameters:
  • icolor (int) – index of the colour and line style from utils.graphics

  • label (str) – legend label

  • power_type (str) – 'power', 'relative_power' or 'fuel', see get_power_type

  • ax (matplotlib.axes.Axes) – axes to plot on

  • norm (float) – normalisation of the power, see get_power_type

plot_power_vs_dist_ratios(denominator, color, label, power_type)[source]

Plot the ratio of power or fuel consumption of this route and another route against the travel distance.

If the histograms of the two routes have a different binning, the values of denominator are linearly interpolated to the bin centres of this route. Plotted on the current pyplot figure.

Parameters:
  • denominator (RouteParams) – route whose values are used as denominator

  • color (str) – matplotlib colour

  • label (str) – legend label

  • power_type (str) – 'power', 'relative_power' or 'fuel', see get_power_type

plot_power_vs_dist_resistances(color, label, power_type, ax1, ax2, ax3, ax4)[source]

Plot power or fuel consumption and the wind, wave and calm water resistance against the travel distance.

All quantities are plotted as bar charts with the step lengths as bar widths; the x axis shows the travel distance in km.

Parameters:
  • color (str) – matplotlib colour

  • label (str) – legend label

  • power_type (str) – 'power' (plotted in kW) or 'fuel' (plotted in t/km), see get_power_type

  • ax1 (matplotlib.axes.Axes) – axes for power or fuel consumption

  • ax2 (matplotlib.axes.Axes) – axes for the wind resistance in N

  • ax3 (matplotlib.axes.Axes) – axes for the wave resistance in N

  • ax4 (matplotlib.axes.Axes) – axes for the calm water resistance in N

plot_route(ax, colour, label, linestyle=False)[source]

Plot the route and markers for start and destination on a map.

Parameters:
  • ax (cartopy.mpl.geoaxes.GeoAxes) – axes with a cartopy projection

  • colour (str) – matplotlib colour of the route and the markers

  • label (str) – legend label of the route

  • linestyle (str or bool) – matplotlib line style; if False, the default line style is used

Returns:

axes with the route

Return type:

cartopy.mpl.geoaxes.GeoAxes

plot_speed_vs_dist(icolor, label, ax)[source]

Plot the speed per step in m/s as step function against the travel distance in km.

Parameters:
  • icolor (int) – index of the colour and line style from utils.graphics

  • label (str) – legend label

  • ax (matplotlib.axes.Axes) – axes to plot on

print_route()[source]
route_type: str
set_ship_params(ship_params)[source]
ship_params_per_step: ShipParams
start: tuple
starttime_per_step: tuple
time: timedelta
write_to_geojson(filename)[source]

Write the route as GeoJSON FeatureCollection of points to a file.

Every coordinate pair (count + 2 points) is written as point feature with the coordinates in the order (longitude, latitude). For the destination, all ship parameters are set to -99.

Parameters:

filename (str) – path of the output file

WeatherRoutingTool.test_maripower_settings_for_different_courses module

WeatherRoutingTool.test_maripower_settings_for_specific_route module

WeatherRoutingTool.weather module

Prepare and provide weather and ocean data for the weather routing.

The classes in this module load environmental data into an xarray.Dataset that is stored in the attribute ds.

class WeatherRoutingTool.weather.FakeWeather(time, hours, time_res, coord_res=0.08333333333333333, var_dict=None, gauss_dict=None)[source]

Bases: WeatherCond

Synthetic weather conditions for testing.

All variables of UNITS_DICT are set to constant values on a regular grid that covers the map size. Optionally, a Gaussian disturbance in space and time is added to the wind and wave height. The map size needs to be set with set_map_size before calling read_dataset.

For the parameters time, hours and time_res see WeatherCond.

Parameters:
  • coord_res (float) – resolution of the latitude and longitude grid in degrees

  • var_dict (dict or None) – constant values for the variables, keys are the variable names of UNITS_DICT and values are in the units of UNITS_DICT; variables that are not given are set to 0

  • gauss_dict (dict or None) – settings of the Gaussian disturbance with the keys lat and lon (centre in degrees), target_height_wind (peak wind speed in m/s) and target_height_wave (peak significant wave height in m); if None, no disturbance is added

add_gauss_to_wave(vhm0_orig, lon_start, lat_start, n_lon_values, n_lat_values, n_time_values, n_height_above_ground)[source]

Superimpose a 3D spatio-temporal Gaussian disturbance field onto existing wave fields.

Combines 2D spatial and 1D temporal Gaussian profiles, scales the disturbance to reach the target peak wave height, and adds the baseline wave field.

Parameters:
  • vhm0_orig (numpy.ndarray) – 3D array of significant wave height in m with the dimensions (latitude, longitude, time).

  • lon_start (float) – Starting longitude coordinate.

  • lat_start (float) – Starting latitude coordinate.

  • n_lon_values (int) – Number of longitude grid points.

  • n_lat_values (int) – Number of latitude grid points.

  • n_time_values (int) – Number of time steps.

  • n_height_above_ground (int) – Number of vertical height levels above ground (not used).

Raises:

ValueError – If configured target_height_wave is smaller than mean baseline wave height.

Returns:

Updated 3D array vhm0_distorted containing the modified wave height, same shape as vhm0_orig.

Return type:

numpy.ndarray

add_gauss_to_wind(uwind, vwind, lon_start, lat_start, n_lon_values, n_lat_values, n_time_values, n_height_above_ground)[source]

Superimpose a 3D spatio-temporal Gaussian disturbance field onto existing wind fields.

Combines 2D spatial and 1D temporal Gaussian profiles, scales the disturbance to reach the target peak wind speed, replicates it across vertical height levels, and adds the resulting u and v vector components to the baseline wind field.

The direction of the disturbance is the wind direction at the first grid point.

Parameters:
  • uwind (numpy.ndarray) – 4D array of baseline eastward wind speed components ($u$) in m/s with the dimensions (latitude, longitude, time, height_above_ground).

  • vwind (numpy.ndarray) – 4D array of baseline northward wind speed components ($v$) in m/s, same shape as uwind.

  • lon_start (float) – Starting longitude coordinate.

  • lat_start (float) – Starting latitude coordinate.

  • n_lon_values (int) – Number of longitude grid points.

  • n_lat_values (int) – Number of latitude grid points.

  • n_time_values (int) – Number of time steps.

  • n_height_above_ground (int) – Number of vertical height levels above ground.

Raises:

ValueError – If configured target_height_wind is smaller than mean baseline wind speed.

Returns:

Updated 4D arrays (u_updated, v_updated) containing modified wind field vectors.

Return type:

tuple[numpy.ndarray, numpy.ndarray]

combine_var_dicts(var_dict_manual, var_dict_zero)[source]
follow_conventions()[source]

Set CF-conform attributes for the coordinates and the wind variables and reorder the dimensions of ds.

The attributes of latitude, longitude and the wind components are replaced. The dimensions are transposed to (time, latitude, longitude, depth, height_above_ground).

gaussian_1D(x, mean, sigma, norm)[source]

Calculate a 1D normalised Gaussian curve over input domain values.

Parameters:
  • x (float or numpy.ndarray) – value(s) at which to evaluate the Gaussian function.

  • mean (float) – Mean / center location of the Gaussian peak.

  • sigma (float) – Standard deviation controlling the width of the Gaussian peak.

  • norm (float) – normalisation factor determining the peak amplitude.

Returns:

1D Gaussian distribution evaluated at x.

Return type:

float or numpy.ndarray

gaussian_2d(x, y, ind_gauss_x, ind_gauss_y, sigma)[source]

Calculate a 2D unnormalized Gaussian distribution on a 2D spatial grid.

Note: In this implementation, x is evaluated relative to ind_gauss_y and y relative to ind_gauss_x.

Parameters:
  • x (numpy.ndarray) – 2D meshgrid array of x-coordinates (longitude direction).

  • y (numpy.ndarray) – 2D meshgrid array of y-coordinates (latitude direction).

  • ind_gauss_x (float or int) – Center index position along the grid’s latitude axis.

  • ind_gauss_y (float or int) – Center index position along the grid’s longitude axis.

  • sigma (float) – Variance factor controlling the spatial spread of the 2D Gaussian peak.

Returns:

2D Gaussian array corresponding to the meshgrid dimensions.

Return type:

numpy.ndarray

get_gauss_over_space(n_lon_values: int, n_lat_values: int, lon_start: float, lat_start: float, target_width: float)[source]

Generate a 2D spatial Gaussian matrix centered on target geographical coordinates.

Maps target lat/lon coordinates to grid indices, computes 2D Gaussian spatial values across the bounding box, and truncates values below 1e-5 to zero.

Parameters:
  • n_lon_values (int) – Total number of longitude grid points.

  • n_lat_values (int) – Total number of latitude grid points.

  • lon_start (float) – Starting longitude coordinate of the domain.

  • lat_start (float) – Starting latitude coordinate of the domain.

  • target_width (float) – width of the Gaussian peak in degrees; it is converted to grid points by dividing by coord_res and passed as sigma to gaussian_2d

Returns:

2D array of shape (n_lat_values, n_lon_values) with spatial Gaussian weights.

Return type:

numpy.ndarray

get_gauss_over_time(n_time_values, norm)[source]

Generate a 1D Gaussian temporal perturbation profile across given time steps.

Evaluates a 1D Gaussian centered at relative time index 0.6 over the interval [0, 1]. Values below 1e-5 are truncated to zero.

Parameters:
  • n_time_values (int) – Number of discrete time steps.

  • norm (float) – Scaling factor applied to the temporal Gaussian peak.

Returns:

1D array of length n_time_values containing Gaussian weights over time.

Return type:

numpy.ndarray

get_index(lat, lon, start_lon, start_lat)[source]
read_dataset(filepath=None)[source]

Generate the synthetic dataset and store it in ds.

The grid covers the map size with the resolution coord_res (map limits included) and the time range with the resolution time_res. There is one depth level (0.494 m) and three heights above ground (10, 20 and 30 m). If gauss_dict is set, the Gaussian disturbance is added to the wind and to VHM0. The final dimension order is (time, latitude, longitude[, depth][, height_above_ground]).

Parameters:

filepath (str or None) – not used

write_data(filepath)[source]
write_reduced_data(filepath)[source]

Write reduced fake weather to file for easy analysis with QGIS.

Only the first depth level and the first height above ground (10 m) are kept, the dimensions depth and height_above_ground are removed and the wind components are renamed to uwind and vwind. The data is written to filepath with the suffix _reduced.nc instead of .nc.

Parameters:

filepath (str or pathlib.Path) – path of the netCDF file written with write_data

class WeatherRoutingTool.weather.WeatherCond(time, hours, time_res)[source]

Bases: object

Base class for weather conditions.

Stores the time range and the time resolution of the weather data and provides helper functions for calculating wind components. Subclasses implement read_dataset to fill the dataset ds.

Parameters:
  • time (datetime.datetime or None) – start time of the weather data; it is rounded down to the time resolution (see time_start). If None, no attributes are set.

  • hours (float) – length of the time range in hours, counted from time

  • time_res (float) – time resolution of the weather data in hours; must be at least 3

Raises:

ValueError – if time_res is smaller than 3 hours

check_units()[source]

Check the units of the data variables in ds against UNITS_DICT.

Logs a warning for variables without units attribute, for variables with a unit that is not listed in UNITS_DICT and for variables that are not expected at all. No exception is raised and the data is not modified.

ds: Dataset
get_map_size()[source]
static get_theta_from_uv(u, v)[source]

Calculate the wind direction from the wind components.

Uses the meteorological convention: the direction from which the wind is blowing, measured clockwise from north (e.g. 0° for wind from the north, 90° for wind from the east).

Parameters:
  • u (float or numpy.ndarray) – eastward wind component

  • v (float or numpy.ndarray) – northward wind component, in the same unit as u

Returns:

wind direction in degrees in the range [0, 360)

Return type:

float or numpy.ndarray

static get_u(theta, windspeed)[source]

Calculate the eastward wind component from wind direction and wind speed.

Inverse of get_theta_from_uv together with get_v.

Parameters:
  • theta (float or numpy.ndarray) – wind direction in degrees, meteorological convention (direction from which the wind is blowing, clockwise from north)

  • windspeed (float or numpy.ndarray) – wind speed; only the absolute value is used

Returns:

eastward wind component in the unit of windspeed

Return type:

float or numpy.ndarray

static get_v(theta, windspeed)[source]

Calculate the northward wind component from wind direction and wind speed.

Inverse of get_theta_from_uv together with get_u.

Parameters:
  • theta (float or numpy.ndarray) – wind direction in degrees, meteorological convention (direction from which the wind is blowing, clockwise from north)

  • windspeed (float or numpy.ndarray) – wind speed; only the absolute value is used

Returns:

northward wind component in the unit of windspeed

Return type:

float or numpy.ndarray

map_size: Map
print_init()[source]
read_dataset(filepath=None)[source]
set_map_size(map)[source]
property time_end
property time_res
property time_start
time_steps: int
visualise_on_map(variables: list) → None[source]

Function to visualise a selection of variables from a netCDF file for the first timestamp on a map.

The user provides a list of variables that is displayed on a 3x3 panel. Only data for the 1st timestamp is visualised. The figure is saved to weather_variables_first_timestamp.png in the current working directory.

Parameters:

variables (list) – names of the variables in ds to visualise; every variable needs a units attribute

Raises:

ValueError – if more than 9 variables are given

class WeatherRoutingTool.weather.WeatherCondEnvAutomatic(time, hours, time_res)[source]

Bases: WeatherCond

Weather conditions downloaded from GFS (atmosphere) and CMEMS (waves, physics, currents).

The CMEMS credentials are read from the environment variables CMEMS_USERNAME and CMEMS_PASSWORD. The map size needs to be set with set_map_size before calling read_dataset. For the parameters see WeatherCond.

check_data_consistency(ds_CMEMS_phys, ds_CMEMS_wave, ds_CMEMS_curr, ds_GFS)[source]

Check the time and space consistency of the downloaded datasets.

Logs the resolutions and shifts of the coordinates time, latitude and longitude of the CMEMS datasets with respect to the GFS dataset. Additionally, the number of time steps of the datasets is checked with assertions.

Parameters:
  • ds_CMEMS_phys (xarray.Dataset) – CMEMS physics data (sea water temperature and salinity)

  • ds_CMEMS_wave (xarray.Dataset) – CMEMS wave data

  • ds_CMEMS_curr (xarray.Dataset) – CMEMS current data

  • ds_GFS (xarray.Dataset) – GFS atmospheric data

Raises:

AssertionError – if the CMEMS physics or current data do not contain exactly one time step more than the wave data or if the wave and GFS data have a different number of time steps

read_dataset(filepath=None)[source]

Download the weather data from GFS and CMEMS and merge them into ds.

The data is requested for the time range of the object and for the map size widened by 1° in every direction. GFS wind is requested at 10 m above ground. The CMEMS physics and current data are interpolated to the time steps of the CMEMS wave data, and the GFS data is interpolated to the grid of the merged CMEMS data.

Parameters:

filepath (str or None) – not used

write_data(filepath)[source]
class WeatherRoutingTool.weather.WeatherCondFromFile(time=None, hours=None, time_res=None)[source]

Bases: WeatherCond

Weather conditions read from a netCDF file.

add_depth_to_EnvData(depth_path, bWriteEnvData=False)[source]

Add the water depth as variable z to the dataset ds.

The depth data is cut to the map size (only points with negative z, i.e. below sea level) and the weather data is linearly interpolated to the grid of the depth data. Missing depth values are set to 0. ds is replaced by the interpolated dataset.

Parameters:
  • depth_path (str) – path to a netCDF file with the variable z and the coordinates lat and lon

  • bWriteEnvData (bool) – if True, the resulting dataset is written to a hard-coded netCDF path

Raises:

Exception – if the map size is not initialised or if the depth contains NaN values after the interpolation

adjust_depth_format(depth_path)[source]

Read depth data from a netCDF file and convert the longitudes from [0, 360] to [-180, 180].

The data is sorted by latitude. The intermediate datasets are printed to stdout.

Parameters:

depth_path (str) – path to a netCDF file with depth data and the coordinates latitude and longitude

Returns:

depth data with longitudes in the range [-180, 180]

Return type:

xarray.Dataset

get_time_step_index(time)[source]

Determine the index of the time step that is closest to the given time.

Parameters:

time (datetime.datetime) – time for which the index is determined

Returns:

dictionary with the time rounded to the time resolution (key rounded_time) and the number of time steps between time_start and the rounded time (key idx)

Return type:

dict

read_dataset(filepath=None)[source]
wind_functions: None
wind_vectors: None
class WeatherRoutingTool.weather.WeatherCondODC(time, hours, time_res)[source]

Bases: WeatherCond

Weather conditions loaded from an Open Data Cube (ODC) instance.

Connects to the ODC instance on initialisation. The map size needs to be set with set_map_size before calling read_dataset. For the parameters see WeatherCond.

load_odc_product(product_name, res_x, res_y, output_crs='EPSG:4326', measurements=None)[source]

Load a product from the Open Data Cube for the time range and map size of the object.

Scale factors and offsets of the data variables are applied if present.

Parameters:
  • product_name (str) – name of the ODC product, e.g. 'waves'

  • res_x (float) – resolution of the output grid in x direction, in units of output_crs (degrees for EPSG:4326)

  • res_y (float) – resolution of the output grid in y direction, in units of output_crs

  • output_crs (str) – coordinate reference system of the output grid

  • measurements (list or None) – names or aliases of the measurements to load; if None, all measurements of the product are loaded

Returns:

loaded data

Return type:

xarray.Dataset

Raises:
  • ValueError – if the product is not known in the ODC instance

  • KeyError – if a requested measurement is not available for the product

read_dataset(filepath=None)[source]

Load the weather data from the ODC products physics, waves, currents and weather into ds.

The CMEMS products are loaded with a resolution of 1/12°, the GFS product with 0.25°. The CMEMS physics and current data are interpolated to the time steps of the wave data, and the GFS data is interpolated to the grid of the merged CMEMS data.

Parameters:

filepath (str or None) – not used

write_data(filepath)[source]

WeatherRoutingTool.weather_factory module

class WeatherRoutingTool.weather_factory.WeatherFactory[source]

Bases: object

static get_weather(data_mode, file_path, departure_time, time_forecast, time_resolution, default_map, **kwargs)[source]

Module contents