Zone Crossing
A place where people cross guide-path space that vehicles also want.
Thin, because the exclusion is not its job. A crossing is a set of zones, an admission policy, and its own statistics -- everything about keeping vehicles and people out of each other's way is already the zone's, and this adds no new rule about it.
Why this is a ModelElement, when a holder is not
The contrast is worth stating because it is the one place the two kinds of occupancy meet. A spill cannot be a ModelElement: it happens at minute 137.4 on whichever aisle the sample picks, and nothing about it can be declared before the run, which is why ZoneHolderIfc is an interface with two members. A crossing is the opposite. It is a piece of the layout -- it has a location, a name, statistics that accumulate across a replication, and a discipline that may carry state between turns -- and there is exactly one of it, known when the model is built. So it is an element, and it gets initialize() and a place in the model tree for the same reasons a Link would if links were elements.
How a turn works
The mechanism is the one the subsystem already has, used for the turn rather than for the people.
The arbiter is asked whether vehicles should be barred. When it says yes the crossing requests its zones as a holder -- so traffic already on them drains off through the ordinary all-or-nothing machinery, and the turn opens on every zone at one instant or on none. Nothing is evicted and no vehicle is stranded half way across.
Once granted, the crossing holds the zones and admits people onto what it holds -- it is a ZonePopulationHostIfc, which is the whole of what that interface means. Vehicles are excluded because the zones are held; people are admitted because the holder is the crossing.
The turn ends when the arbiter stops barring vehicles and the last person is off. A turn always finishes: the arbiter can stop admitting, never evict.
The design record originally said vehicles would be excluded by the population count rather than by anything holding on the pedestrians' behalf. That does not work, and the reason is worth keeping: a count excludes traffic only once somebody is already standing in the road, which is too late to be how a crossing gathers people safely. One holder for the crossing is not the thing that was being warned against -- a holder per pedestrian would have been.
What it earns its place by absorbing
The population edges. A walker that balks, is interrupted, or is destroyed must still leave the count, or the crossing stays shut to vehicles for the rest of the replication with nobody on it. This is the single most likely hand-rolling error, and ProcessModel.Entity cleans it up at the same two exits that give back guide-path space.
Admission control, which is where the modelling actually lives, and which is a substitutable CrossingArbiterIfc rather than a policy baked in here.
The statistics: turns taken, time shut to traffic, how long people wait and how many.
Parameters
where this sits in the model
the guide path whose zones are being crossed
the zones the crossing covers, all on that guide path, distinct, at least one
who decides whose turn it is; substitutable, and the point of the construct
the crossing's name in the model
Constructors
Properties
The discipline by name, so a scenario or an app can change it without holding an arbiter.
Never anything. A crossing waits for space through its request, not by queuing on a zone, so it contributes no queuing edge to the wait-for graph.
How many people got across.
The fraction of time the crossing was shut to vehicles, counting the drain as shut.
How long the one at the head of the queue has been waiting, or zero when nobody is.
How many are on the crossing now.
How many were waiting to cross, time-weighted.
How many are waiting to step on.
How many pedestrian turns the crossing opened.
How long each person waited before stepping on. Zero when the crossing was already open.
Functions
Called once, when the space has drained and the hold has taken effect.
Called once, when the space has been given back -- by the holder, or by the clock.
This method should be overridden by subclasses that need actions performed to initialize prior to a replication. It is called once before each replication occurs if the model element wants initialization. It is called after beforeReplication() is called