VSIKnowledge

Building a Twin

Building a twin from a SysML v2 model, and adding a block that exists only there

Two transforms connect SysML v2 text and VSI in both directions. vsi2sysml.py writes a twin as a SysML v2 package that the OMG pilot validates and the SysML v2 Modeler renders. sysml2vsi.py reads that same subset back, plus what a hand-authored block needs, and emits a vsiBuild command file. Together they let a block live only in SysML v2, with no Teamcenter port and no ICD row, and still land in the twin wired to the others.

The SysML v2 shape the transform reads

package MyTwin {
    private import ScalarValues::*;

    abstract port def VsiPort;
    port def GenericPayloadPort :> VsiPort;
    port def CanPort :> VsiPort { attribute frameId : String; }
    port def EthernetPort :> VsiPort { attribute ipPort : Natural; attribute transport : String; }

    abstract part def VsiComponent;
    abstract part def CppComponent :> VsiComponent;
    abstract part def PythonComponent :> VsiComponent;

    part def SensorDef :> CppComponent {
        port sense_p : GenericPayloadPort;
        out attribute sense_temperature : Integer;
    }
    part def LoggerDef :> PythonComponent {
        port log_p : GenericPayloadPort;
        in attribute log_temperature : Integer;
    }

    part def Twin {
        part Sensor : SensorDef;
        part Logger : LoggerDef;
        flow f_temp from Sensor.sense_temperature to Logger.log_temperature;  // bus Telemetry
    }
    part twin : Twin;
}

Rules the transform applies:

  • A port def named PROTOCOLPort defines the protocol vocabulary; the port's protocol becomes the gateway, c++2Dt or python2Dt prefixed by the component language.
  • CppComponent and PythonComponent are the two languages understood; specialising anything else is an error naming the line.
  • in, out and inout attributes become input, output and in_out signals of type int; other attribute types are emitted as int and listed as an assumption.
  • A signal belongs to the port whose name minus _p is its prefix (sense_temperature belongs to sense_p). A flow whose signal matches no port is an error.
  • A flow becomes connect signals. A connection between two Ethernet ports becomes a TCP server and client socket pair (the first end is the server), with the number taken from a trailing // tcp N comment or handed out from 8800. Connections between CAN or LIN ports become one shared frame per group, id from a // frame 0x100 comment or assigned, 8 bits per signal in declaration order.
  • A trailing // bus NAME comment names the bus; spaces in it become underscores so the glue can key its per-bus periods on the name.

Everything derived rather than read goes to OUT.assumptions.md. The transform parses by its own line grammar, not the pilot's semantic model, so validate first.

Validate, transform, build, run

python validate_sysml.py sysml\MyTwin.sysml
python sysml2vsi.py -i sysml\MyTwin.sysml -o mytwin.vsi.cmd --twin MyTwinDT --workspace D:\wfpy
vsiBuild -c -f mytwin.vsi.cmd
python twin_glue\apply_glue_generic.py mytwin.vsi.cmd D:\wfpy\MyTwinDT

Then compile, run and check as in running-and-controlling/build-and-run. The validator runs the OMG pilot kernel 0.61.0 headless (Java 21, the standard library passed as the program argument, the file fed as one line, %exit appended) and prints PASS or the pilot's own error with the source line.

Proof that it works (EXERCISED 2026-09-08)

Round trips first. The Candidate A export, transformed back, matched its original command file in 44 of 44 command lines (only the build flag differs). The 63-component Wildfire export matched in every command kind: 63 components, 78 ports, 63 signal lines, 118 sockets, 22 CAN frames including the trailing -idType standard, 30 signal connections.

Then the driven block. sysml\Msp2_A_sysmlblock.sysml is Candidate A plus a MSP2_Ground_Test_Monitor part def specialising PythonComponent, with four in attributes and four flows from the card discretes. Pilot PASS; transformed to eight components (7 C++ and 1 Python); generated to D:\wfpy\Msp2DT_S; glued (three buses at periods 1, 2 and 3); built (7 clients and one Python gateway); run in 20 s; checker 14 pass, 0 fail, 10 of 10 producer rates, the four links into the SysML-only block among them. Evidence in runs\20260908-2144-msp2S-sysmlblock-14pass, including the glued Python file.

Going the other way

python vsi2sysml.py TWIN.vsi.cmd --package MyTwin --views --views-per-bus --out sysml\MyTwin.sysml

Writes the package above from a command file, plus a MyTwinViews package of interconnection diagrams (one per bus for large twins; a single 63-node diagram never renders in the Modeler). Every flow and connection is named so a diagram edge can expose it, and view names are unique across all diagrams in the package because the Modeler resolves a reused name into another diagram silently. Loading into the local SysML v2 Modeler is in the smsv2-model-and-diagram-authoring skill.

Source: innexis-vsi/sysml2vsi.py, vsi2sysml.py, validate_sysml.py, sysml/Msp2_A_sysmlblock.sysml, runs/20260908-2144-msp2S-sysmlblock-14pass (EXERCISED 2026-09-08) · retrieved Tue Sep 08 2026 00:00:00 GMT+0000 (Coordinated Universal Time)