Event Correction
How to run this?
Go here to instantly run all code below inside of your browser.
Use case
This is a more advanced use case. If you have little coding experience we recommend following the "Basics" and "Speed-Fuel curve" use cases first.
When an event takes place that alters the performance of the vessel, like when it gets cleaned or an ESD is installed, the Toqua Ship Kernel might not reflect the new vessel condition immediately. This could be because the data has not been uploaded yet or there's not enough data yet for the Ship Kernel to be sufficiently accurate.
In such cases you can let the Ship Kernel know of any expected performance changes. The Ship Kernel will use that information to apply a correction to the predictions following the event. This correction will eventually be removed by itself once the model has seen enough data after the event.
We will show how you can add such an expected performance change, how to see which corrections are applied and how those affect the model.
Setup
Fill in the IMO number of your ship below.
IMO_NUMBER = "9999999"
Helper functions
Some helper functions to not clutter our code too much later on.
import requests
def make_api_call(method, url, payload=None):
headers = {
"accept": "application/json",
"content-type": "application/json",
"X-API-Key": API_KEY,
}
if method == 'GET':
response = requests.get(url, headers=headers)
elif method == 'POST':
response = requests.post(url, json=payload, headers=headers)
else:
print("Error: Invalid method")
return None
if not str(response.status_code).startswith("2"):
print(f"Error: API request failed with status code {response.status_code}")
print(response.text)
return response
return response
def predict(imo_number, payload):
url = f"https://api.toqua.ai/ships/{imo_number}/models/latest/predict"
return make_api_call('POST', url, payload)
def get_metadata(imo_number):
url = f"https://api.toqua.ai/ships/{imo_number}/models/latest/metadata"
return make_api_call('GET', url)
def ingest_event(imo_number, payload):
url = f"https://api.toqua.ai/ships/{imo_number}/data/events"
return make_api_call('POST', url, payload)
Determining the current vessel performance
To see the effect of a correction, we must first know what the performance of the vessel was before the correction.
To find out, we'll predict what the fuel consumption is for a STW of 12 given a single set of conditioning parameters.
We'll call this prediction the baseline_prediction
and save it for later when we want to compare against the corrected Ship Kernel.
api_input = {
"data": {
"stw": [12], # [knots]
"wave_direction": [0], # [degrees]
"wave_height": [2], # [m]
"wind_direction": [0], # [degrees]
"wind_speed": [6], # [m/s]
"current_direction": [0], # [degrees]
"current_speed": [0], # [m]
"draft_avg": [12], # [m]
"trim": [0], # [degrees]
"fuel_specific_energy": [41] # [MJ/kg]
}
}
baseline_prediction = predict(IMO_NUMBER, api_input).json()
del baseline_prediction["errors"]
print(baseline_prediction)
{'sog': [12.0], 'stw': [12.0], 'me_rpm': [44.690351382184815], 'me_power': [7323.964299889474], 'me_fo_consumption': [31.986373946738524], 'me_fo_emission': [100.82105068011984]}
Setting an expected performance change
Whenever there is an event that is expected to change the performance of the ship, you can provide an expected_performance_change
key to convey the expected change. The value for expected_performance_change
should fall within the range of -100 to 100. A value of 100 indicates that the ship's performance will increase by 100%, meaning it will use 100% less power, resulting in a power of 0 kW. On the other hand, a value of -100 means that the ship will use 100% more power, resulting in the doubling of required power. A value of 0 indicates no performance change.
Using the value for expected_performance_change
, the Ship Kernel determines a correction factor. Only one correction factor can be present at a time, and any previous corrections will be overwritten when a new expected_performance_change
is given. You can ensure that previous corrections remain applied by providing null
or simply leaving out the expected_performance_change
key.
In the following example, we will show how to ingest a hull cleaning event that occurred yesterday of which we expect it will result in a 15% improvement in ship performance.
import datetime
import json
yesterday = datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(days=1)
event_data = {
"type": ["hull_cleaning", "esd"],
"description": ["Partial hull cleaning, flat bottom only", "retrofit of bulbous bow"],
"expected_performance_change": [15, None],
"datetime_end": [
yesterday.isoformat(),
"2024-05-14T12:00:00+00:00"
]
}
print("Ingesting the following events:")
print(json.dumps(event_data, indent=4))
response = ingest_event(IMO_NUMBER, event_data)
print(f"Event ingested. Response status code: {response.status_code}")
Ingesting the following events:
{
"type": [
"hull_cleaning",
"esd"
],
"description": [
"Partial hull cleaning, flat bottom only",
"retrofit of bulbous bow"
],
"expected_performance_change": [
15,
null
],
"datetime_end": [
"2023-12-07T13:35:09.504421+00:00",
"2024-05-14T12:00:00+00:00"
]
}
Event ingested. Response status code: 201
Viewing the applied corrections
You can check if there are any corrections currently applied by inspecting the corrections
array in the model metadata.
The correction_date
key in the corrections
array indicates the date on which the correction started to be applied. The creation_date
is the date at which the event was uploaded. The correction_factor
indicates the factor with which the Main Engine Power will be multiplied.
metadata = get_metadata(IMO_NUMBER).json()
metadata["corrections"]
[{'correction_date': '2023-12-07T13:35:09.504421+00:00',
'correction_factor': 0.85,
'creation_date': '2023-12-08T13:35:12.998456+00:00'}]
We can see that the event we uploaded is already being applied. This makes sense, as the event took place yesterday.
The correction_factor
is set to 0.85 as we expected a performance increase of 15%.
Determining the effect of a correction
To see how the correction affects our Ship Kernel, we will do a new prediction and compare it to the old prediction we have saved.
print("Prediction before correction:")
print(baseline_prediction)
corrected_prediction = predict(IMO_NUMBER, api_input).json()
del corrected_prediction["errors"]
print("Prediction after correction:")
print(corrected_prediction)
Prediction before correction:
{'sog': [12.0], 'stw': [12.0], 'me_rpm': [44.690351382184815], 'me_power': [7323.964299889474], 'me_fo_consumption': [31.986373946738524], 'me_fo_emission': [100.82105068011984]}
Prediction after correction:
{'sog': [12.0], 'stw': [12.0], 'me_rpm': [44.690351382184815], 'me_power': [7323.964299889474], 'me_fo_consumption': [31.986373946738524], 'me_fo_emission': [100.82105068011984]}
The me_rpm
, me_power
and me_fo_consumption
have increased.
Using the Pandas libray we can easily determine the exact ratio of the corrected predictions to the baseline predictions.
import pandas as pd
# Create a DataFrame with corrected and baseline predictions as rows
df = pd.concat([pd.DataFrame(corrected_prediction), pd.DataFrame(baseline_prediction)]).set_index([['corrected', 'baseline']])
# Calculate the ratio of corrected values to baseline values and add a new row 'ratio' to the DataFrame
df.loc['ratio', :] = df.loc['corrected', :] / df.loc['baseline', :]
df
sog | stw | me_rpm | me_power | me_fo_consumption | me_fo_emission | |
---|---|---|---|---|---|---|
corrected | 12.0 | 12.0 | 44.690351 | 7323.9643 | 31.986374 | 100.821051 |
baseline | 12.0 | 12.0 | 44.690351 | 7323.9643 | 31.986374 | 100.821051 |
ratio | 1.0 | 1.0 | 1.000000 | 1.0000 | 1.000000 | 1.000000 |
As expected, the Main Engine power has decreased by 15%.
The Main Engine RPM and Main Engine Fuel Oil Consumption have decreased too, but by a different magnitude. Given the nature of how these variables relate to one another the decrease this is as expected.
Updated 10 months ago