library(terra)
library(sf)
library(tidyverse)
library(ncdf4)
# import bathymetry file to R
<- rast("./gebco_cropped.nc")
gebco
# import the shapefile that will mask the bathymetry raster. In this case, we are using windfarms
<- st_read("./OWF/EMODnet_HA_WindFarms_pg_20220324.shp") %>%
OWF filter(STATUS %in% c("Production","Construction")) %>%
vect() %>%
project(crs(gebco))
# perform masking, this will update the raster cells inside the polygons into NA
<- mask(gebco,OWF, inverse=T, updatevalue = NA)
gebco_masked
# convert the NA cells into zero and the rest into 1
<- ifel(is.na(gebco_masked), 0, 1)
gebco_masked
# flip the raster vertically
<- flip(gebco_masked, direction = "vertical")
mask
writeCDF(mask,"mask.nc", varname="mask", overwrite=TRUE)
5.2 Ship Routing
Ship Routing is another tool that can be developed using the real-time data collection by VISTools. In this section, we describe how such tool can be run. Our partners from the ILIAD project, namely Foundation for Research and Technology – Hellas (FORTH), Meteorological Environmental Earth Observation (MEEO), and Hidromod - Modelação em Engenharia, successfully packaged the VISIR-2 model that suggests shipping routes based on weather forecasts. The model can optimize for shortest distance, fastest travel time, or lowest CO₂ emissions.You can explore their use case in Greece through this link.
In our implementation, however, we did not deploy the tool for users because the simulation results did not fully align with our specific use case.
The docker execution was done in a Microsoft operating system.
Requirements
You need to install some software before you can test the dockerized model in your local machine. Download and install the latest version of Docker. Then, install an Ubuntu terminal from the Microsoft store. we have used the Ubuntu 20.04.6 LTS. You can then run the following codes in the said terminal. Make sure the Docker software is open.
cd /mnt/c/path/to/the/working/directory #go to the directory
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install cwltool
CWL Tool
The tool relies on Common Workflow Language (CWL) which describes the pipeline on how the data inputs are processed into outputs. Below is the CWL file you need to execute to run the docker container of VISIR-2.
Show CWL file
#!/usr/bin/env cwl-runner
$namespaces:
s: https://schema.org/
cwltool: http://commonwl.org/cwltool#
$graph:
- class: Workflow
hints:
"cwltool:Secrets":
secrets: [wrf_username, wrf_password, cmems_username, cmems_password]
inputs:
wrf_ftpserver:
doc: FTP Server for WRF Download
type: string
wrf_password:
doc: Password for WRF Download
type: string
wrf_username:
doc: Username for WRF Download
type: string
wrf_remotedir:
doc: Remote dir path from root for WRF Download
type: string
vessel_type:
type: string
doc: Vessel Type (sail or motor)
cmems_username:
type: string
doc: CMEMS Username
cmems_password:
type: string
doc: CMEMS Password
departure_date:
type: string
doc: Departure Date (%Y-%m-%dT%H:%M:00Z)
start_lat:
type: float
doc: Starting Latitude
start_lon:
type: float
doc: Starting Longitude
end_lat:
type: float
doc: Ending Latitude
end_lon:
type: float
doc: Ending Longitude
maxDraught:
type: float
doc: Max Draught
bathymetry_file:
type: File?
doc: Optional Bathymetry File
outputs:
visir_output:
type: Directory
outputSource: running/visir_output
steps:
running:
in:
wrf_ftpserver: wrf_ftpserver
wrf_username: wrf_username
wrf_password: wrf_password
wrf_remotedir: wrf_remotedir
vessel_type: vessel_type
cmems_username: cmems_username
cmems_password: cmems_password
departure_date: departure_date
start_lat: start_lat
start_lon: start_lon
end_lat: end_lat
end_lon: end_lon
maxDraught: maxDraught
bathymetry_file: bathymetry_file
run: '#running'
out:
- visir_output
id: run_visir
s:author:
- class: s:Person
s:email: vasmeth@iacm.forth.gr
s:name: Vassiliki Metheniti
- class: s:Person
s:email: antonisparasyris@iacm.forth.gr
s:name: Antonios Parasyris
- class: s:Person
s:email: joao.ribeiro@hidromod.com
s:name: João Ribeiro
- class: s:Person
s:email: miguel.delgado@hidromod.com
s:name: Miguel Delgado
s:contributor:
- class: s:Person
s:email: vasmeth@iacm.forth.gr
s:name: Vassiliki Metheniti
- class: s:Person
s:email: antonisparasyris@iacm.forth.gr
s:name: Antonios Parasyris
- class: s:Person
s:email: joao.ribeiro@hidromod.com
s:name: João Ribeiro
- class: s:Person
s:email: miguel.delgado@hidromod.com
s:name: Miguel Delgado
s:description: |-
Solving Dijkstra's optimization algorithm to find optimal ship routes that minimize CO2 emissions, trip time and distance. Using VISIR II software (https://zenodo.org/records/10960842 created by CMCC), that runs using forcing from either CMRL's (https://crl.iacm.forth.gr/en/) high resolution models in the southern Greece region forecasting atmospheric state (WRF 3km x 3km), hydrodynamics (NEMO 1km x 1km) and waves (Wavewatch III 1km x 1km), or the GFS/CMEMS lower resolution forecasts to be able to generalize to routes globally.
s:keywords:
- hidromod
- visir
- VISIR
- least CO2 emissions
- optimal ship routes
- least distance
- least time
- regional
- high resolution
- global
- FORTH
- CMRL
s:name: Execution of VISIR model
s:programmingLanguage: python
s:softwareVersion: 1.0.0
s:producer:
class: s:Organization
s:name: FORTH
s:url: https://www.iacm.forth.gr/
s:address:
class: s:PostalAddress
s:addressCountry: GR
s:sourceOrganization:
- class: s:Organization
s:name: FORTH
s:url: https://www.iacm.forth.gr/
s:address:
class: s:PostalAddress
s:addressCountry: GR
- class: s:Organization
s:name: CMRL
s:url: https://crl.iacm.forth.gr/en/
s:address:
class: s:PostalAddress
s:addressCountry: GR
- class: s:Organization
s:name: Hidromod
s:url: https://hidromod.com/
s:address:
class: s:PostalAddress
s:addressCountry: PT
- class: CommandLineTool
requirements:
- class: InlineJavascriptRequirement
- class: ShellCommandRequirement
- class: DockerRequirement
dockerPull: antonisparasyris/iliad:ship_routing
- class: NetworkAccess
networkAccess: true
- class: LoadListingRequirement
loadListing: deep_listing
- class: InitialWorkDirRequirement
listing:
- entryname: /VISIR/__data/bathymetry/GEBCO_2024_sub_ice_topo.nc
entry: $(inputs.bathymetry_file)
hints:
"cwltool:Secrets":
secrets: [wrf_username, wrf_password, cmems_username, cmems_password]
inputs:
wrf_ftpserver:
type: string
wrf_password:
type: string
wrf_username:
type: string
wrf_remotedir:
type: string
vessel_type:
type: string
cmems_username:
type: string
cmems_password:
type: string
departure_date:
type: string
start_lat:
type: float
start_lon:
type: float
end_lat:
type: float
end_lon:
type: float
maxDraught:
type: float?
bathymetry_file:
type: File?
outputs:
visir_output:
type: Directory
outputBinding:
glob: ./OUTPUT
baseCommand:
- /bin/bash
- -c
arguments:
- valueFrom: |
"/VISIR/run.sh '$(inputs.wrf_ftpserver)' '$(inputs.wrf_username)' '$(inputs.wrf_password)' '$(inputs.wrf_remotedir)' \
'$(inputs.vessel_type)' '$(inputs.cmems_username)' '$(inputs.cmems_password)' '$(inputs.departure_date)' $(inputs.start_lat) \
$(inputs.start_lon) $(inputs.end_lat) $(inputs.end_lon)$(inputs.maxDraught ? ' ' + inputs.maxDraught : '')" shellQuote: false
id: running
s:author:
- class: s:Person
s:email: vasmeth@iacm.forth.gr
s:name: Vassiliki Metheniti
- class: s:Person
s:email: antonisparasyris@iacm.forth.gr
s:name: Antonios Parasyris
- class: s:Person
s:email: joao.ribeiro@hidromod.com
s:name: João Ribeiro
- class: s:Person
s:email: miguel.delgado@hidromod.com
s:name: Miguel Delgado
s:contributor:
- class: s:Person
s:email: vasmeth@iacm.forth.gr
s:name: Vassiliki Metheniti
- class: s:Person
s:email: antonisparasyris@iacm.forth.gr
s:name: Antonios Parasyris
- class: s:Person
s:email: joao.ribeiro@hidromod.com
s:name: João Ribeiro
- class: s:Person
s:email: miguel.delgado@hidromod.com
s:name: Miguel Delgado
s:description: |-
Solving Dijkstra's optimization algorithm to find optimal ship routes that minimize CO2 emissions, trip time and distance. Using VISIR II software (https://zenodo.org/records/10960842 created by CMCC), that runs using forcing from either CMRL's (https://crl.iacm.forth.gr/en/) high resolution models in the southern Greece region forecasting atmospheric state (WRF 3km x 3km), hydrodynamics (NEMO 1km x 1km) and waves (Wavewatch III 1km x 1km), or the GFS/CMEMS lower resolution forecasts to be able to generalize to routes globally.
s:keywords:
- hidromod
- visir
- VISIR
- least CO2 emissions
- optimal ship routes
- least distance
- least time
- regional
- high resolution
- global
s:name: Execution of VISIR model
s:programmingLanguage: python
s:softwareVersion: 1.0.0
s:producer:
class: s:Organization
s:name: FORTH
s:url: https://www.iacm.forth.gr/
s:address:
class: s:PostalAddress
s:addressCountry: GR
s:sourceOrganization:
- class: s:Organization
s:name: FORTH
s:url: https://www.iacm.forth.gr/
s:address:
class: s:PostalAddress
s:addressCountry: GR
- class: s:Organization
s:name: CMRL
s:url: https://crl.iacm.forth.gr/en/
s:address:
class: s:PostalAddress
s:addressCountry: GR
- class: s:Organization
s:name: Hidromod
s:url: https://hidromod.com/
s:address:
class: s:PostalAddress
s:addressCountry: PT
cwlVersion: v1.2
Job YAML File
Aside from the CWL file, you need to have a job file which contains important input details such as the starting and end point of the route, departure date and time, type of the vessel, maximum vessel draught, and CMEMS credentials.
wrf_ftpserver: InsertWRFServer
wrf_username: InsertWRFusername
wrf_password: InsertWRFpassword
wrf_remotedir: InsertWRFremotedir
start_lat: 51.394615
start_lon: 3.168766
end_lat: 54.01584
end_lon: 1.88759
vessel_type: motor #sail or motor
cmems_username: CMEMSusername
cmems_password: CMEMSpassword
departure_date: 2025-09-04T08:30:00Z
maxDraught: 5
bathymetry_file:
class: File
path: /mnt/c/path/to/the/custom/bathymetry/file/output.nc
Custom Bathymetry
The docker container uses the GEBCO Sub Ice layer to construct the nodes of the network graph. Moreover, the max draught argument in the job file above filters out nodes that are too shallow for the vessel. Hence these nodes are not considered in the route optimzation. We can also add non-navigable areas such as offshore windfarms. This can be done by setting the depth value in this areas to zero. Currently, the docker container can only take NetCDF file from GEBCO. This means that if we import and process this GEBCO file in R, the original structure of the file is altered and this can’t be read properly by the docker. To solve this, we can perform 2 steps - (1) create a mask in R using the original GEBCO bathymetry file, (2) process the GEBCO bathymetry file using the mask through the command line software NCO.
First, you need to download the NetCDF file from GEBCO. Specify the bounding box of the area of interest. Once you have downloaded the NetCDF file, you have to process it in R. The resulting mask layer should contain cell values of 1 for navigable areas and values of 0 for non-navigable areas.
In the second last line of code, the raster is flipped vertically. We have done this because the command line package NCO
, which will further process the NetCDF file, reads the cells inversely compared to terra
. Then, we need to install NCO, apply the mask, and run the VISIR docker container.
sudo apt install nco
ncrename -d latitude,lat -d longitude,lon mask.nc
ncks -A -v mask mask.nc gebco_cropped.nc
ncap2 -s 'elevation=elevation*mask' gebco_cropped.nc output.nc
cwltool workflow.cwl#run_visir job.yml
When the execution is successful, an Output
folder is created containing the simulation results. The files containing the name *_voyageplan.json
are the one we are interested in and we can visualize this in R.
VISIR
└── OUTPUT
├── 𝘊𝘖2𝘵_𝘷𝘰𝘺𝘢𝘨𝘦𝘱𝘭𝘢𝘯.𝘫𝘴𝘰𝘯
├── 𝘤𝘶𝘳𝘳.𝘯𝘤
├── 𝘥𝘪𝘴𝘵_𝘷𝘰𝘺𝘢𝘨𝘦𝘱𝘭𝘢𝘯.𝘫𝘴𝘰𝘯
├── 𝘚𝘰𝘭𝘶𝘵𝘪𝘰𝘯𝘴.𝘫𝘴𝘰𝘯
└── 𝘵𝘪𝘮𝘦_𝘷𝘰𝘺𝘢𝘨𝘦𝘱𝘭𝘢𝘯.𝘫𝘴𝘰𝘯
We can quickly visualize the routes suggested using the mapview
R package. This route starts from Zeebrugge, Belgium and ends near a windpark in the UK. As you can see the suggested route navigates around the windparks instead of going through them.
Code
library(jsonlite)
library(mapview)
library(lubridate)
<- fromJSON("./Data/Polygons/OUTPUT/CO2t_voyageplan.json") %>%
least_CO2 arrange(ISO_date) %>%
st_as_sf(coords=c("lon","lat"), crs=st_crs(4326)) %>%
summarise(do_union=F) %>%
::st_cast(.,"LINESTRING")
sf
<- fromJSON("./Data/Polygons/OUTPUT/dist_voyageplan.json") %>%
least_dist arrange(ISO_date) %>%
st_as_sf(coords=c("lon","lat"), crs=st_crs(4326)) %>%
summarise(do_union=F) %>%
::st_cast(.,"LINESTRING")
sf
<- fromJSON("./Data/Polygons/OUTPUT/time_voyageplan.json") %>%
least_time arrange(ISO_date) %>%
st_as_sf(coords=c("lon","lat"), crs=st_crs(4326)) %>%
summarise(do_union=F) %>%
::st_cast(.,"LINESTRING")
sf
mapview(OWF) +
mapview(least_CO2, color="#5ec962") +
mapview(least_dist, color="#31688e") +
mapview(least_time, color="#bc3754")
We can also visualize one route and see the direction and speed. Let’s have a look at the route with least CO2 emissions.
Code
library(leaflet)
library(leaflet.extras2)
<- fromJSON("./Data/Polygons/OUTPUT/CO2t_voyageplan.json") %>%
points_sf arrange(ISO_date) %>%
drop_na(HDG) %>%
st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
st_transform(points_sf, crs = 32630)
<-3000 # you can scale this with SOG or keep constant
arrow_length <- points_sf %>%
arrow_lines mutate(coords = st_coordinates(geometry)) %>%
mutate(
hdg_rad = (90 - HDG) * pi / 180,
x_start = coords[, 1],
y_start = coords[, 2],
x_end = x_start + arrow_length * cos(hdg_rad),
y_end = y_start + arrow_length * sin(hdg_rad)) %>%
st_set_geometry(NULL) %>%
select(-coords) %>%
mutate(line_geom = paste0("LINESTRING(",x_start," ",y_start,", ",x_end," ",y_end,")")) %>%
st_as_sf(., wkt="line_geom", crs=32630) %>%
st_transform(points_sf, crs = 4326)
<- colorNumeric("YlOrRd", domain = arrow_lines$SOG)
pal
<- fromJSON("./Data/Polygons/OUTPUT/CO2t_voyageplan.json") %>%
points arrange(ISO_date) %>%
drop_na(HDG) %>%
st_as_sf(coords = c("lon", "lat"), crs = 4326)
leaflet() %>%
addProviderTiles("CartoDB.DarkMatter") %>%
setView(lng = 1.5, lat = 51.5, zoom = 6) %>%
addArrowhead(
data = arrow_lines,
color = ~pal(SOG), # color by speed
weight = 2,
opacity = 1,
options = arrowheadOptions(yawn = 60, size = "50%"),
popup = ~paste0("Speed: ", round(SOG, digits=2), " knots <br>
Heading: ", round(HDG, digits=2), "° <br>
Timestamp: ", ymd_hms(ISO_date))) %>%
addCircles(
data = points,
color = ~pal(SOG),
weight = 4,
opacity = 1,
popup = ~paste0("Speed: ", round(SOG, digits=2), " knots <br>
Heading: ", round(HDG, digits=2), "° <br>
Timestamp: ", ymd_hms(ISO_date))) %>%
addPolygons(data=OWF, stroke=F, color="beige") %>%
addLegend(values = c(min(arrow_lines$SOG),max(arrow_lines$SOG)), pal = pal, opacity=1,
title = "Speed Over <br>Ground (knots)")
Practical Takeaways and What’s Next
The plot above shows the suggested Speed Over Ground (SOG) along the simulated route. However, these values are unrealistically high for a typical Belgian beam trawl fishing vessel, which reaches a maximum steaming speed of only about 10 knots. While this demonstrates that the Dockerized VISIR-2 model can be executed successfully in our region and has potential as a deployable tool, the simulated routes currently suggest speed profiles that are not operationally feasible. For this reason, the model cannot yet be applied to our use case.
To tailor VISIR-2 more closely to our context, vessel performance curves need to be developed. These curves describe how the vessel behaves under varying sea and weather conditions, including both achievable speeds and associated CO₂ emissions, and they serve as a critical input to the VISIR-2 model. Such curves can be derived using the fuel consumption data currently being collected through VISTools.
In addition, the operational area of Belgian beam trawlers is subject to specific navigational constraints. For instance, vessels transiting through Traffic Separation Schemes (TSS) must remain in the designated lane for their direction of travel, and any crossing must occur at right angles. At present, the VISIR-2 graph search algorithm does not account for these navigational rules, which further limits its immediate applicability.