Examples

This section provides practical examples of using Alt-Ctrl-Proj for various tasks related to Primavera P6 project management.

Schedule Health Check

This example performs a complete schedule health check using the DCMA 14-point assessment criteria:

from xer_parser.reader import Reader
from xer_parser.dcma14.analysis import DCMA14

# Load the XER file
xer = Reader("project.xer")

# Create analyzer with custom thresholds
analyzer = DCMA14(xer,
                 duration_limit=5,    # Flag activities with duration > 5 days
                 lag_limit=2,         # Flag relationships with lag > 2 days
                 tf_limit=15)         # Flag activities with float > 15 days

# Run analysis
results = analyzer.analysis()

# Print summary
print("DCMA 14-Point Assessment Results:")
print("=================================")
print(f"Total Activities: {results['analysis']['summary']['activity_cnt']}")
print(f"Total Relationships: {results['analysis']['summary']['relationship_cnt']}")

# Check missing logic
successors_pct = results['analysis']['successors']['pct'] * 100
print(f"Activities missing successors: {successors_pct:.1f}% (threshold: 5%)")

predecessors_pct = results['analysis']['predecessors']['pct'] * 100
print(f"Activities missing predecessors: {predecessors_pct:.1f}% (threshold: 5%)")

# Check high float
highfloat_pct = results['analysis']['totalfloat']['pct'] * 100
print(f"Activities with high float: {highfloat_pct:.1f}% (threshold: 5%)")

# Check negative float
negfloat_pct = results['analysis']['negativefloat']['pct'] * 100
print(f"Activities with negative float: {negfloat_pct:.1f}% (threshold: 0%)")

# Check resources
no_resources_pct = results['analysis']['resources']['pct'] * 100
print(f"Activities without resources: {no_resources_pct:.1f}% (threshold: 10%)")

Extracting Critical Path

This example extracts and analyzes the critical path from a project:

from xer_parser.reader import Reader

# Load the XER file
xer = Reader("project.xer")

# Get all activities
activities = xer.activities.activities

# Identify critical activities (zero or negative float)
critical_activities = [
    activity for activity in activities
    if activity.total_float_hr_cnt is not None and activity.total_float_hr_cnt <= 0
]

# Sort by early start date to see the sequence
critical_activities.sort(key=lambda x: x.early_start_date if x.early_start_date else datetime.max)

# Print critical path
print("Critical Path Analysis:")
print("======================")
print(f"Number of critical activities: {len(critical_activities)}")

for activity in critical_activities:
    # Get predecessors and successors of this critical activity
    predecessors = xer.relations.get_predecessors(activity.task_id)
    successors = xer.relations.get_successors(activity.task_id)

    # Count how many predecessors and successors are also on critical path
    critical_preds = sum(1 for p in predecessors if
                        xer.activities.find_by_id(p.pred_task_id).total_float_hr_cnt is not None and
                        xer.activities.find_by_id(p.pred_task_id).total_float_hr_cnt <= 0)

    critical_succs = sum(1 for s in successors if
                        xer.activities.find_by_id(s.task_id).total_float_hr_cnt is not None and
                        xer.activities.find_by_id(s.task_id).total_float_hr_cnt <= 0)

    # Print activity details
    print(f"\nActivity: {activity.task_code} - {activity.task_name}")
    print(f"  Duration: {activity.duration} days")
    print(f"  Early Start: {activity.early_start_date}")
    print(f"  Early Finish: {activity.early_end_date}")
    print(f"  Float: {activity.total_float_hr_cnt / 8.0 if activity.total_float_hr_cnt else 0} days")
    print(f"  Critical predecessors: {critical_preds}/{len(predecessors)}")
    print(f"  Critical successors: {critical_succs}/{len(successors)}")

Resource Loading Analysis

This example analyzes resource loading across the project timeline:

from xer_parser.reader import Reader
from collections import defaultdict
from datetime import datetime, timedelta

# Load the XER file
xer = Reader("project.xer")

# Get resources and resource assignments
resources = xer.resources
assignments = xer.activityresources

# Create a dictionary to track resource loading by day
resource_loading = defaultdict(lambda: defaultdict(float))

# Process all activities with assigned resources
for activity in xer.activities.activities:
    # Skip activities without dates
    if not activity.early_start_date or not activity.early_end_date:
        continue

    # Get resource assignments for this activity
    activity_assignments = assignments.find_by_activity_id(activity.task_id)

    if not activity_assignments:
        continue

    # Calculate daily resource units
    start_date = activity.early_start_date
    end_date = activity.early_end_date
    duration_days = (end_date - start_date).days + 1

    if duration_days <= 0:
        continue

    # Process each assignment
    for assignment in activity_assignments:
        resource_id = assignment.rsrc_id
        units_per_day = float(assignment.remain_qty) / duration_days if assignment.remain_qty else 0

        # Distribute units across all days of the activity
        current_date = start_date
        while current_date <= end_date:
            # Skip weekends (simplistic approach)
            if current_date.weekday() < 5:  # 0-4 are Monday to Friday
                resource_loading[resource_id][current_date] += units_per_day

            current_date += timedelta(days=1)

# Print resource loading
print("Resource Loading Analysis:")
print("=========================")

for resource_id, daily_loading in resource_loading.items():
    resource = resources.find_by_id(resource_id)
    if not resource:
        continue

    print(f"\nResource: {resource.rsrc_name}")

    # Find peak loading
    peak_date = max(daily_loading.items(), key=lambda x: x[1], default=(None, 0))
    if peak_date[0]:
        print(f"Peak loading: {peak_date[1]:.2f} units on {peak_date[0]}")

    # Calculate average loading
    avg_loading = sum(daily_loading.values()) / len(daily_loading) if daily_loading else 0
    print(f"Average loading: {avg_loading:.2f} units")

    # Get total assigned units
    total_units = sum(daily_loading.values())
    print(f"Total assigned units: {total_units:.2f}")

XER Explorer Tool

This example demonstrates how to use the XER Explorer tool to generate a summary report of a P6 XER file:

Command-Line Usage

The Explorer tool can be used directly from the command line after installing Alt-Ctrl-Proj:

# Basic usage
xer-explorer path/to/your/file.xer

# Specify custom output file
xer-explorer path/to/your/file.xer -o custom_report.txt

# Include large collections (which are skipped by default)
xer-explorer path/to/your/file.xer --include-large

# Set custom threshold for what's considered a "large" collection
xer-explorer path/to/your/file.xer --threshold 2000

Programmatic Usage

The Explorer can also be used programmatically in your Python code:

from xer_parser.tools import XerExplorer, explore_xer_file

# Simple function approach
explore_xer_file("path/to/your/file.xer", "output_report.txt")

# Object-oriented approach for more control
explorer = XerExplorer("path/to/your/file.xer")
explorer.parse_file()
explorer.collect_data()
explorer.generate_report("output_report.txt",
                        skip_large_collections=True,
                        large_threshold=1000)

# Access the collected data directly
project_data = explorer.collection_data.get("projects", [])
for project in project_data:
    print(f"Project: {project.proj_short_name}")

Example Output

The Explorer generates a concise report with information about the XER file contents:

Alt-Ctrl-Proj Exploration Results
Generated on: 2025-04-14 15:45:30
XER File: sample2.xer
================================================================================

FILE STATISTICS
================================================================================
Collections found in this XER file:
  projects: 1 items
  wbss: 837 items
  activities: 3397 items
  relations: 7474 items
  calendars: 12 items
  resources: 2 items
  activitycodes: 15655 items

Skipping detailed exploration of large collections:
  - activities (too large - 3397 items)
  - relations (too large - 7474 items)
  - activitycodes (too large - 15655 items)

--------------------------------------------------------------------------------

1. PROJECT SUMMARY
================================================================================
Found 1 project(s)

Project #1:
  proj_id: 4015
  proj_short_name: SA06C1_BL_Rev_F_10042025
  clndr_id: 639
  plan_start_date: 2020-12-31 00:00
  plan_end_date: None

// ... additional sections ...

This makes it easy to get a quick overview of an XER file’s contents without having to write custom code to explore each part of the file.