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 (with Frozen Dictionaries and Dynamic Registration):

We use a multi-layered resolution system that infers missing datatypes from CIM schema definitions, prioritizing schema-based resolution and supporting runtime extensibility:

  1. CgmesTypeMap - Auto-generated static mappings for primitives, CIM datatypes, and property types. Used as the authoritative source for registry population.

  2. CimPropertyTypeRegistry - Singleton registry using frozen dictionaries from CgmesTypeMap for high-performance lookups. Supports additional dynamic registrations for properties, primitives, and CIM datatypes. All names are normalized (handles URIs and prefixes).

public class CimPropertyTypeRegistry : ICimPropertyTypeRegistry {
    // Uses frozen dictionaries from CgmesTypeMap for static lookups
    // Supports dynamic registration for runtime schema extensions
    // Normalizes names (e.g., "cim:Float" or "http://iec.ch/TC57/CIM100#Float" → "Float")
    public bool TryGetPropertyDataType(string propertyName, out string? dataType) { ... }
    public bool TryGetCSharpType(string cimType, out string? csharpType) { ... }
    public bool TryGetPrimitiveType(string cimType, out string? primitiveType) { ... }
    public void RegisterProperty(string propertyName, string cimDataType) { ... }
    public void RegisterPrimitive(string cimTypeName, string csharpTypeName) { ... }
    public void RegisterCimDataType(string cimDataTypeName, string primitiveTypeName) { ... }
}
  1. CimPropertyTypeResolver - Resolves property names to CIM datatypes, then to C# types, then to XSD datatypes. Maintains a static map from C# types to XSD URIs.
public class CimPropertyTypeResolver : ICimPropertyTypeResolver {
    // Resolution chain: propertyName → CIM datatype → C# type → XSD URI
    public bool TryResolveDataType(string propertyName, out string? xsdDataType) {
        // 1. Try registry for property datatype
        // 2. Resolve CIM datatype to C# type
        // 3. Map C# type to XSD URI
    }
}
  1. CimPropertyFactory - When creating literal properties, prioritizes schema-based datatype resolution (via TypeResolver). If schema resolution fails, falls back to literal node datatype. Handles compound, resource, and literal properties with clear separation.
public class CimPropertyFactory : ICimPropertyFactory {
    public virtual CimLiteralProperty GetLiteralProperty(string propertyName, ILiteralNode literalNode) {
        string? dataType = null;
        // Try schema registry first
        if (TypeResolver.TryResolveDataType(propertyName, out var schemaDataType)) {
            dataType = schemaDataType;
        }
        // Fallback to literal node datatype
        else if (literalNode.DataType != null) {
            dataType = literalNode.DataType.ToString();
        }
        // If still no datatype, leave null
        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" (via CgmesTypeMap)
   - Primitive lookup: "Susceptance"  "Float"
   - C# mapping: "Float"  "float"
   - XSD mapping: "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:

  • Schema-first resolution: Always uses authoritative schema mapping if available, falls back to literal node datatype if not.
  • Frozen dictionary performance: Static mappings from CgmesTypeMap ensure fast lookups.
  • Dynamic registration: Registry can be extended at runtime for new schema types.
  • Normalization logic: Handles URIs and prefixes for consistent property/type resolution.
  • Standard XSD Output: Converts CIM types to W3C standard XSD datatypes for interoperability.

CgmesTypeMap:

  • Auto-generated from CIM schema, contains static mappings for primitives, CIM datatypes, and property types.
  • Used to populate CimPropertyTypeRegistry at startup.

CimPropertyFactory:

  • Handles literal, resource, and compound properties.
  • Prioritizes schema-based datatype resolution.

3. No Standard Way to Handle Multiple Profiles/Versions

Root Cause Analysis

  • Complex Ecosystem: CGMES has multiple versions (v2.4.15, v3.0.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