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:
- Mutually exclusive problems: Each problem should describe a distinct failure mode. If two problems overlap, technicians will be inconsistent in their coding.
- Exhaustive causes: The causes under each problem should cover all reasonably likely root causes. An "OTHER" cause is acceptable but should be used rarely.
- Actionable remedies: Each remedy should describe a specific corrective action. "INSPECT" is not a remedy. "REPLACE-BEARINGS" is a remedy.
- 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.