Skip to content

CGMES/CIMXML Gaps

1. Non-Standard RDF/XML Serialization (CIMXML)

Root Cause Analysis

IEEE published CIMXML in 2003, but W3C RDF/XML 1.0 was finalized in 2004 → CIMXML was based on a draft specification.

  • Technical Issues:
    1. rdf:ID and rdf:about use non-standard URI formats (e.g., _123 instead of proper URIs)
    2. rdf:parseType="Statements" was introduced but is not valid W3C RDF/XML syntax
    3. Multiple graphs in one file violates standard RDF/XML structure

Standard RDF libraries (Apache Jena, rdflib, etc.) cannot parse CIMXML correctly without custom modifications.

How We Solved It

In DifferenceModelReader.cs:

// MANUAL HANDLING OF rdf:parseType="Statements"
private string WrapInRdfDocument(string xmlContent, IGraph parentGraph)
{
    // Reconstruct proper RDF/XML with correct namespaces
    return $"<?xml version=\"1.0\" encoding=\"utf-8\"?><rdf:RDF {namespaces}>{xmlContent}</rdf:RDF>";
}

In CimNodeResolver.cs implementations:

// FIX FOR NON-STANDARD URIs
public string GetInstanceId(INode node)
{
    var rawId = GetRawValue(node);
    // Convert CIMXML's "_123" to proper "urn:uuid:123"
    // Create a normalized URI format for consistent processing
    return normalizeId
}

2. Missing Datatype Information

Root Cause Analysis

CIMXML serialization does not include rdf:datatype attributes for literal values.

  • Example: <cim:GeneratingUnit.maxOperatingP>100</cim:GeneratingUnit.maxOperatingP>
    • Missing: rdf:datatype="http://www.w3.org/2001/XMLSchema#decimal"

Applications cannot distinguish between strings, numbers, dates, etc., leading to validation errors and incorrect calculations.

How We Solved It

Schema-Based Type Registry System:

We built a two-layer resolution system that infers missing datatypes from CIM schema definitions:

  • CimPropertyTypeRegistry - Singleton registry populated at startup with schema mappings:
public class CimPropertyTypeRegistry : ICimPropertyTypeRegistry
{
    // Property name → datatype URI (e.g., "ACLineSegment.bch" → "Susceptance")
    private readonly Dictionary<string, string> _propertyToDataType;

    // CIMDatatype name → primitive type (e.g., "Susceptance" → "Float")
    private readonly Dictionary<string, string> _cimDataTypes;

    // Primitive type name → CimPrimitiveType enum
    private readonly Dictionary<string, CimPrimitiveType> _primitives;

    public bool TryGetPropertyDataType(string propertyName, out string dataTypeUri)
    {
        // Lookup property → datatype mapping from schema
        return _propertyToDataType.TryGetValue(propertyName, out dataTypeUri);
    }

    public bool TryGetPrimitiveType(string cimDataType, out CimPrimitiveType primitiveType)
    {
        // Resolve CIMDatatype → primitive type chain
        // e.g., "Susceptance" → "Float" → CimPrimitiveType.Float
        if (_primitives.TryGetValue(cimDataType, out primitiveType))
            return true;

        if (_cimDataTypes.TryGetValue(cimDataType, out var valueType))
            return TryGetPrimitiveType(valueType, out primitiveType);

        return false;
    }
}
  • CimPropertyTypeResolver - Resolves property names to XSD datatypes:
public class CimPropertyTypeResolver : ICimPropertyTypeResolver
{
    private readonly ICimPropertyTypeRegistry _registry;

    public bool TryResolveDataType(string propertyName, out string? xsdDataType)
    {
        // Step 1: Property name → CIM datatype
        if (!_registry.TryGetPropertyDataType(propertyName, out var dataType))
            return false;

        // Step 2: CIM datatype → Primitive type
        if (!_registry.TryGetPrimitiveType(dataType, out var primitiveType))
            return false;

        // Step 3: Primitive type → XSD URI
        xsdDataType = primitiveType switch
        {
            CimPrimitiveType.Float => "http://www.w3.org/2001/XMLSchema#float",
            CimPrimitiveType.Integer => "http://www.w3.org/2001/XMLSchema#integer",
            CimPrimitiveType.Boolean => "http://www.w3.org/2001/XMLSchema#boolean",
            CimPrimitiveType.DateTime => "http://www.w3.org/2001/XMLSchema#dateTime",
            // ... other mappings
            _ => null
        };

        return xsdDataType != null;
    }
}
  • Integrated in CimPropertyFactory - Automatically enriches properties during parsing:
public class CimPropertyFactory : ICimPropertyFactory
{
    protected ICimPropertyTypeResolver TypeResolver { get; }

    public virtual CimLiteralProperty GetLiteralProperty(
        string propertyName, 
        ILiteralNode literalNode)
    {
        // Use existing datatype if present in the literal
        var dataType = literalNode.DataType?.ToString();

        // If no datatype in literal, try to resolve from schema registry
        if (string.IsNullOrEmpty(dataType) &&
            TypeResolver.TryResolveDataType(propertyName, out var schemaDataType))
        {
            dataType = schemaDataType;
        }

        return new CimLiteralProperty(
            name: propertyName,
            value: literalNode.Value,
            dataType: dataType,
            language: literalNode.Language
        );
    }
}

Resolution Chain Example:

Input: <cim:ACLineSegment.bch>0.0000005</cim:ACLineSegment.bch>

1. CimPropertyFactory detects missing rdf:datatype
2. TypeResolver.TryResolveDataType("ACLineSegment.bch", out xsdType)
   - Registry lookup: "ACLineSegment.bch"  "Susceptance"
   - Primitive lookup: "Susceptance"  CimPrimitiveType.Float
   - XSD mapping: CimPrimitiveType.Float  "http://www.w3.org/2001/XMLSchema#float"
3. CimLiteralProperty created with inferred datatype

Output: Properly typed property that can be validated and processed correctly

Key Benefits:

  • No Runtime Schema Queries: Registry pre-populated at startup for performance
  • Handles CIMDatatype Chains: Resolves nested type references (CIMDatatype → value → Primitive)
  • Graceful Fallback: If type resolution fails, property still created without datatype
  • Standard XSD Output: Converts CIM types to W3C standard XSD datatypes for interoperability

3. No Standard Way to Handle Multiple Profiles/Versions

Root Cause Analysis

  • Complex Ecosystem: CGMES has multiple versions (v2.4.15, v3.0) and profiles (EQ, SSH, TP, SV, etc.)
  • Missing Machinery: No standard way to:
    • Validate against specific profile versions
    • Convert between versions
    • Handle backward/forward compatibility

Vendor tools implement different validation rules, causing interoperability failures.

4. Lack of Open, Standardized Tooling

Root Cause Analysis

  • Vendor Lock-in: Each vendor developed proprietary parsers with different interpretations
  • Duplicated Effort: 40+ TSOs and their vendors all solving the same problems independently
  • No Reference Implementation: IEC/ENTSO-E published standards but no reference code

5. Poor Validation & Debugging Experience

Root Cause Analysis

  • Legacy Validation: Originally used OCL (Object Constraint Language), hard to maintain
  • No Standard Validation Reports: Each tool produces different error formats
  • Hard to Debug: When validation fails, difficult to trace which profile/rule caused it