Data Exchange
Topics covered in this chapter:
Python to Mosel data flow
MoselPy enables bidirectional data exchange in memory between Python and Mosel through the moselpy: I/O driver.
Basic pattern
Data exchange uses Mosel's initializations blocks with the "moselpy:" driver. In the Mosel model, use initializations from "moselpy:" to receive input data from Python and initializations to "moselpy:" to send output data back. The following example demonstrates multiple types at once (a string, an integer, and an array):
Note: initializations from/to "moselpy:" can be used with local or global entities. For access via find_identifier() after execution, the explicit public keyword is required; entities are private by default (see Section Accessing results). When compiled with the g or G flag, all globally declared entities become visible to find_identifier().
model DataDemo
uses "mmsystem"
declarations
user_name: string
num_items: integer
values: array(1..3) of real
total: real
message: text
end-declarations
initializations from "moselpy:"
user_name num_items values
end-initializations
total := sum(i in 1..3) values(i)
message := "Hello " + user_name + "! Total is " + total
initializations to "moselpy:"
total message
end-initializations
end-model Pass input as a dictionary to run(). The method returns a dictionary of all output values:
import moselpy as mp
mp.compile_model("datademo.mos", "datademo.bim")
model = mp.load_model("datademo.bim")
output = model.run(input_data={
"user_name": "Alice",
"num_items": 5,
"values": {1: 10.0, 2: 20.0, 3: 30.0}
})
print(output['message'])
print(f"Total: {output['total']}") Output:
Hello Alice! Total is 60 Total: 60.0
See Section Parameterising the data source for how to make this model runnable standalone for testing.
Type mapping
The sections below show code examples for each type. For the full type conversion table including NumPy and bytes support, see Chapter I/O Driver.
Scalars
Scalar types (integer, real, string, boolean) are passed directly as Python values:
# All scalar types together
data = {
"count": 42, # integer
"price": 19.99, # real
"name": "Widget", # string
"active": True, # boolean
} Arrays
Mosel arrays are passed as Python dicts, where keys are the array indices and values are the data:
# Mosel: values: array(1..3) of real
data = {"values": {1: 10.0, 2: 20.0, 3: 30.0}}
# Built from a list using a loop
values_list = [10.0, 20.0, 30.0]
data = {"values": {i+1: v for i, v in enumerate(values_list)}} For 2D arrays, use tuple keys:
# Mosel: array(ROWS, COLS) of real -- explicit
data = {"matrix": {(1, 1): 5.0, (1, 2): 10.0, (2, 1): 15.0, (2, 2): 20.0}}
# Built from nested lists using loops
rows, cols = [1, 2], [1, 2]
values = [[5.0, 10.0], [15.0, 20.0]]
data = {"matrix": {(r, c): values[i][j]
for i, r in enumerate(rows)
for j, c in enumerate(cols)}} Sets
Python set maps directly to a Mosel set. Several common ways to build one:
# Mosel: PRODUCTS: set of string
# Literal
data = {"PRODUCTS": {"Widget", "Gadget", "Gizmo"}}
# From a list (preserves no order, as sets are unordered)
products = ["Widget", "Gadget", "Gizmo"]
data = {"PRODUCTS": set(products)}
# From a DataFrame or Series index
data = {"PRODUCTS": set(demand_df.index)}
data = {"MONTHS": set(capacity_series.index)}
# Integer set from a range
data = {"PERIODS": set(range(1, 13))} # 1..12 Lists
Python list maps to a Mosel list (an ordered sequence). Pass directly or build from a range:
# Literal
data = {"months": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]}
# From range
data = {"periods": list(range(1, 7))} # [1, 2, 3, 4, 5, 6]
# From an existing collection
data = {"products": list(demand_df.index)} Pandas integration
MoselPy converts Pandas Series and DataFrames to Mosel arrays automatically, using the index as the set dimension, for both input and output. In Mosel, declare arrays indexed by a dynamic set; the set is populated automatically when the array data is read:
model SupplyDemand
declarations
CITIES: set of string
Demand, Capacity: array(CITIES) of real
Revenue: array(CITIES) of real ! output
end-declarations
! CITIES populated automatically from the Series index when reading array data
initializations from "moselpy:"
Demand Capacity
end-initializations
forall(c in CITIES) Revenue(c) := Demand(c) * 10.0
initializations to "moselpy:"
Revenue
end-initializations
end-model import pandas as pd
import moselpy as mp
model = mp.load_model("supply.bim")
# Input: pass Series/DataFrame directly in input_data
demand = pd.Series({"NYC": 100, "LA": 80, "CHI": 90})
capacity = pd.Series({"NYC": 120, "LA": 100, "CHI": 85})
output = model.run(input_data={"Demand": demand, "Capacity": capacity})
# Output 1D: wrap dict in pd.Series, or use find_identifier(use_pandas=True)
revenue = pd.Series(output["Revenue"])
# or: revenue = model.find_identifier("Revenue", use_pandas=True) 2D arrays. For a 2D Mosel array (e.g. Production: array(PRODUCTS, MONTHS) of real), find_identifier(use_pandas=True) returns a MultiIndex Series. Call unstack() to get a DataFrame with rows and columns matching the Mosel index sets:
production_series = model.find_identifier("Production", use_pandas=True)
production_df = production_series.unstack(level=1)
print(production_df) Output:
Jan Feb Mar Apr May Jun Gadgets 53.33 53.33 53.33 53.33 53.33 46.67 Gizmos 60.00 70.00 80.00 75.00 65.00 55.00 Widgets 0.00 0.00 0.00 0.00 0.00 0.00
Parameterising the data source
The initializations blocks allow switching between data sources of different types by parameterising the source name. Use a string parameter DATASOURCE that defaults to a local .dat file for standalone execution; when calling from Python, pass DATASOURCE="moselpy:" via exec_params:
parameters DATASOURCE = "mydata.dat" ! default: read from file when running standalone end-parameters ! ... declarations ... initializations from DATASOURCE x y z end-initializations ! ... model logic ... initializations to DATASOURCE result end-initializations
Run standalone for testing (reads/writes mydata.dat):
mosel model.mos
Run from Python (uses the moselpy: driver for live data exchange):
model.run(exec_params={"DATASOURCE": "moselpy:"}, input_data={...}) © 2001-2026 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.
