IBM Maximo Application Suite · Predict · A worked example, told as it happened

Maximo Predict, one full example: from a Jupyter notebook to a predicted failure date

Most Predict material stops at the slide that says "train a model in Watson Studio". This post does the whole exercise on a live system: load IBM's sample pumps, train the Predicted Failure Date model in a notebook, register it, and get scores into the database. It also reports the seven things that went wrong on the way, because those are what will cost you a day if nobody tells you.

What you will learn

Reading time: about 15 minutes. System: MAS 9.2 (Manage, Monitor, Health, Predict 9.2.x) on OpenShift 4.21, Cloud Pak for Data with Watson Studio and Watson Machine Learning, Db2. Library: pmlib 9.2.6.dev10800.

1. What Predict is, in one picture

Predict has almost no screen of its own. It is a small API server plus a Python library, and it borrows everything else from its neighbours.

Manageassets, failures Monitorsensor readings Notebook (pmlib)Watson Studio, CP4D Predict APImodel registry Monitor pipelinescheduled scoring Health and Predictthe screen users see
PieceWhat it does in this example
ManageHolds the five pumps, their installation dates and their failure history.
MonitorHolds the sensor readings, and later runs the trained model on a schedule.
Watson Studio (Cloud Pak for Data)Runs the Jupyter notebooks. This is where you train.
pmlibIBM's Python library. It reads from Manage and Monitor, trains, and talks to the Predict API.
Predict APITwo pods. Keeps the list of registered models and hands credentials to the notebook.
Health and PredictThe application in Manage where a reliability engineer reads the result.

2. Where Predict keeps its data

A fair question when you first see a table called MAS_INSTDB2_PREDICT.PMITENANT: does Predict have its own database? On this system, no. It has its own schemas inside the same Db2 database that Manage and Monitor use. Predict was bound to the suite's system JDBC configuration at install time, so it landed next to them.

One Db2 database, several schemas. Predict's three schemas are in blue. The data it learns from stays with Manage and Monitor; the trained model files go to Watson Machine Learning.
SchemaOwnerWhat is in it
MAS_<inst>_PREDICTPredict7 tables. PMITENANT: one row with the Manage, Monitor and Watson ML addresses and an integration status. MODEL_TEMPLATE and ASSET_GROUP_MODEL_INSTANCE: the models you register. PMIMAHIAPIKEY: Manage API keys.
MAS_<inst>_PREDICT_EXP_MASTER_…
MAS_<inst>_PREDICT_EXP_META_…
PredictExplainability: predictions, explanations, payloads, models, explainers.
MAXIMOManageAssets, failure reports, asset groups. Later, the scores shown in Health (APMVALUE).
<workspace>_MAM (here WSP_MAM)MonitorOne table of readings per device type (IOT_PUMP_AFM_1) and one table of results per asset group (DM_DEVICE_TYPE_NEW_AFMGRP_…).
Why this matters. Predict's own schemas hold configuration and a registry, nothing else. If you back up or restore "the Predict database" you have moved a few rows. The readings are Monitor's, the assets are Manage's, and a restored PMITENANT row still points at the system it came from. That last point is problem 4 below.

3. Before the first cell: three fixes

Predict creates a Watson Studio project with IBM's notebooks, sample CSV files and a README. Three things in it did not match the system.

3.1 The runtime must be Python 3.12

The README says Python 3.10. The default notebook environment is 3.11. The library ships a compiled part built for 3.12, so on anything else the install fails:

"not a supported wheel on this platform": the cp312 in the file name means Python 3.12 only.

Create an environment template on Runtime 25.1 on Python 3.12 (Manage › Environments › Templates › New template; 4 vCPU and 16 GB is enough), then give it to each notebook from the project's Assets list: row menu › Change environment. The runtime must be stopped first.

A new template on Runtime 25.1 / Python 3.12.
Change environment on the notebook.

3.2 Tell the notebook where Monitor is

The notebooks read the Monitor address from an environment variable that nothing sets, and stop with a TypeError a few cells later. Add one cell before the cell that reads Predict_Envs.json:

import os
os.environ['API_BASEURL'] = 'https://<workspace>.api.monitor.<instance>.<cluster domain>'

3.3 Put pmlib.zip in the project

The project lists a data asset called pmlib.zip, but the file behind it was missing. Download it once from the Predict API into the project's data folder (196 MB); every notebook then installs from the local copy:

!curl -sk -o /project_data/data_asset/pmlib.zip \
  "${APM_API_BASEURL}/ibm/pmi/service/rest/ds/${APM_ID}/${APM_API_KEY}/lib/download?filename=pmlib"
The API key is in that address. pmlib also prints the full address in some warning lines. Keep the output of those cells out of screenshots and shared notebooks, and rotate the key if it has been shown.

The last prerequisite is the file Predict_Envs.json: three values (APM_ID, APM_API_BASEURL, APM_API_KEY) that you copy from Health and Predict and save in the project.

4. Step 1: load the sample data

Notebook: FastStart2021Loader-New. It runs 46 cells and builds the whole scenario.

The loader notebook opens with IBM's own map of the exercise.
What it createsWhereOn our system
Five assetsManageNEW_DEVICE001, 003, 005, 007, 009 at site BEDFORD, installed 2010 to 2016
Failure historyManageFailure class PUMPS, problem STOPPED
An asset groupManageNEW_AFMGRP
A device type with 8 readingsMonitorPump_AFM: velocity X, Y, Z, motor temperature, winding temperature, current, pressure, load
Sensor historyMonitor296,857 rows in WSP_MAM.IOT_PUMP_AFM_1
The link asset ↔ devicePredict / Monitor5 rows in APM_ASSET_DEVICES

The sample data is from 2008 onwards. The loader shifts every date forward so the history ends near today; here the shift was 6,553 days and the readings ended on 3 August 2026.

5. Step 2: train the model

Notebook: PMI - Predicted Failure Date. The cell that matters describes the model in one Python dictionary: which readings to use, how to summarise them, and what to predict.

group = TimeToFailureAssetGroupPipeline(
    asset_group_id=asset_group_id,                      # NEW_AFMGRP
    model_pipeline={
        "features": ['Pump_AFM:velocityx', 'Pump_AFM:velocityy', 'Pump_AFM:velocityz'],
        "features_resampled": {'Pump_AFM': {'${freqency}': '1D',
            'velocityx': {'mean': None}, 'velocityy': {'mean': None}, 'velocityz': {'mean': None}}},
        "predictions": ['predicted_time_to_failure', 'predicted_failure_date'],
    })
df = group.execute()

In plain words: take the three vibration readings, average them per day, join them with each pump's installation and failure dates, and learn how long a pump with that vibration pattern has left. Training took about one minute.

One cell trains the model and returns the predictions as a table.

df now holds 1,186 predictions: one per pump per day.

The result in the notebook. On 8 July 2026 the model gave NEW_DEVICE009 about 526 days: a predicted failure date of 15 December 2027.

6. Step 3: register and schedule

model_instance_id = group.register()
group.enable(enabled=True, schedule={"starting_at": "05:00:01", "every": "5min"})

register() stores the model files in Watson Machine Learning, writes one row in Predict's MODEL_TEMPLATE and one in ASSET_GROUP_MODEL_INSTANCE, and creates the two output items in Monitor. enable() asks Monitor to run the model on a schedule.

Register returns a model ID; enable returns HTTP 200.

The model is then visible in Manage under Health and Predict › Prediction settings:

The asset group the loader created.
One trained instance, template "Predicted Failure Date", every 5 minutes, active, five scored assets.

7. Step 4: get the scores

This is where the run stopped being smooth. register() is meant to save the first predictions to Monitor. It reported success and saved nothing: both result tables had zero rows. The cause is problem 5 in the log below. With a two-line patch in the notebook, the write went through:

from pmlib import api as _api
_t = _api.get_new_monitor_table_name_for_prediction_result
_api.get_new_monitor_table_name_for_prediction_result = lambda db, name, cols: _t(db, asset_group_id, cols)
group._write(df)
"initial results written".

The database confirms it: 2,372 rows in each of the two result tables in Monitor's schema (1,186 timestamps × 2 outputs; one table for the raw output, one for the daily summary). The latest score for each pump:

AssetInstalledLast scored dayDays to failurePredicted failure date
NEW_DEVICE0012016-03-012026-06-09515.62027-11-06
NEW_DEVICE0032012-05-012026-07-04524.62027-12-10
NEW_DEVICE0052010-10-012026-08-03521.62028-01-06
NEW_DEVICE0072011-08-012026-07-24523.62027-12-29
NEW_DEVICE0092014-12-012026-07-15492.02027-11-19
select ENTITY_ID, KEY, VALUE_N, VALUE_T, TIMESTAMP
from WSP_MAM.DM_DEVICE_TYPE_NEW_AFMGRP_3_0L
where KEY in ('predicted_time_to_failure', 'predicted_failure_date')
order by ENTITY_ID, TIMESTAMP desc;

Monitor result tables are tall: one row per asset, timestamp and output name, with the value in VALUE_N (number) or VALUE_T (date).

8. Step 5: what Health and Predict shows

The honest state at the end of this run:

ItemState
Model trained in the notebookYes
Model registered, listed in Prediction settingsYes
Predictions in Monitor's result tablesYes, 2,372 rows per table, after the notebook patch
Scheduled scoring every 5 minutesNo. Every run fails (problem 6)
"Next failure" card on the asset's Predict tabNo. Still empty (problem 7)

So on this build the example gets from a notebook to scores in the database, and stops one step short of the card a reliability engineer would look at. I am publishing it at that point on purpose: the last two rows are product defects, confirmed in the logs and in the library source, and they belong in a support case rather than in more workarounds.

9. The field log: seven problems, in order

#SymptomCauseWhat I did
1TypeError in the environment cellAPI_BASEURL is not set, so the Monitor address is emptyOne added cell (section 3.2)
2No such file: pmlib.zipThe data asset exists but has no fileDownloaded it once (section 3.3)
3"not a supported wheel on this platform"The library is built for Python 3.12; the default runtime is 3.11New environment template (section 3.1)
4group.register() returns HTTP 500The database had been restored from another cluster. PMITENANT still held that cluster's Monitor address, with status COMPLETESet the status to PENDING; Predict re-ran its integration within 30 seconds
5Register succeeds, no predictions in the databasepmlib takes the asset group ID from the table name by splitting on "_". dm_new_afmgrp becomes new. The error is caught and logged at debug level onlyNotebook patch (section 7). Or use a group ID without an underscore
6Scheduled scoring fails every runOn the first run Monitor passes an end time and no start time; pmlib rejects that when the model uses features_resampled. A failed run leaves no checkpoint, so the next run is a "first run" againOpen. Training without resampling should avoid it; not tested here
7"Next failure" stays emptyPredict's background job that copies results into Manage stops with java.lang.String incompatible with JSONObject while reading the model's outputsOpen

Problem 4 in detail: a restored database remembers its old home

Predict integrates with Monitor once, stores the result in PMITENANT, and marks it COMPLETE. A background job looks only for rows marked PENDING. After a restore from another environment, the row is complete and wrong. Predict's own log says what to do (it suggests changing the status to PENDING). Take a copy first:

create table CRBKP.PREDICT_PMITENANT_BAK as (select * from MAS_INSTDB2_PREDICT.PMITENANT) with data;
update MAS_INSTDB2_PREDICT.PMITENANT set MAS_INTG_STATUS = 'PENDING' where PMI_TENANT_ID = 1;

Within half a minute the row carried this cluster's Monitor address and was back to COMPLETE.

How I confirmed problems 5 and 6

Both are in the library you already downloaded. Unzip pmlib.zip and read pmlib/persist.py (the split on "_") and pmlib/pipeline.py (search for "when resampling is used"). For problem 6, the log of the failed job pod in the Monitor namespace ends with the same sentence. Reading the source took ten minutes and saved guessing.

Two smaller surprises. group.enable(enabled=False) returned HTTP 500 although Monitor answered "updated": Predict could not read Monitor's reply. And a note from the keyboard: in Jupyter, typing while a cell is selected but not in edit mode fires shortcuts. I restarted my own kernel that way and had to retrain.

10. A checklist for your own run

  1. Monitor, Health and Predict are active, and Predict's PMITENANT row shows your Monitor address.
  2. The notebook environment is Runtime 25.1 / Python 3.12.
  3. Predict_Envs.json and pmlib.zip are both in the project's data assets.
  4. The cell that sets API_BASEURL is in each notebook.
  5. Run the loader notebook fully before any model notebook.
  6. After register(), count the rows in the group's DM_DEVICE_TYPE_… tables. Zero means the first write failed silently.
  7. After enable(), look at the newest <workspace>.g1.… job pod in the Monitor namespace. Its log tells you in one line whether scoring ran.
  8. Keep the API key out of notebook output, and rotate it when you finish.
The one idea to keep. Predict is a thin layer over Manage, Monitor and Watson Studio. When it misbehaves, the answer is almost never in Predict's screen. It is in one of three places: the notebook output, the job pod's log in Monitor, or a row in PMITENANT.

Written from a single run on a demo system on 3 October 2026. Versions and behaviour may differ on your build; the defects described here are as observed with pmlib 9.2.6.dev10800 and are not official IBM statements.