Vessel Scheduling

Story
In this practical example, an efficient plan is developed for delivering large cargoes using oil tankers.
The model assumes each ship can carry only one cargo at a time, and once the time horizon begins, all vessels head directly to the loading port. Upon loading, each vessel proceeds directly to the delivery location within its designated time window.
Constraints include ensuring each cargo is loaded inside the determined time window, each cargo being transported by only one vessel, and each charter vessels being assigned to only one route at a time.
The objective is to minimize costs associated to combinations of cargoes and routes.
Mathematical Model
To appreciate the complexity of the below mathematical formulation, it is important to note that the number of routes grows combinatorially with the number of cargos. For instance, with 7 vessels and 20 cargos, the number of routes can exceed half a million.
Vessel Scheduling Model |
||
---|---|---|
Sets and indices: |
||
\(v\), \(v \in Vessels\) |
Vessels |
|
\(c\), \(c \in Cargos\) |
Cargos |
|
\(r\), \(r \in Routes\) |
Routes |
|
Parameters: |
||
\(D_{v,r} \in \{ 0, 1 \}\) |
Route \(r\) used by vessel \(v\): |
|
\(CR_{c,r} \in \{ 0, 1 \}\) |
Cargo \(c\) on route \(r\): |
|
\(IC_{v} \in \mathbb{R_{+}}\) |
Idle cost for vessel \(v\): |
|
\(SC_{c} \in \mathbb{R_{+}}\) |
Cost cargo \(c\) handled on spot market: |
|
\(T_{r} \in \mathbb{R_{+}}\) |
Cost executing route \(r\): |
|
Variables: |
||
\(a_{(v,r)|D_{v,r}} \in \{ 0, 1 \}\) |
allocate vessel \(v\) to route \(r\): |
|
\(s_{c} \in \{0..1\}\) |
cargo \(c\) is left to the spot market: |
|
\(i_{v} \in \{0..1\}\) |
vessel \(v\) remains idle: |
|
Constraints: |
||
1 |
\(\forall c: \sum_r a_{v,r} * CR_{c,r} + s_{c} = 1\) |
Cargo on a single vessel, or left to spot market |
2 |
\(\forall v: \sum_r a_{v,r} + i_{v} = 1\) |
Each vessel can take only one route, or is idle |
Minimize: |
||
\(\sum_{v,r} T_{r} * a_{v,r} +\) |
Operational cost |
|
\(\sum_{v} IC_{v} * i_{v} +\) |
Unused vessel cost |
|
\(\sum_{c} SC_{p,c} * S_{c}\) |
Total cost of cargos left to the spot market |
Language
Route Generation
Before optimization, all possible routes are generated after data import, taking into account each cargo’s loading window to ensure timely delivery.
During the mathematical optimization process, each cargo is then assigned to either a time-chartered or voyage-chartered vessel within the model.
In this example, the vessel scheduling problem is solved by first generating the routes, followed by the mathematical optimization. The majority of the time is spent on route generation.
Example
A single vessel, vessel1
, located at Caracas, is to handle two cargos, labeled: a1
and a2
.
a1
load in Paramaribo, deliver in Sao Paolo
a2
load in Montevideo, deliver in Rio de Janeiro.
Then there are five potential routes:
vessel1_a1_a2
: with actions:
Sail to Caracas to Paramaribo
Load Cargo
a1
Sail to Sao Paolo
Deliver Cargo
a1
Sail to Montevideo
Load Cargo
a2
Sail to Rio de Janeiro
Deliver Cargo
a2
vessel1_a2_a1
: similar asvessel1_a1_a2
, just a different order of locations; and thus also different vessel sailing times and cargo pickup moments.
vessel1_a1
:vessel1
only handles cargoa1
vessel1_a2
:vessel1
only handles cargoa2
vessel1
Remains at port Caracas
The route generation procedure is as follows:
For each vessel i, the idle route is generated:
vessel<i>
. Together they initialize the set of just generated routes,JG
.Move the set of just generated routes
JG
, to the set of input routesIR
.For each
r
inIR
, all cargosc
are considered to be appended for a new router'
. A router' = r_c
is accepted if:c
is not a part ofr
,c
is picked up in its time window, andc
is delivered before the end of the horizon.
All routes
r'
just generated, form the new set of just generated routesJG
. If the setJG
is empty, stop, otherwise continue with step 2.
Because a route r'
ends later than route r
, this procedure is finite.
In order to determine the cost of a route, careful administration of each leg needs to be done (sailing to the loading location, perhaps waiting, sailing to the delivery location).
WebUI Features
On input page, if you click around the graphs, a highlighted cell will appear identifying the last clicked element. The results are displayed in a combination chart (stacked bar chart).
The following WebUI features are used:
UI Styling
Below there are the css files you will find with comments on what they change.
1:root {
2 --primaryDark: #DA2063;
3 --primaryDarker: #FF4940;
4 --secondary90Transparent: #ff4a4023;
5 --secondary: #2E324F;
6
7 --bg_app-logo: 15px 50% / 40px 40px no-repeat url(/app-resources/resources/images/schedule.png); /*app logo*/
8 --spacing_app-logo_width: 60px;
9 --color_border_app-header-divider: var(--secondary); /*line color after header*/
10
11 --color_workflow-item-divider: var(--secondary90Transparent); /*workflow step divider color*/
12 --color_bg_workflow_current: var(--primaryDark); /*bg color when step is selected*/
13 --color_workflow_active: var(--primaryDark); /*font and icon color when step is active*/
14 --color_workflow-icon-border: var(--primaryDark); /*round border of the step*/
15 --color_bg_workflow_active: #ff4a400e;;
16
17 --color_bg_app-canvas: url(/app-resources/resources/images/RightBackground.png) rgb(249, 249, 249) no-repeat left/contain; /*background color*/
18 --color_bg_widget-header: linear-gradient(90deg, rgba(255,73,64,0.75) 0%, rgba(218,32,99,0.75) 100%); /*widget header background color*/
19 --border_widget-header: 2px solid var(--secondary); /*line color after widget header*/
20
21 --color_text_widget-header: var(--secondary);
22 --color_text_edit-select-link: var(--primaryDark);
23
24 --color_bg_button_primary: var(--primaryDark);
25 --color_bg_button_primary_hover: var(--primaryDarker);
26}
1/*Hide checkbox contents of delete and edit annotations*/
2.annotation-edit-element input.boolean-cell-editor-contents,
3.annotation-delete-element input.boolean-cell-editor-contents{
4 visibility: hidden;
5 display: block;
6}
7
8.annotation-edit-element {
9 background: white url(img/pencil.png) no-repeat 50%/contain;
10 background-size: auto 70% ;
11}
12
13.annotation-delete-element {
14 background: white url(img/minus.png) no-repeat 50%/contain;
15 background-size: auto 50% ;
16
17}
18
19.annotation-NotInUse,
20.annotation-DeliveringPort,
21.annotation-VisibleLocations{
22 fill: #FE493F;
23 background: #FE493F !important;
24}
25
26.annotation-InUse,
27.annotation-LoadingPort{
28 fill: #9E3869;
29 background: #9E3869 !important;
30}
31
32.annotation-not-fulfilled{
33 background: #ffc21b2c;
34}
35
36.annotation-highlight-cell {
37 background: var(--secondary90Transparent);
38}
1/*Centering cells*/
2.tag-table .cell.flag-string .cell-wrapper,
3.tag-table .cell.flag-number input,
4.tag-table .cell.flag-string input{
5 text-align: center;
6}
7
8.tag-slider .slider-value {
9 color: var(--color_text_edit-select-link);
10}
11
12.widget-menu__item .title {
13 color: var(--color_text_app-footer);
14}
15
16.ql-snow a {
17 color: var(--color_text_edit-select-link) !important;
18}
19
20input.boolean-cell-editor-contents {
21 accent-color: var(--primaryDark) /*boolean color*/
22}
23
24.react-contextmenu .react-contextmenu-item .display-text {
25 color: inherit;
26}
27
28.aimms-widget[data-widget\.uri="scl_EditAddElements"] .awf-dock.top,
29.aimms-widget[data-widget\.uri="msl_selecRoutes"] .awf-dock.top,
30.aimms-widget[data-widget\.uri="MappingCargoesWithCollors_1"] .awf-dock.top,
31.aimms-widget[data-widget\.uri="Vessel loading_1"] .awf-dock.top{
32 display: none;
33}
34
35.status-message:hover,
36.status-message.clickable:hover .status-display-text {
37 background-color: #ffcdcb2d;
38 color: #505767;
39}
As a service
In the above, the algorithm of this app is presented that generates a set of potential routes, and optimizes a mathematical program to find an optimal selection of those routes.
A service can be defined around this algorithm facilitating its use by other applications via REST API.
A service in an AIMMS model is easily defined by associating the name of a service to an AIMMS procedure. More interestingly, is that there are several data formats available for providing input (request body) and output (response body) to a request on such a service.
In the following sections, we will detail:
Defining a service
Implementing a service
Testing such a service using a Python script with the requests python library
Developing and testing such a service on AIMMS Cloud using the
Defining and implementing a a service
Coding the service
A service is defined by naming it and associating it with a procedure. For instance in the following example code:
1rocedure pr_solveVesselSchedulingExcel {
2 Body: {
3 block
4
5 pr_initTask();
6
7 _sp_inp := dex::api::RequestAttribute( 'request-data-path' ) ;
8 _sp_out := dex::api::RequestAttribute( 'response-data-path' ) ;
9
10 pr_actuallySolveVesselSchedulingExcel( _sp_inp, _sp_out );
11
12 onerror _ep_err do
13
14 _sp_msg := errh::Message( _ep_err );
15 display _sp_msg ;
16
17 endblock ;
18
19 return 1 ;
20 }
21 dex::ServiceName: solveVesselSchedulingExcel;
22 StringParameter _sp_inp;
23 StringParameter _sp_out;
24 ElementParameter _ep_err {
25 Range: errh::PendingErrors;
26 }
27 StringParameter _sp_msg;
28}
Remarks:
Line 1: The name of the procedure that will be executed when the service is called.
Line 21: The name of the service, that will be available for execution.
Lines 7,8: The filename of the request and response.
Whereby pr_initTask
The procedure pr_initTask
is run when a task is started; it is intended to make the
“Business model” of the application stateless; such that tasks can be run independently from
each other.
Here “Business model” refers to identifiers (sets, parameters, variables, and constraints)
that represent objects in the reality being modeled.
This is contrasted with application management identifiers such as such as user filenames,
time of day, profiling information, and so forth.
The sets and parameters in the libraries WebUI and PRO are all examples of management identifiers;
and should not be altered by a procedure such as pr_initTask
.
1Procedure pr_initTask {
2 Body: {
3 ! Reset the Business model
4 empty s_cargoes, s_vessels, s_locations, s_calc_feasibleRoutes ;
5
6 ! Clean the generated mathematical programs.
7 _ep_gmp := first( AllGeneratedMathematicalPrograms );
8 while _ep_gmp do
9 gmp::Instance::Delete( _ep_gmp );
10 endwhile ;
11
12 ! Other cleanups
13 StringGarbageCollect();
14 CleanDependents();
15 }
16 ElementParameter _ep_gmp {
17 Range: AllGeneratedMathematicalPrograms;
18 }
19}
and pr_actuallySolveVesselSchedulingExcel
1Procedure pr_actuallySolveVesselSchedulingExcel {
2 Arguments: (sp_inp,sp_out);
3 Body: {
4 dex::AddMapping(
5 mappingName : "ImportDataSet",
6 mappingFile : "Mappings/Generated/ImportDataSet-Excel.xml");
7
8 p_vesselVelocity := 37.04 [km/hour];
9
10 if dex::ReadFromFile(
11 dataFile : sp_inp,
12 mappingName : "Generated/ImportDataSet-Excel") then
13
14 !Activate all master data
15 bp_activeCargoes(i_cargo):= 1;
16 bp_activeVessels(i_vessel) := 1;
17 bp_activeLocations(i_loc) := 1;
18 endif ;
19
20 pr_calculateRoutesAndCost(ep_routeCalculationImplementation: ep_selectedRouteCalculationImplementation );
21
22 solve mm::mp_vesselScheduling;
23
24 !Post Execution
25 mm::pr_post_vesselResults();
26 mm::pr_post_cargoResults();
27 mm::pr_post_routeResults();
28
29 dex::WriteToFile(
30 dataFile : sp_out,
31 mappingName : "Generated/ExportDataSet-Excel",
32 pretty : 1);
33 }
34 DeclarationSection Argument_declarations {
35 StringParameter sp_inp {
36 Property: Input;
37 }
38 StringParameter sp_out {
39 Property: Input;
40 }
41 }
42}
Remarks:
Line 10-12: The request data is read in.
Line 29-31: The response data is written out.
Starting and stopping the service
When using the AIMMS IDE, you can manually start and stop the service using the procedures:
https://documentation.aimms.com/dataexchange/api.html#dex-api-StartAPIService
https://documentation.aimms.com/dataexchange/api.html#dex-api-StopAPIService
When using AimmsCMD, or AIMMS inside a docker container, the service is better started using the procedure dex::api::RESTServiceHandler
.
This will stop execution after timeout or after exceeding the maximum number of requests. Fine control is provided via the parameters:
dex::api::RESTServiceMaxRequests
dex::api::RestServiceMinTimeout
dex::api::RESTServiceTimeout
When using the AIMMS cloud, the service is automatically started when a task is posted; no need to manually start the service.
Vessel Scheduling Headless execution
Headless execution is available in several ways, depending on your software environment, you can choose what is best for you.
The headless execution can take place:
on your laptop,
inside a docker container, or
in the AIMMS Cloud.
Headless execution on your laptop
Directly using AimmsCmd
When project and data are both available on the same Windows machine,
directly using AimmsCmd
is perhaps the easiest way.
AimmsCmd
command lines follow the structure:
AimmsCmd [options for AimmsCmd] projectName.aimms [options for aimms application] < aimmscmdfile > logfile 2> errfile
There is a clear ordering in this command line:
First, the options to
AimmsCmd
itself. These options are optional, but a typical example is--run-only
<run only procedure>.Second, the name of the project. This is mandatory and
Third, the arguments to the AIMMS project, which can be retrieved using SessionArgument
Fourth, input/output redirection. Often used as an alternative to the run only procedure.
Three examples:
Example a: A single run procedure with session arguments.
A .bat file demonstrating the use:
1echo on
2
3rem Use AimmsCMD to start Vessel Scheduling with session arguments.
4
5set AIMMS_VERSION=25.3.2.6-x64-VS2022
6set AIMMS_EXECUTABLE=%localappdata%\AIMMS\IFA\Aimms\%AIMMS_VERSION%\Bin\AimmsCMD.exe
7
8pushd ..\AIMMSProject
9
10%AIMMS_EXECUTABLE% --run-only pr_solveModelSessionArguments "VesselScheduling.aimms" data\VS_7Vessel_20Cargo.xlsx data\VS_7Vessel_20Cargo_Results.xlsx
11
12popd
13
14echo Current time: %time%
15
16pause
Remarks:
Lines 5 and 6 is to facilitate easy switching between AIMMS Versions / executables.
Line 10: A run only procedure is used, and this procedure accepts two arguments to do the actual run.
The
pushd
andpopd
commands ensure the current working folder during the AIMMS session is the project folder of the application.Subsequently, both the input and output of the AIMMS Session are in the subfolder
data
.And also, the logs of what happened during the AIMMS Session are in the subfolder
log
Example b: with file redirection and AimmsCmd
scripts.
In some environments, such a script is known as a properties file.
1echo on
2
3rem Use AimmsCMD to start Vessel Scheduling via an AimmsCmd script
4
5set AIMMS_VERSION=25.3.2.6-x64-VS2022
6set AIMMS_EXECUTABLE=%localappdata%\AIMMS\IFA\Aimms\%AIMMS_VERSION%\Bin\AimmsCMD.exe
7
8pushd ..\AIMMSProject
9
10%AIMMS_EXECUTABLE% "VesselScheduling.aimms" < single-run.properties > log/single-run.log 2> log/single-run.err
11
12popd
13
14echo Current time: %time%
15
16pause
The AimmsCmd
script single-run.properties
in above contains a series of AimmsCmd
commands, for instance the following:
let sp_theExcelInput := "data/VS_7Vessel_20Cargo.xlsx" ;
let sp_theExcelOutput := "data/VS_7Vessel_20Cargo_Results.xlsx" ;
run pr_solveTheModel ;
quit ;
This achieves the same result.
Example c: starting the application as a service
1echo on
2
3rem Use AimmsCMD to start Vessel Scheduling as a service.
4
5set AIMMS_VERSION=25.3.2.6-x64-VS2022
6set AIMMS_EXECUTABLE=%localappdata%\AIMMS\IFA\Aimms\%AIMMS_VERSION%\Bin\AimmsCMD.exe
7
8set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
9set VS_PROJECT=%VS_ROOT%\AIMMSProject
10
11pushd %VS_PROJECT%
12
13%AIMMS_EXECUTABLE% --run-only dex::api::RESTServiceHandler "VesselScheduling.aimms" --dex::serviceTimeOut 30000
14
15popd
16
17echo Current time: %time%
18
19pause
Remarks:
Line 10 is the interesting one, we use
--run-only dex::api::RESTServiceHandler
to start the service, andthe session arguments
--dex::serviceTimeOut
and30000
the set the default timeout to 30 seconds (as opposed to 5 minutes).
Headless execution in a docker container
To execute AIMMS inside a docker container, first a docker image needs to be prepared with the necessary components, and subsequently, AIMMS needs to be executed by completing the missing information and starting the executable. Both for preparing the image, and for the choice on how to run there are several options. These will be detailed below.
Preparing an image for the docker container
To execute an AIMMS session in a docker container, a setup needs to be prepared. This setup consists of four components:
The AIMMS Executable / installation
The AIMMS License to be used
The AIMMS Application
The data for the AIMMS Application
We will discuss the choices available for each of the components below.
Including the AIMMS Executable to the docker image
The docker image is based on the aimms-eo docker image. This docker image is parameterized for the AIMMS version, and includes the materials from the Linux AIMMS installation and necessary other software components to execute.
Including or mounting the AIMMS License to the docker image
The AIMMS License must be available in the /data folder, which can be either mounted or included in the image definition. The folder structure should be as follows:

Here the license.cfg
file may contain a network license - which is a license of the following contents:
1 network <your license server>:3400
Including or mounting the AIMMS Application to the docker image
Also the AIMMS application can be stored in the image, or be made accessible via a mount.
The folder /model
is used inside the Docker image for this purpose,
and execution of AIMMS needs to start in this folder.
You can achieve this by adding /w model
to your docker run command.
When adding the project to the image, please copy the essential contents
of the project to the subfolder model in the aimms-eo
folder (build context).
Here the essential contents are the contents without folders such as backup
and log
.
Optionally a, you can add a LoggerConfig.xml
to the model folder for logging execution.
Redirect the output to a mounted folder for inspection.
For example, if your LoggerConfig.xml
is taken from this how-to, change line 44 from:
<param name="File" value="log/aimms-log.txt" />
to
<param name="File" value="/outputs/aimms-log.txt" />
Where /outputs
is a mounted volume (see also below).
Optionally b, You can also add a bash script, aimmscmdrun.sh
, to steer execution:
The contents of this aimmscmdrun.sh
bash script:
#!/bin/sh
/usr/local/Aimms/Bin/AimmsCmd VesselScheduling.aimms </inputs/single-run.properties >/outputs/single-run.log 2>/outputs/single-run.err
The contents of this bash script clearly depend on the AIMMS project name and on other name choices for mounting volumes.
Mounting the data for the AIMMS application
The data, both input and output, are not typically included in the image, as this data varies per run.
Assuming files are used to exchange data, use the /inputs
and /outputs
folders:
In the example I used, there are two folders used: /inputs
and /outputs
:
/inputs
contains input files and possiblysingle-run.properties
./outputs
contains the results and execution logs.
In my example I mount these volumes. An alternative, when the /model folder is mounted, they can also be sub folders of the /model folder.
Building the image
1echo on
2
3rem Builds a docker image with:
4rem 1. license info in sub-folder "data" of aimms-eo checkout
5rem 2. AIMMS application in sub-folder "model" of aimms-eo checkout
6rem 3. AIMMS 25.2.3.1 installation
7
8set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
9
10pushd %VS_ROOT%\aimms-eo
11
12docker build -f Dockerfile.WithLicenseAndModel -t vesselscheduling:1.0.2.1 --build-arg AIMMS_VERSION_MAJOR=25.3 --build-arg AIMMS_VERSION_MINOR=1.0 .
13
14popd
15
16pause
Running AIMMS inside the image
Information used when running AIMMS in a docker container can either be in the Docker container, or on the host on which the docker container runs.
In this example:
the AIMMS installation is on the image,
the AIMMS license is on the image,
the AIMMS model is on the image, but
the input and output data of the AIMMS application is stored in mounted volumes.
This setup for docker containers permits the following three ways of executing headless:
Using AimmsCmd in a container and just running a single procedure
echo on
rem Script to execute a single procedure in an AIMMS app stored in a docker image.
set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
set VS_INPUTS=%VS_ROOT%\inputs
set VS_OUTPUTS=%VS_ROOT%\outputs
docker run --rm -i -v "%VS_INPUTS%:/inputs" -v "%VS_OUTPUTS%:/outputs" -w /model vesselscheduling:1.0.2.1 AimmsCmd --run-only pr_solveModelSessionArguments "VesselScheduling.aimms" /inputs/VS_70Vessel_100Cargo.xlsx /outputs/VS_70Vessel_100Cargo_results.xlsx
pause
Using AimmsCmd in a container and executing a aimmscmd script
Here AimmsCmd is called with redirected input and output. To ensure that the input/output redirection is applied to the command executing in the docker container, and not the docker command that is running on the host, the AimmsCmd call in encapsulated in a shell call.
echo on
rem run vessel-scheduling by redirecting the AimmsCmd command file /inputs/single-run.properties as input to AimmsCmd in a docker container.
set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
set VS_INPUTS=%VS_ROOT%\inputs
set VS_OUTPUTS=%VS_ROOT%\outputs
docker run -i -v "%VS_INPUTS%:/inputs" -v "%VS_OUTPUTS%:/outputs" -w /model vesselscheduling:1.0.2.1 /bin/bash -c "/usr/local/Aimms/Bin/AimmsCmd VesselScheduling.aimms </inputs/single-run.properties >/outputs/single-run.log 2>/outputs/single-run.err"
pause
Alternatively, you can put the bash command in a bash script file, for instance aimmscmdrun.sh
as detailed above.
echo on
rem run vessel-scheduling by redirecting the AimmsCmd command file /inputs/single-run.properties as input to AimmsCmd in a docker container.
set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
set VS_INPUTS=%VS_ROOT%\inputs
set VS_OUTPUTS=%VS_ROOT%\outputs
docker run -i -v "%VS_INPUTS%:/inputs" -v "%VS_OUTPUTS%:/outputs" -w /model vesselscheduling:1.0.2.1 /bin/bash -c /model/aimmscmdrun.sh
pause
whereby aimmscmdrun.sh
is as above.
the reason for using aimmscmdrun.sh
is to apply the redirection to AimmsCmd
and not to docker
.
Using AimmsCmd in a container and running a service
echo on
rem Start the VesselScheduling app with a REST API Service, handling tasks to solve the VesselScheduling problem.
set VS_ROOT=C:\u\s\examples\application-examples\vessel-scheduling
set VS_INPUTS=%VS_ROOT%\inputs
set VS_OUTPUTS=%VS_ROOT%\outputs
docker run --rm -i -v "%VS_INPUTS%:/inputs" -v "%VS_OUTPUTS%:/outputs" -p 12003:12003 -w /model vesselscheduling:1.0.2.1 AimmsCmd --run-only dex::api::RESTServiceHandler "VesselScheduling.aimms"
pause
Remarks:
-p is used to publish a port.
You can subsequently use a REST API client to use the service exposed.
Running AIMMS headless inside the AIMMS Cloud
The handling of AIMMS and docker containers on the AIMMS Cloud is fully automated; hence this section is very brief.
Once an AIMMS application is published, its services are automatically available. No need to start the service explicitly; when a task for an application is posted, the corresponding AIMMS project is started and the task is handled.
More information can be found here.
Minimal Requirements
AIMMS Community license is sufficient for working with this example. To run the Python client, you will need to have Python installed, for this example we used Python 3.11.
To deploy the application on AIMMS Cloud, a commercial license is needed.
References
#. Gustavo Diz, Luiz Felipe Scavarda, Roger Rocha, Silvio Hamacher (2014) Decision Support System for PETROBRAS Ship Scheduling. Interfaces 44(6):555-566.
Release Notes
- v1.3 (07/10/2024)
Fixing integration problems (import and export) when using the project on AIMMS PRO Portal.
- v1.2 (23/09/2024)
Added support for AimmsCmd, the task output now has three sheets, and the python now reads from the data folder inside the AIMMS Project.
- v1.1 (19/09/2024)
Performance of the route generation procedure was updated. Now you are able to solve using a Python call.
- v1.0 (15/08/2024)
First version of this application.