The aimmspy
Python Module
The main features of the aimmspy
Python module are:
a seamless integration with existing AIMMS models from within a Python script
assign and retrieve data using Python dictionaries, Pandas, Polars or Arrow date frames
execute AIMMS procedures and retrieve results programmatically
The aimmspy
library has been built with pybind11 for high-performance C++
integration.
Installation Instructions
To install the aimmspy
module, you can use pip:
pip install aimmspy
However, in case you execute your Python script from within an AIMMS procedure (i.e. using pyaimms
), you do not need
to install the aimmspy
module. It is sufficient to add the aimmspy
reference in your project’s .toml
file.
This will make sure that aimmspy
is installed in the virtual Python environment that will be set up.
All Module Versions
To quickly list the versions of all modules being used in your Python script, you can use the show_dependencies()
method (available in the aimms.utils
module). This will print the version numbers of all modules that are being used.
Its output will may look like this:
re: 2.2.1
ctypes: 1.1.0
platform: 1.0.8
numpy: 2.2.4
pytz: 2025.2
dateutil: 2.8.2
decimal: 1.70
pyarrow: 19.0.1
six: 1.16.0
csv: 1.0
zlib: 1.0
json: 2.0.9
pandas: 2.2.3
polars: 1.26.0
aimmspy: 25.1.1.18
This information may bey useful in case you need to report an issue with the aimmspy
module or one of its dependencies.
Connecting to an AIMMS Project
To connect your Python script to an (already existing) AIMMS model, you will need to initialize an instance of the Project class by providing:
the path of the AIMMS executable
the path to the project file
the license url
Feel free to use the following project to follow this article:
Instead of the path to the AIMMS executable you can also provide just the AIMMS version number and use the function
find_aimms_path
(available in the aimms.utils
module) to figure out the location of the path to the AIMMS
executable.
If you have already a working, licensed AIMMS setup on your computer, there is no need to specify the license_url
in the constructor of the Project
instance.
After having created a project instance, you can retrieve the actual model by calling get_model
. The returned
model instance provides access to the identifiers in the model.
import os
from aimmspy.project.project import Project, Model
from aimmspy.utils import find_aimms_path
# Initialize the AIMMS project
project = Project(
# path to the AIMMS Bin folder (on linux the Lib folder)
aimms_path=find_aimms_path("25.4.3.3"),
# path to the AIMMS project
aimms_project_file=R"C:\AimmsProjects\MyAimmsProject\MyAimmsProject.aimms",
# url
license_url=R"wss://licensing.aimms.cloud/license-ws/license?profile=community&license=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
)
aimms_model: Model = project.get_model(__file__)
Of course, in case you are using a free AIMMS community license, you will need to replace the license code in the above snippet, by the license code of your community license.
Important
You can only connect to a single AIMMS project from within a Python script.
Identifier References
Identifier references (as an attribute of an instance of the project class) are case-sensitive. For example, if your AIMMS project contains an identifier Pi
and,
in your Python script, you created a reference to the associated model project with name aimms_model
, you will need to write aimms_model.Pi.data()
to retrieve the data for the identifier Pi
. Writing aimms_model.pi.data()
will show a Python _AttributeError_
with
message
'Model' object has no attribute 'pi'. Did you mean: 'Pi'?.
Namespace prefixes (e.g. for AIMMS identifiers inside a library) need to be separated by a dot character character.
Note that you will need to declare the library identifiers that you want to access in your Python script as public identifiers (on the attribute form of the library node in the AIMMS model tree).
Return Data Types
In this section we will focus on the data types that are used in Python to represent AIMMS data. For simple or medium sized AIMMS data you can use Python dictionaries. For large sized AIMMS data you might be better of using Python data frames.
Indexed data can be represented in
using Python dictionaries (see Python Dictionaries)
using Python data frames (see Python Data Frames)
using Arrow Tables (see Python Data Frames)
Python dictionaries are a simple and straight-forward way to contain data for a single identifier. However, when the data size gets really big and/or you want to store the data of multiple (similar) identifiers in the same data structure, it is recommended to use a data frame to store your data.
The default data return type for multi-dimensional data can be specified during project construction. It is possible to override the default return type on a per-statement level. More details about this in the section on Retrieving Data.
import os
from aimmspy.project.project import Project, Model
from aimmspy.utils import find_aimms_path
# Initialize the AIMMS project
project = Project(
# path to the AIMMS Bin folder (on linux the Lib folder)
aimms_path=find_aimms_path("25.4.3.3"),
# path to the AIMMS project
aimms_project_file=R"C:\AimmsProjects\MyAimmsProject\MyAimmsProject.aimms",
# default data type when retrieving multi-dimensional data
data_type_preference= DataReturnTypes.PANDAS
)
To communicate with scalar identifiers, plain Python string
and float
values are used.
Not surprisingly, values of scalar AIMMS string parameters and scalar element parameters are represented
as a string
in Python. A scalar element parameter in a calendar however, will return a Python
datetime value.
Values of scalar numerical identifiers are represented as a float
in Python.
Note
When retrieving datetime values from AIMMS, the Python data type will be datetime64[ms]
.
Python Dictionaries
When representing AIMMS data in a Python dictionary, we assume the following:
the keys in the dictionary are the tuples for which the identifier has non-default data
the value type of the values in the dictionary depends on the identifier type in the AIMMS model
Python Data Frames
When working with AIMMS data that is large or complex, it is often more efficient to use data frames.
For data transfer of large sized data, the aimmspy
Python module has support for two popular (and comparable)
data frame libraries, being:
Note
Special values (in AIMMS) are currently represented in Python in the following way:
the AIMMS value
inf
is translated into a Pythonfloat
with value 1e+150the empty label (in AIMMS) is translated into an empty Python string
the AIMMS values
zero
,undf
andna
are translated to a Python float with value 0.0
Dealing with Default Values
The translation of AIMMS data to Python data will be executed sparse, meaning that only non-default values
will be retrieved from AIMMS. Currently you can only retrieve data for a single identifier at a time.
For multi-dimensional data this means that no default values will be communicated to Python.
Scalar data with a default value are communicated to Python as values of type float
or string
, even in
case these scalar represent a default value.
When retrieving data from multi-dimensional AIMMS data identifiers with a non-default default value, you will have to deal with that in your Python script yourself (to ensure that all calculations in your Python script are correct).
Dealing with Units
Numerical values are communicated (both-ways) in the unit of the corresponding AIMMS identifier.
As in any AIMMS model, you can use conventions to change the identifier unit. This would allow you to input
data in, say, kilometers
while, after having changed the (model) convention, retrieve the same value in miles
.
Reference Manual
Project
- Project(aimms_path, aimms_project_file, exposed_identifier_set_name=None, license_url=None, data_type_preference=None)
Project
class constructor.- Arguments
aimms_path – the path to the AIMMS executable. You can use the
find_aimms_path
utility function to find the path for a specific AIMMS version.aimms_project_file – the path the the AIMMS project file.
exposed_identifier_set_name – optional, a model set (subset of
AllIdentifiers
) that contains all model identifiers that are available in your Python script. Defaults toAllIdentifiers
if not specified.license_url – optional, a reference to an AIMMS community cloud license url of the form
wss://licensing.aimms.cloud/license-ws/license?profile=community&license=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
, whereas thexxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
part needs to be replaced by the code of your AIMMS community license.data_type_preference – optional, the default return type when retrieving data from non-scalar data identifiers (by calling
.data()
on the associatedIdentifier
instance). Should be one ofDataReturnTypes.PANDAS
,DataReturnTypes.POLARS
, orDataReturnTypes.ARROW
. Defaults toDataReturnTypes.DICT
if not specified.
A Project
instance provides access to the AIMMS model through:
- get_model()
Returns an instance of the
Model
class.
- exposed_identifier_set()
Returns the set of all AIMMS model identifiers that are accessible from the Python script.
Important
In model with a lot of identifiers, you are advised to use the exposed_identifier_set_name
parameter to restrict
the accessible identifiers to those that are needed in your Python script.
Model
The Model
instance is retrieved through the get_model
method of the Project
instance.
During construction of the Model
instance, the aimmspy library will automatically create a stub
file that is can be to support you while editing your Python script using
Visual Studio Code.
To do so, when you are creating a Python script with name my_script.py
, the aimmspy library will create
a stub file with name
my_script.pyi
in the same directory as your Python script. This stub file contains all identifiers that are
available in the AIMMS model. To actually use the stub file, you should extend your script with something like:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from my_script import Model
The stub file will ensure that you can refer to any of the exposed identifiers as if it was an attribute of the Model
instance.
On the Model
instance you can find the following methods to read and write data to multiple identifiers.
Assigning Data
To assign data from Python objects to AIMMS identifiers two methods are available on instances of type DataIdentifier
.
- multi_assign(data, options=None)
Assigns data to the identifiers that are referred to in the columns of the data frame that is passed as the
data
argument. Please note that the identifiers are expected to share the same index domain.- Arguments
data – a Pandas or a Polars data frame, or an Arrow table.
options – a dictionary with options that can be used to control the behavior of the assignment.
Available options:
update
: If set toFalse
(default), the identifier will be emptied before the assignment is executed. If set toTrue
, the behavior is identical to that of theupdate
method.extendType
: Should be one of the following (string) values:extend
(default): Elements that are not in a domain set yet, will be automatically added (assumed the set is updatable).error
: AnAimmsPyException
will be thrown when encountering an element that is outside of one of the domain sets.filter
: Tuples with an element that is outside the domain will be silently ignored.
mapping
: A string-to-string map in which the key should correspond to a column name in the date frame and the corresponding values should refer to the associated identifier name in the AIMMS model.
For example:
city_data_df = pd.DataFrame({
"c": [ 'Amsterdam', 'Haarlem' ],
"NumInhabitants": [ 741636, 147590 ],
"Longitude": [ 4.88969, 4.63683 ],
"Latitude": [ 52.37403, 52.38084 ]
})
aimms_model.multi_assign(city_data_df)
Retrieving Data
- multi_data(identifier_list, options=None)
To retrieve data from multiple AIMMS identifiers into a single data frame, you can use the
.multi_data()
method on an instance of typeProject
. The return value will be a Pandas or Polars data frame, or an Arrow table. Again (as when assigning data to multiple identifiers in one go), the identifiers are expected to share the same index domain.- Arguments
identifier_list – a list containing the names.
options – optional, a dictionary with options that can be used to specify the return type of the data.
When retrieving data from multiple identifiers at once, you can specify how you want default values to appear. For this purpose,
a new boolean writeDefaults
option has been introduced.
At all times, a return value of the multi_data()
method will return sparse data, meaning that it will never return a row in
which all identifiers have a default value. By default, default values will appear as NaN
in the returned data frame.
However, if you set the writeDefaults
option to True
, the returned data will show the default value for the
identifier at hand.
For example:
city_data_df = aimms_model.multi_data(["NumInhabitants", "Longitude", "Latitude"], {"return_type": DataReturnTypes.PANDAS})
DataIdentifier
Assigning Data
To assign data from Python objects to AIMMS identifiers two methods are available on instances of type DataIdentifier
.
- assign(data, options=None)
Assigns data to the identifier that is associated with the
DataIdentifier
instance.- Arguments
data –
data
should be anint
,float
, astring
, adatetime
object, a dictionary, a Pandas or a Polars data frame, or an Arrow table. For set identifiers,data
is expected to be a Python list or set object.options – a dictionary with options that can be used to control the behavior of the assignment.
Available options:
update
: If set toFalse
(default), the identifier will be emptied before the assignment is executed. If set toTrue
, the behavior is identical to that of theupdate
method.extendType
: Should be one of the following (string) values:extend
(default): Elements that are not in a domain set yet, will be automatically added (assumed the set is updatable).error
: AnAimmsPyException
will be thrown when encountering an element that is outside of one of the domain sets.filter
: Tuples with an element that is outside the domain will be silently ignored.
mapping
: A string-to-string map in which the key should correspond to a column name in the date frame and the corresponding values should refer to the associated identifier name in the AIMMS model.
The options can be combined in a dictionary, for example:
{ "update": True, "extendType": "filter", {"mapping": { "MyColumnName": "MyIdentifierName"} }
For example:
num_inhabitants_data_df = pd.DataFrame({
"c": [ 'Amsterdam', 'Haarlem' ],
"Number of Inhabitants": [ 741636, 147590 ]
})
aimms_model.NumInhabitants.assign(num_inhabitants_data_df, { "update": True, "mapping": { "Number of Inhabitants": "NumInhabitants"} })
- update(data, options=None)
Assigns data to the identifiers. Same as
data
withupdate
option set toTrue
.
Retrieving Data
- data(options=None)
To retrieve data from AIMMS identifiers, you can use the
.data()
method on an instance of typeDataIdentifier
. The return value will be afloat
,string
or adatetime
object for scalar identifiers, and a dictionary, a Pandas or Polars data frame, or an Arrow table for multi-dimensional identifiers.- Arguments
options – optional, a dictionary with options that can be used to specify the return type of the data.
For example, to enforce the return type to be a Pandas DataFrame, you can use the following for the options
argument:
{ "return_type": DataReturnTypes.PANDAS }
Using this for the NumInhabitants
identifier that we used in the previous session would for example look like:
num_inhabitants = aimms_model.NumInhabitants.data({ "return_type": DataReturnTypes.PANDAS })
print(f"num_inhabitants:\n{num_inhabitants}")
which would yield the following output:
num_inhabitants:
c NumInhabitants
0 Amsterdam 741636.0
1 Haarlem 147590.0
The default return type for multi-dimensional identifiers can be set during the construction of the Project
instance.
Running Procedures
Procedure can be executed directly using the Model
instance. Just create a reference to the procedure and add to brackets
(in case of a procedure without arguments) to trigger execution.
So far, we only support scalar input arguments for procedures. The order of the arguments needs to match the order in which they are declared in the model. The return value will be the return value of the AIMMS procedure. For example:
retval = aimms_model.SetInterestRate(rate=1.06)
Exceptions
The aimmspy
module introduces two custom exceptions:
AimmsException
: Exceptions that are generated in AIMMS itself, either raised from model or due to some other internal issue.AimmsPyException
: Exceptions that are raised in theaimmspy
Python module, i.e. the part of the code that is responsible for the communication between Python and AIMMS.
For example,
additional_num_inhabitants_data = pd.DataFrame({
"c": [ 'Invalid City' ],
"NumInhabitants": [ 123456 ]
})
try:
aimms_model.NumInhabitants.assign(additional_num_inhabitants_data, {"update": True, "extendType": "error"})
except AimmsPyException as e:
print(f"Invalid set element raised an AimmsPyException (as expected): {e}")
would yield the following output:
Invalid set element raised an AimmsPyException (as expected): Invalid element 'Invalid City