PhaseContainer
Miscellaneous functions PhaseContainer
syntax
- PhaseContainer(container, string message)
description
PhaseContainer calculates all Subitems in the specified Container that are made available to consumers as subitems of the resulting container and posts the configured string message in the EventLog when finished before any of the resulting subitems can be used. This forces the scheduler to first complete a set of calculations before commencing on a subsequent set.
Starting from version 14.4.0, any calculation task that is scheduled after the calculation of a fenced container will only start after the calculation of all fenced tasks is completed, thus enabling a modeller to synchronize memory-intensive sub-tasks and limit simultaneous memory allocation for such separated sub-tasks.
Note that this operator is especially effective when using it to denote a ‘calculation block’ of which all preparatory steps can be removed from memory when finished calculating. Then, only the result (in the PhaseContainer) is kept in memory and ready for use in the next step in the model.
If the message is all that is wanted and the serialisation is not, use CalcAndWrite instead: it posts the same kind of message when an item has finished calculating, without fencing anything.
a phase only runs when something reaches it
A PhaseContainer is not executed because it exists; it is executed because something asks for it. There are two ways to reach one:
- an item outside the phase uses the data of one of its members, for example
phase/resultin a calculation rule, or - the phase container itself is updated, for example by naming it in ExplicitSuppliers or by requesting it on the GeoDmsRun command line.
Since GeoDMS 20.17.0 a member of a phase also counts. Before that release only the container itself did, and reaching only members left the phase silently inert: the work behind the fence still ran, but unfenced and without a message. This is easy to hit without noticing, because the common way to sequence exports does not use the data of anything:
parameter<string> Generate := 'Ready', ExplicitSuppliers = "WriteResults";
container Results := PhaseContainer(GetResults, 'Results for ' + Tile_name);
// elsewhere, the driver that pulls the tiles:
parameter<string> Step := 'Ready', ExplicitSuppliers = "PerTile/tile_0/Results/Generate";
Here nothing ever asks for the value of Results/Generate; the string 'Ready' only exists to carry the supplier relation. Up to GeoDMS 20.16.0 such a configuration produced correct results, produced no PhaseContainer(...) message at all, and enforced no ordering, while still paying for the fence’s bookkeeping.
What changes when you upgrade. A configuration written this way now actually gets the serialisation it asked for. Expect two visible differences: PhaseContainer(...) messages that never appeared before start appearing in the EventLog, and work that used to overlap may now be held back until the phase in front of it has completed. If a model got faster than intended because its fences were inert, this is where that shows up. Removing a fence that was only ever inert is the way to get the old behaviour back.
what a phase calculates
A phase calculates the members that are demanded, and leaves the rest of the fenced container alone.
Up to GeoDMS 20.16.0 it calculated all of them. One reference to phase/x took interest on every member of the fenced container, so the phase materialised the whole of it. A fence placed to bound the working set was therefore widening it: a fence over a container of three results with only one consumed calculated all three, where the same container without the fence calculated one. The same effect made a fence over a container of source data report
PhaseContainer: Source <item> has no calculation rule so its data cannot be collected
for every attribute in it that is read from a storage and that nothing referred to – a member with no calculation rule is nothing for the phase to collect, and it should never have been asked for. Both are gone; if you removed members from a fenced container to keep it cheap, they can go back.
The units of a fenced container are still supplied as a whole, because a consumer that names phase/u as its domain resolves through the mirror unit. Only the values are on demand.
what the message means
The PhaseContainer(<n>): <message> line reports that the phase has completed: the work behind the fence that this phase collected has finished and its results have been handed to the phase’s members. It is therefore usable as per-tile progress reporting in a tiled batch model.
Up to GeoDMS 20.16.0 that was not reliable. The phase’s completion step was driven by a consumer joining it, so a phase with no eager consumer reported only when the final collecting expression pulled it. With several independent phases gathered by one expression, for example
parameter<string> Generate := ='add(' + AsList('PerTile/' + Tiles/name + '/Results/Generate', ',') + ')';
each tile’s work ran in turn, but all the messages appeared together in a burst at the very end, long after the work they announced. The workaround was to give each phase an eager consumer – letting tile k+1 name tile k’s phase result in its ExplicitSuppliers – at the price of coupling tiles that are otherwise independent, so that invalidating tile k invalidated every later tile. That workaround is no longer needed and can be removed.
a dependency through an indirect property escapes the fence
A phase orders the items it can see as suppliers. A dependency that exists only through an indirect property – most commonly an indirect StorageName such as
unit<uint32> WriteResults : nrofrows = 1
, StorageName = "='%LocalDataDir%/out/' + Start/Tile_name + '.dbf'";
– is not visible to the scan that assigns items to phases, so such an item stays in front of the fence and its work is not held back by it. Add an explicit reference to the phase result in ExplicitSuppliers to make the dependency visible.
example
container Results := PhaseContainer(Results0, 'Results for '+Context/ThisIterName+' are finished calculating');