Reliability-Centered Maintenance in Maximo: Building an RCM Program with FMEA Templates, Failure Codes, and Asset Strategies

>

Share
Reliability-Centered Maintenance in Maximo: Building an RCM Program with FMEA Templates, Failure Codes, and Asset Strategies

Reliability-Centered Maintenance in Maximo: Building an RCM Program with FMEA Templates, Failure Codes, and Asset Strategies

Reliability-Centered Maintenance is the most rigorous approach to maintenance strategy development. It asks four fundamental questions about every asset: what can fail, how can it fail, what happens when it fails, and what should we do about it. The answers to these questions determine whether an asset receives preventive maintenance, predictive monitoring, run-to-failure treatment, or redesign.

Maximo provides the data structures to support RCM, but the structures alone do not create a program. This article covers how to build a functioning RCM program in Maximo, from criticality analysis through FMEA template design, failure code hierarchies, asset strategy deployment, and the feedback loops that keep the program alive.

The RCM Framework in Maximo

RCM in Maximo is not a single application. It is a methodology supported by several interconnected data structures:

┌─────────────────────────────────────────────────────────────┐
│ RCM Data Architecture │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Criticality │ │ Failure Codes │ │
│ │ Assessment │────▶│ Hierarchy │ │
│ │ (Asset criticality│ │ (Problem → Cause │ │
│ │ ranking) │ │ → Remedy) │ │
│ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ FMEA / RCM Analysis │ │
│ │ (Failure modes, effects, criticality, │ │
│ │ maintenance task selection) │ │
│ └────────────────────┬─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ Asset Strategy / PM │ │
│ │ (Preventive maintenance schedules, │ │
│ │ condition monitoring tasks, │ │
│ │ inspection routes) │ │
│ └────────────────────┬─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ Work Order Feedback │ │
│ │ (Actual failures vs. predicted, │ │
│ │ strategy effectiveness, │ │
│ │ continuous improvement) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Each layer feeds the next. Criticality determines which assets receive RCM analysis. Failure codes provide the taxonomy for describing failures. FMEA analysis identifies failure modes and selects maintenance tasks. Asset strategies deploy those tasks as scheduled PMs and condition monitoring. Work order feedback validates whether the strategies are working.

Criticality Analysis: Where to Start

RCM is resource-intensive. You cannot apply it to every asset. Criticality analysis identifies which assets justify the investment.

The Criticality Matrix

A criticality matrix evaluates each asset on two dimensions: the consequence of failure and the probability of failure. Assets with high consequence and high probability receive the most rigorous RCM treatment.

Low Probability Medium Probability High Probability
High Consequence RCM Analysis RCM Analysis RCM Analysis + Condition Monitoring
Medium Consequence PM Review RCM Analysis RCM Analysis
Low Consequence Run to Failure PM Review PM Review

Consequence is typically evaluated across multiple dimensions: safety, environmental, operational, and financial. Each dimension is scored, and the highest score determines the overall consequence rating.

Implementing Criticality in Maximo

Maximo supports criticality through the asset record's failure class and criticality fields. However, a robust criticality program requires more structure:

-- Create a custom criticality assessment table
-- This extends the built-in asset criticality with multi-factor scoring

CREATE TABLE ASSETCRITICALITY (
ASSETCRITID BIGINT NOT NULL,
ASSETNUM VARCHAR(12) NOT NULL,
ASSESSMENTDATE DATE NOT NULL,
SAFETY_SCORE INT, -- 1-10: 10 = catastrophic safety consequence
ENVIRONMENTAL_SCORE INT, -- 1-10: 10 = major environmental release
OPERATIONAL_SCORE INT, -- 1-10: 10 = complete plant shutdown
FINANCIAL_SCORE INT, -- 1-10: 10 = >$1M financial impact
PROBABILITY_SCORE INT, -- 1-10: 10 = failure expected within 1 year
OVERALL_CRITICALITY VARCHAR(20), -- HIGH, MEDIUM, LOW
ASSESSEDBY VARCHAR(30),
NEXTASSESSMENTDATE DATE,
PRIMARY KEY (ASSETCRITID)
);

-- Calculate overall criticality based on the highest consequence score
-- and the probability score
CREATE OR REPLACE VIEW ASSETCRITICALITY_VIEW AS
SELECT
a.ASSETNUM,
a.DESCRIPTION,
a.LOCATION,
ac.SAFETY_SCORE,
ac.ENVIRONMENTAL_SCORE,
ac.OPERATIONAL_SCORE,
ac.FINANCIAL_SCORE,
ac.PROBABILITY_SCORE,
GREATEST(ac.SAFETY_SCORE, ac.ENVIRONMENTAL_SCORE,
ac.OPERATIONAL_SCORE, ac.FINANCIAL_SCORE) AS MAX_CONSEQUENCE,
CASE
WHEN GREATEST(ac.SAFETY_SCORE, ac.ENVIRONMENTAL_SCORE,
ac.OPERATIONAL_SCORE, ac.FINANCIAL_SCORE) >= 8
AND ac.PROBABILITY_SCORE >= 5 THEN 'HIGH'
WHEN GREATEST(ac.SAFETY_SCORE, ac.ENVIRONMENTAL_SCORE,
ac.OPERATIONAL_SCORE, ac.FINANCIAL_SCORE) >= 5
AND ac.PROBABILITY_SCORE >= 3 THEN 'MEDIUM'
ELSE 'LOW'
END AS OVERALL_CRITICALITY
FROM ASSET a
JOIN ASSETCRITICALITY ac ON a.ASSETNUM = ac.ASSETNUM
WHERE ac.ASSESSMENTDATE = (
SELECT MAX(ASSESSMENTDATE) FROM ASSETCRITICALITY
WHERE ASSETNUM = a.ASSETNUM
);

Automation Script for Criticality Calculation

An automation script can calculate and update criticality automatically when asset data changes:

# Automation Script: Calculate Asset Criticality
# Launch Point: OBJECT - ASSET - Save - After Save
# Updates the asset's criticality based on multi-factor scoring

def calculate_criticality():
"""
Calculate and update asset criticality based on safety, environmental,
operational, and financial consequence factors.
"""

# Get consequence scores from the asset or its classification
safety_score = mbo.getInt("SAFETYCRITICALITY", 0)
env_score = mbo.getInt("ENVIRONMENTALCRITICALITY", 0)
ops_score = mbo.getInt("OPERATIONALCRITICALITY", 0)
fin_score = mbo.getInt("FINANCIALCRITICALITY", 0)

# Calculate probability based on asset age, condition, and failure history
probability_score = calculate_failure_probability(mbo)

# Determine overall criticality
max_consequence = max(safety_score, env_score, ops_score, fin_score)

if max_consequence >= 8 and probability_score >= 5:
criticality = "HIGH"
elif max_consequence >= 5 and probability_score >= 3:
criticality = "MEDIUM"
else:
criticality = "LOW"

# Update the asset record
mbo.setValue("CRITICALITY", criticality, MboConstants.NOACCESSCHECK)

# Log the assessment
logger = MXLoggerFactory.getLogger("maximo.rcm")
logger.info(
"Asset {} criticality calculated: {} (Safety={}, Env={}, Ops={}, Fin={}, Prob={})".format(
mbo.getString("ASSETNUM"), criticality,
safety_score, env_score, ops_score, fin_score, probability_score
)
)

def calculate_failure_probability(asset_mbo):
"""
Calculate failure probability score based on asset age, condition,
and failure history.
"""
score = 5 # Default moderate probability

# Factor 1: Asset age relative to expected life
install_date = asset_mbo.getDate("INSTALLDATE")
expected_life = asset_mbo.getInt("EXPECTEDLIFE", 20)
if install_date:
from java.util import Calendar, Date
from java.time import LocalDate, ZoneId, Period

install_local = install_date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
age_years = Period.between(install_local, LocalDate.now()).getYears()

if age_years > expected_life * 0.8:
score += 3 # Near end of life
elif age_years > expected_life * 0.5:
score += 1 # Mid-life

# Factor 2: Recent failure history
wo_set = asset_mbo.getMboSet("WORKORDER")
wo_set.setWhere("STATUSDATE >= SYSDATE - 365 AND WORKTYPE IN ('EM', 'CM')")
failure_count = wo_set.count()

if failure_count > 10:
score += 3
elif failure_count > 5:
score += 2
elif failure_count > 2:
score += 1

# Factor 3: Condition rating
condition = asset_mbo.getInt("CONDITIONRATING", 50)
if condition < 30:
score += 3
elif condition < 50:
score += 1

return min(score, 10) # Cap at 10

# Execute
calculate_criticality()

Building a Failure Code Hierarchy

Failure codes are the taxonomy of your RCM program. Without a well-structured failure code hierarchy, you cannot analyze failure patterns, identify dominant failure modes, or measure strategy effectiveness.

The Problem-Cause-Remedy Structure

Maximo supports a three-level failure code hierarchy:

Failure Class (Top Level)
├── Problem (What happened?)
│ ├── Cause (Why did it happen?)
│ │ └── Remedy (What was done about it?)

For example, for a centrifugal pump:

PUMP-FAILURE (Failure Class)
├── LOW-FLOW (Problem)
│ ├── IMPELLER-WEAR (Cause)
│ │ ├── REPLACE-IMPELLER (Remedy)
│ │ └── REBUILD-PUMP (Remedy)
│ ├── SUCTION-BLOCKAGE (Cause)
│ │ ├── CLEAR-BLOCKAGE (Remedy)
│ │ └── CLEAN-STRAINER (Remedy)
│ └── MOTOR-UNDERSPEED (Cause)
│ ├── REPAIR-MOTOR (Remedy)
│ └── REPLACE-MOTOR (Remedy)
├── EXCESSIVE-VIBRATION (Problem)
│ ├── MISALIGNMENT (Cause)
│ │ ├── REALIGN-PUMP (Remedy)
│ │ └── REPLACE-COUPLING (Remedy)
│ ├── BEARING-FAILURE (Cause)
│ │ ├── REPLACE-BEARINGS (Remedy)
│ │ └── REPLACE-SHAFT (Remedy)
│ └── CAVITATION (Cause)
│ ├── ADJUST-SUCTION (Remedy)
│ └── REDESIGN-INLET (Remedy)
└── SEAL-LEAK (Problem)
├── SEAL-WEAR (Cause)
│ ├── REPLACE-SEAL (Remedy)
│ └── UPGRADE-SEAL (Remedy)
└── IMPROPER-INSTALL (Cause)
├── REINSTALL-SEAL (Remedy)
└── TRAIN-TECHNICIAN (Remedy)

Designing the Hierarchy

A good failure code hierarchy has these properties:

  1. Mutually exclusive problems: Each problem should describe a distinct failure mode. If two problems overlap, technicians will be inconsistent in their coding.
  2. Exhaustive causes: The causes under each problem should cover all reasonably likely root causes. An "OTHER" cause is acceptable but should be used rarely.
  3. Actionable remedies: Each remedy should describe a specific corrective action. "INSPECT" is not a remedy. "REPLACE-BEARINGS" is a remedy.
  4. Appropriate granularity: Too few codes, and you cannot distinguish between failure modes. Too many codes, and technicians will default to the first one in the list.

The hierarchy should be designed by reliability engineers in collaboration with experienced technicians. Engineers understand the failure modes. Technicians understand what they actually see in the field. Both perspectives are necessary.

FMEA Templates in Maximo

FMEA (Failure Mode and Effects Analysis) is the analytical engine of RCM. It systematically evaluates each failure mode for each asset, assesses its risk, and selects appropriate maintenance tasks.

The FMEA Data Structure

Maximo does not have a built-in FMEA application, but you can model FMEA using custom objects or by extending the asset template functionality:

-- Custom FMEA table structure
CREATE TABLE FMEA_ANALYSIS (
FMEAID BIGINT NOT NULL,
ASSETNUM VARCHAR(12) NOT NULL,
FAILURECLASS VARCHAR(30),
PROBLEMCODE VARCHAR(30),
FAILUREMODE VARCHAR(100),
FAILUREEFFECT VARCHAR(500),
SEVERITY INT, -- 1-10: How bad is the failure?
OCCURRENCE INT, -- 1-10: How likely is the failure?
DETECTION INT, -- 1-10: How detectable is the failure?
RPN INT, -- Risk Priority Number = Severity × Occurrence × Detection
MAINTENANCETASK VARCHAR(50),
TASKINTERVAL INT,
INTERVALUNIT VARCHAR(10),
TASKASSIGNEDTO VARCHAR(30),
REVIEWDATE DATE,
REVIEWEDBY VARCHAR(30),
STATUS VARCHAR(20), -- DRAFT, APPROVED, DEPLOYED, RETIRED
PRIMARY KEY (FMEAID)
);

The RPN Calculation

The Risk Priority Number (RPN) is the product of severity, occurrence, and detection:

RPN = Severity × Occurrence × Detection

Factor Score 1-3 Score 4-6 Score 7-9 Score 10
Severity Minor inconvenience Reduced functionality Major operational impact Safety or environmental incident
Occurrence Once per 10+ years Once per 1-10 years Once per 1-12 months Once per month or more
Detection Always detected by existing controls Usually detected Sometimes detected Never detected until failure

The RPN ranges from 1 to 1,000. Higher RPN values indicate higher risk and justify more intensive maintenance strategies.

Automation Script for FMEA Processing

# Automation Script: FMEA Risk Assessment
# Launch Point: OBJECT - FMEA_ANALYSIS - Save - Before Save
# Calculates RPN and recommends maintenance strategy

def process_fmea():
"""
Calculate RPN and recommend maintenance strategy based on
severity, occurrence, and detection scores.
"""

severity = mbo.getInt("SEVERITY", 1)
occurrence = mbo.getInt("OCCURRENCE", 1)
detection = mbo.getInt("DETECTION", 1)

# Calculate RPN
rpn = severity * occurrence * detection
mbo.setValue("RPN", rpn, MboConstants.NOACCESSCHECK)

# Recommend maintenance strategy based on RCM decision logic
strategy = recommend_strategy(severity, occurrence, detection, rpn)
mbo.setValue("MAINTENANCETASK", strategy, MboConstants.NOACCESSCHECK)

# Set review date based on risk level
from java.util import Calendar
cal = Calendar.getInstance()
if rpn >= 200:
cal.add(Calendar.MONTH, 6) # Review every 6 months for high risk
elif rpn >= 100:
cal.add(Calendar.MONTH, 12) # Review annually for medium risk
else:
cal.add(Calendar.MONTH, 24) # Review every 2 years for low risk
mbo.setValue("REVIEWDATE", cal.getTime(), MboConstants.NOACCESSCHECK)

def recommend_strategy(severity, occurrence, detection, rpn):
"""
Apply RCM decision logic to recommend a maintenance strategy.

RCM decision logic:
- High severity (safety/environmental): Mandatory preventive or predictive task
- High occurrence: Preventive maintenance or redesign
- Low detection: Predictive/condition-based maintenance
- Low RPN overall: Run to failure
"""

# Safety-critical failures always require preventive or predictive tasks
if severity >= 9:
if detection <= 3:
return "CONDITION-BASED" # Hard to detect, need monitoring
else:
return "PREVENTIVE" # Scheduled restoration or replacement

# High-occurrence failures benefit from preventive maintenance
if occurrence >= 7:
if detection <= 5:
return "PREDICTIVE" # Monitor condition to predict failure
else:
return "PREVENTIVE" # Scheduled maintenance

# Low-detection failures need condition monitoring
if detection <= 3 and severity >= 5:
return "CONDITION-BASED"

# Moderate risk: preventive or condition-based
if rpn >= 100:
return "PREVENTIVE"

# Low risk: run to failure
return "RUN-TO-FAILURE"

# Execute
process_fmea()

Deploying Asset Strategies

The output of RCM analysis is a set of maintenance tasks. These tasks must be deployed as scheduled preventive maintenance records, condition monitoring points, or inspection routes in Maximo.

From FMEA to PM

Each FMEA record that recommends preventive maintenance should generate a corresponding PM record:

# Automation Script: Deploy FMEA to PM
# Launch Point: ACTION - FMEA_ANALYSIS - Deploy to PM
# Creates PM records from approved FMEA analyses

def deploy_fmea_to_pm():
"""
Create PM records from approved FMEA analyses.
This script is triggered by a custom action on the FMEA analysis record.
"""

fmea_set = mbo.getThisMboSet()
fmea = fmea_set.moveFirst()

created_count = 0
skipped_count = 0

while fmea is not None:
if fmea.getString("STATUS") != "APPROVED":
skipped_count += 1
fmea = fmea_set.moveNext()
continue

# Check if a PM already exists for this FMEA
existing_pm = check_existing_pm(fmea)
if existing_pm:
skipped_count += 1
fmea = fmea_set.moveNext()
continue

# Create the PM record
pm_set = MXServer.getMXServer().getMboSet("PM",

MXServer.getMXServer().getSystemUserInfo())
pm = pm_set.add()

# Set PM attributes from FMEA
pm.setValue("ASSETNUM", fmea.getString("ASSETNUM"))
pm.setValue("DESCRIPTION",

"RCM: {} - {}".format(
fmea.getString("FAILUREMODE"),
fmea.getString("MAINTENANCETASK")
))
pm.setValue("WORKTYPE", "PM")
pm.setValue("JPSEQUENCE", fmea.getString("TASKINTERVAL"))
pm.setValue("FREQUENCY", fmea.getInt("TASKINTERVAL"))
pm.setValue("FREQUENCYUNIT", fmea.getString("INTERVALUNIT"))
pm.setValue("LEAD", fmea.getString("TASKASSIGNEDTO"))

# Link back to the FMEA for traceability
pm.setValue("FMEAID", fmea.getLong("FMEAID"))

pm_set.save()
created_count += 1

fmea = fmea_set.moveNext()

# Report results
logger = MXLoggerFactory.getLogger("maximo.rcm")
logger.info(
"FMEA to PM deployment complete: {} created, {} skipped".format(
created_count, skipped_count
)
)

def check_existing_pm(fmea):
"""
Check if a PM already exists for this FMEA record.
"""
pm_set = MXServer.getMXServer().getMboSet("PM",
MXServer.getMXServer().getSystemUserInfo())
pm_set.setWhere("FMEAID = {}".format(fmea.getLong("FMEAID")))
return not pm_set.isEmpty()

# Execute
deploy_fmea_to_pm()

Strategy Types and Their Maximo Implementation

RCM Strategy Maximo Implementation Example
Preventive (Time-Based) PM with time-based frequency Replace bearings every 6 months
Preventive (Usage-Based) PM with meter-based frequency Change oil every 500 operating hours
Condition-Based Condition monitoring point + Monitor Monitor vibration, alert at threshold
Predictive Predict model + Health score Predict remaining useful life from trend data
Failure Finding PM for hidden failure detection Test standby pump monthly
Run to Failure No PM; corrective work orders only Replace light bulbs when they burn out
Redesign Capital project or modification Redesign inlet to eliminate cavitation

Living Program Maintenance

An RCM program is not a one-time project. It is a living program that must be maintained as assets age, failure patterns change, and new technologies become available.

The Feedback Loop

The most important feedback mechanism is the comparison between predicted failures and actual failures:

-- Query: Compare predicted vs. actual failures
-- Identifies failure modes that are occurring despite preventive tasks

SELECT
fmea.FAILUREMODE,
fmea.MAINTENANCETASK,
fmea.TASKINTERVAL,
fmea.INTERVALUNIT,
COUNT(wo.WONUM) AS ACTUAL_FAILURES,
fmea.OCCURRENCE AS PREDICTED_OCCURRENCE
FROM FMEA_ANALYSIS fmea
LEFT JOIN WORKORDER wo ON
wo.ASSETNUM = fmea.ASSETNUM
AND wo.FAILURECODE = fmea.PROBLEMCODE
AND wo.STATUSDATE >= SYSDATE - 365
AND wo.WORKTYPE IN ('EM', 'CM')
WHERE fmea.STATUS = 'DEPLOYED'
GROUP BY
fmea.FAILUREMODE,
fmea.MAINTENANCETASK,
fmea.TASKINTERVAL,
fmea.INTERVALUNIT,
fmea.OCCURRENCE
HAVING COUNT(wo.WONUM) > fmea.OCCURRENCE
ORDER BY ACTUAL_FAILURES DESC;

This query identifies failure modes where actual failures exceed predicted occurrence. These are candidates for strategy revision: either the preventive task is ineffective, the interval is too long, or the failure mode was not fully understood during the initial analysis.

Strategy Effectiveness Metrics

Track these metrics to measure RCM program effectiveness:

Metric Calculation Target
PM Effectiveness (Emergency WOs prevented) / (Total PMs executed) >80%
Strategy Coverage (Assets with active strategy) / (Critical assets) 100% for high criticality
Failure Mode Accuracy (Predicted failures) / (Actual failures) Within 20%
RCM Review Currency (FMEAs reviewed on time) / (Total FMEAs) >95%

Automation Script for Strategy Review Trigger

# Automation Script: RCM Strategy Review Trigger
# Launch Point: ESCALATION - Scheduled
# Identifies FMEA records due for review and creates review tasks

def trigger_strategy_reviews():
"""
Identify FMEA records due for review and create review work orders.
This runs as a scheduled escalation (monthly).
"""

fmea_set = MXServer.getMXServer().getMboSet("FMEA_ANALYSIS",
MXServer.getMXServer().getSystemUserInfo())
fmea_set.setWhere("STATUS = 'DEPLOYED' AND REVIEWDATE <= SYSDATE + 30")

review_count = 0
fmea = fmea_set.moveFirst()

while fmea is not None:
# Create a review work order
wo_set = MXServer.getMXServer().getMboSet("WORKORDER",
MXServer.getMXServer().getSystemUserInfo())
wo = wo_set.add()

wo.setValue("ASSETNUM", fmea.getString("ASSETNUM"))
wo.setValue("DESCRIPTION",

"RCM Strategy Review: {} - {}".format(
fmea.getString("FAILUREMODE"),
fmea.getString("MAINTENANCETASK")
))
wo.setValue("WORKTYPE", "RCM")
wo.setValue("REPORTEDPRIORITY",

1 if fmea.getInt("RPN") >= 200 else 2)
wo.setValue("ASSIGNEDTO", fmea.getString("REVIEWEDBY"))
wo.setValue("TARGCOMPDATE", fmea.getDate("REVIEWDATE"))
wo.setValue("FMEAID", fmea.getLong("FMEAID"))

wo_set.save()
review_count += 1

fmea = fmea_set.moveNext()

logger = MXLoggerFactory.getLogger("maximo.rcm")
logger.info("RCM review trigger: {} review work orders created".format(review_count))

# Execute
trigger_strategy_reviews()

Practical Implications

If you skip criticality analysis, you will apply RCM to the wrong assets. You will spend months analyzing non-critical equipment while critical assets fail. Start with the assets that matter most.

If your failure code hierarchy is poorly designed, you will not be able to analyze failure patterns. Technicians will select the first code in the list. Your failure data will be inconsistent. Your RCM analysis will be based on bad data.

If you treat RCM as a one-time project, your strategies will become obsolete. Assets age. Failure patterns change. New technologies become available. An RCM analysis from five years ago is a historical document, not a maintenance strategy.

If you do not close the feedback loop, you will not know whether your strategies are working. You will continue executing PMs that do not prevent failures. You will miss failure modes that are not covered by your strategies.

If you do not involve technicians in the FMEA process, you will miss failure modes that are obvious in the field but invisible from the office. The best FMEA analyses combine engineering analysis with field experience.

Bottom Line

RCM is the most rigorous approach to maintenance strategy development, and Maximo provides the data structures to support it. But the structures alone do not create a program. You need a systematic approach: criticality analysis to prioritize assets, a well-designed failure code hierarchy to capture failure data, FMEA templates to analyze failure modes and select strategies, and feedback loops to validate and improve those strategies over time.

The investment in RCM pays for itself through reduced emergency work, extended asset life, and improved reliability. But it only pays for itself if the program is maintained. An RCM program that is not reviewed and updated is a shelf document. An RCM program that is actively maintained is a competitive advantage.

Read more