|
RTE RBC 2oo2 Specific Application 0.1.0 build 53572f9
Installer packaging and site-data libraries for the RBC_GP reference RBC
|
Real railML 3.3 (https://www.railml.org/schemas/3.3), IS (infrastructure) + IL (interlocking) modules in one file, sharing one ID space so IL can refersTo/ refersToSwitch straight into IS elements. Structure and attribute names verified against the real railML 3 wiki (wiki3.railml.org) and the real schema's targetNamespace this session — not invented.
Topology v2 (this session, replacing the original single 12 km open-line dataset): two stations, WEST and EAST, each with 4 tracks (W1-W4, E1-E4, 300 m each), connected by a double-track open line — UP (WEST→EAST, 4×2000 m blocks) and DOWN (EAST→WEST, 4×2000 m blocks), same corridor. WEST's throat has two switches (SW_W_A merging W1/W2 onto UP, SW_W_B splitting DOWN into W3/W4); EAST mirrors this (SW_E_A/SW_E_B). Absolute chainage (km, WEST station = 0) is carried per balise via sapi:etcsBaliseGroup/@km — see the Extensions section below. 16 segments / 14 signals / 4 switches / 16 balises / 16 routes.
This file is read independently by two generators (see their own header comments for the full rationale — neither derives from the other, both parse this file directly):
This split is a deliberate correction from the RailML-standard model, where routes are just another interlocking asset alongside everything else: in this codebase specifically, GP owns the physical world, GA owns the interlocking-route logic that IL talks to — see the Platform_RTE workspace root CLAUDE.md's GP/GA/SA section and this session's own plan file for why.
Three fields have no confirmed native railML attribute after this session's own research (not from lack of trying — see the caveats below) and use railML's own sanctioned per-element <extensions> mechanism, under a project-local namespace (xmlns:sapi="https://rterbc2oo2.example/schemas/sapi-ext/1" — not a real, registered railML extension, just a private one scoped to this project):
| C field (today's ab_site*.h) | railML source | Nature |
|---|---|---|
| segment id | POSITIONAL: document order of netElement in <netElements> (1..N) | derived — see "ID assignment" caveat below |
| segment prev_segment_id/next_segment_id | netRelation/@elementA/@elementB (adjacency graph), resolved to the positional id above; first relation seen per netElement wins at a branch point | derived, simplified — see caveat below |
| segment length_m | netElement/@length | native |
| segment v_max_kmh/gradient_permil/switch_id | sapi:trackDescription | extension |
| segment start_signal_id/end_signal_id | boundary-signal lookup: a signal at pos=0/pos=length on this segment's own netElement, falling back to the adjacent segment's own boundary position if none sits locally (both placement conventions appear in this topology - see caveat below) | derived |
| signal id | POSITIONAL: document order of signalIS in <signalsIS> (1..N) | derived — signalIS/@id no longer carries a parseable numeric convention (topology v2 names like SW1/HW/U1 replaced the old "S"+number scheme) |
| signal name | signalIS's own designator (@name) | native |
| signal segment_id/pos_m/direction | spotLocation/@netElementRef/@pos/@applicationDirection | native |
| signal type | IS:signalIS/@type | native |
| signal function/sight_distance_m | IL:signalIL/@function/@sightDistance (an IL overlay on the IS signal, via refersTo) | native, different module than type |
| switch id/name/segment_id/pos_m | switchIS/@id/designator + spotLocation; id is POSITIONAL (document order), same as segments/signals | native fields, positional id |
| switch normal_segment_id/reverse_segment_id | switchIS/@continueCourse/@branchCourse, resolved to the referenced netElement's own positional segment id | native reference, derived id |
| switch default_position/max_speed_*_kmh | sapi:switchDescription | extension |
| balise nid_lrbg | sapi:etcsBaliseGroup/@nidLrbg | extension |
| balise name/segment_id/pos_m/direction | baliseGroup/@id + spotLocation | native |
| balise chainage_m | sapi:etcsBaliseGroup/@km × 1000 | extension (see above) |
| balise route_id | cross-reference: which route's sapi:routeDescription/@baliseNidLrbg names this balise | derived |
| route id/name | route/@id/@designator | native |
| route start_signal/end_signal | routeEntry/routeExit's refersTo, resolved to the referenced signal's own positional id | native reference, derived id |
| route prev_route_id/next_route_id | derived: route A's end_signal == route B's start_signal | derived (no native field — confirmed absent from IL:route's child list) |
| route length_m | sapi:routeDescription/@lengthM | extension (no native field — confirmed absent; matches what ab_siteGP.h's own pre-existing doc comment already treated as "sum of segments," i.e. already conceptually derived, not a new burden) |
| route segment_ids[]/segment_count | hasTvdSection/@ref → its track's own netElementRef → that netElement's positional segment id | derived |
| route switch_ids[]/switch_positions[]/switch_count | facingSwitchInPosition/trailingSwitchInPosition (refersToSwitch + inPosition), refersToSwitch resolved to the referenced switch's own positional id | native structure, derived id. inPosition ("normal"/"reverse") maps to this project's NORMAL/REVERSE enum via the referenced switch's own continueCourse/branchCourse — handedness isn't assumed fixed |
| route balise_nid_lrbgs[]/balise_count | sapi:routeDescription/@baliseNidLrbg | extension |
The original single open-line topology used names a plain numeric-suffix parse could read directly (ne_segNN, "S"+number). Topology v2's branching, two-station layout doesn't fit that convention (ne_w1, sig_HW, sig_U1, ...), so all three independent readers (generate_ab_site_gp.py, generate_ab_site_ga.py, and RBC_Test_Env/etc/scripts/generate_site_routes_resource.py) now assign segment/signal/switch ids positionally — 1..N by document order of netElement/ signalIS/switchIS respectively. All three readers see the same document order in the same file, so they agree with no shared code or build-order coupling — the same independent-generator principle the rest of this file already relies on.
Two singular-field simplifications fall out of this topology's real branch points, both accepted deliberately rather than treated as bugs:
Flagged honestly rather than glossed over — this file was authored against the real railML 3 wiki documentation and the real schema's confirmed targetNamespace, but not validated against a downloaded real XSD (attempts to fetch the raw schema file this session didn't return usable binary/XSD content via the available tools):
None of these affect correctness of the generators reading this file (they read the sapi:* extensions either way) — they only affect how "standards-pure" the file is. Worth a follow-up pass with a real XSD validator (xmllint --schema) against the actual downloaded 3.3 schema if this ever needs to interoperate with real external railML tooling.