Initializing help system before first use

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.