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
PROTOCOLPortdefines the protocol vocabulary; the port's protocol becomes the gateway,c++2Dtorpython2Dtprefixed by the component language. CppComponentandPythonComponentare the two languages understood; specialising anything else is an error naming the line.in,outandinoutattributes becomeinput,outputandin_outsignals of typeint; other attribute types are emitted asintand listed as an assumption.- A signal belongs to the port whose name minus
_pis its prefix (sense_temperaturebelongs tosense_p). A flow whose signal matches no port is an error. - A
flowbecomesconnect signals. Aconnectionbetween 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 Ncomment or handed out from 8800. Connections between CAN or LIN ports become one shared frame per group, id from a// frame 0x100comment or assigned, 8 bits per signal in declaration order. - A trailing
// bus NAMEcomment 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)