This part of the Rose user guide walks you through using more than one cylc family for configuring a task's runtime (multiple inheritance).
This helps when tasks naturally belong to more than one category - e.g. an application type category and a job submission type category.
Our example suite will control a drag race.
Create a new suite (or just a new directory somewhere - e.g. in your homespace) containing a blank rose-suite.conf and a suite.rc file that looks like this.
Create a subdirectory in your suite directory called lib/ and create a file inside this subdirectory called output.html with this content. This is a web page that summarises the suite output.
We also need to copy the library jquery.min.js into the same directory.
We'll also need an executable script that looks
like
this - create a bin/ subdirectory in
your suite directory, and paste the script into a
file called race. The bin/
directory is added to the path by cylc
,
which means you can just specify the command in
script
(e.g. script =
race).
We need to make the file executable as well - you'll need to run:
chmod +x bin/race
where your current working directory is the suite directory.
A realistic scenario for multiple inheritance might be when you have one set of families handling job submission (e.g. parallel vs serial) and one set driving the particular setup of the code run by the task (e.g. for different systems).
In our suite.rc file, there is a set of families for the engine (ENGINE_PETROL, ENGINE_ELECTRIC), and one for the actual chassis and body (BODY_CAR, BODY_TRUCK).
We need to use configuration from both sets to build a racer.
We can see from the graph specification in dependencies that we have a family called COMPETITOR_VEHICLE whose tasks will be run.
BODY_CAR and BODY_TRUCK themselves inherit from COMPETITOR_VEHICLE, so any tasks belonging to these families will also belong to COMPETITOR_VEHICLE and will be run.
Let's start off with creating a configuration for a task called red_car.
We'll inherit from a single family BODY_CAR - put this under the [runtime] section:
[[red_car]] inherit = BODY_CAR
Since BODY_CAR inherits from COMPETITOR_VEHICLE, and every task/family inherits from root, the order configuration is applied and overwritten in is:
settings in root extended/overwritten by settings in COMPETITOR_VEHICLE extended/overwritten by settings in BODY_CAR extended/overwritten by settings in red_car
In a diagram form, the inheritance looks like:
root | COMPETITOR_VEHICLE | BODY_CAR | red_car
This means that any settings in, for example, root, can be overwritten by settings from the others. This is the standard way that single inheritance of families works.
We now need an engine - this means that we need to include some configuration from an entirely separate family.
Add another family to inherit from by writing:
[[red_car]] inherit = BODY_CAR, ENGINE_ELECTRIC
In a diagram form, the inheritance now looks like:
root / \__________ / \ COMPETITOR_VEHICLE ENGINE_ELECTRIC / _____/ BODY_CAR / \ / red_car
The order of inheritance becomes:
settings in root extended/overwritten by settings in ENGINE_ELECTRIC extended/overwritten by settings in COMPETITOR_VEHICLE extended/overwritten by BODY_CAR extended/overwritten by red_car
We can see that settings in ENGINE_ELECTRIC could be overwritten by the other families and the task itself - in other words, the inheritance list in inherit = BODY_CAR, ENGINE_ELECTRIC is basically last-to-first (ENGINE_ELECTRIC then the BODY_CAR-related families (COMPETITOR_VEHICLE and BODY_CAR)).
We also need some racing colours, which should be task-specific - change the runtime to:
[[red_car]] inherit = BODY_CAR, ENGINE_ELECTRIC [[[environment]]] COMP_COLOUR = red
When cylc
evaluates this runtime now,
it will be equivalent to:
[[red_car]] # From COMPETITOR_VEHICLE: script = race [[[environment]]] # From ENGINE ELECTRIC: COMP_GEAR_RATIOS = 2.0 COMP_POWER_FRAC_VS_1000_RPM = 0.63 0.65 0.66 0.69 0.71 0.73 0.76 0.78 0.81 0.84 0.88 0.92 0.96 1.0 0.8 0.5 COMP_MAX_POWER_KW = 126 # From BODY_CAR: COMP_MASS_KG = 1000 COMP_WHEEL_DIAMETER_M = 0.5 # From red_car itself: COMP_COLOUR = red
Note that because configuration in the task is applied last, you can override any family configuration at the task level - whether single inheritance or multiple.
A race isn't a race without more than one competitor - add another COMPETITOR_VEHICLE task in the runtime:
[[blue_truck]] inherit = BODY_TRUCK, ENGINE_PETROL [[[environment]]] COMP_COLOUR = blue
This task inherits from different families, but gives a similar kind of configuration to red_car.
Go ahead and run the suite with rose
suite-run
. The two vehicles will race over a
quarter mile, and you should see the results in the
cylc gui
. The environment variables we
set up will be printed in the standard output of both
tasks. You can view the output with Rose Bush by
following the link to the job.out file
of the output task.
This is a successful implementation of multiple inheritance! The next thing to do is to make it slightly more tricky.
Let's suppose the race organisers decide on a maximum engine power for competitors to adhere to. At the moment, COMP_MAX_POWER_KW is different in the two types of engine we've specified.
As this will be common to all competitors, it makes sense to move the setting to the COMPETITOR_VEHICLE class.
Remove all the lines in the suite.rc file for COMP_MAX_POWER_KW, and change the COMPETITOR_VEHICLE runtime to:
[[COMPETITOR_VEHICLE]] pre-script = printenv | sort | grep ^COMP script = race [[[environment]]] COMP_MAX_POWER_KW = 130 COMP_OUTPUT_DIR = $CYLC_SUITE_SHARE_PATH
We'll also change the ENGINE families so that they include this setting through inheritance - add inherit lines to both ENGINE families:
[[ENGINE_PETROL]] inherit = COMPETITOR_VEHICLE
and
[[ENGINE_ELECTRIC]] inherit = COMPETITOR_VEHICLE
Our red_car task has inherit = BODY_CAR, ENGINE_ELECTRIC.
The inheritance order for the red_car task used to be:
settings in root extended/overwritten by settings in ENGINE_ELECTRIC extended/overwritten by settings in COMPETITOR_VEHICLE extended/overwritten by BODY_CAR extended/overwritten by red_car
However, since the ENGINE families now inherit from COMPETITOR_VEHICLE, they should be evaluated after it - they should be able to override that family. The algorithm will recognise this and change the order accordingly.
This means that the order will now be:
settings in root extended/overwritten by settings in COMPETITOR_VEHICLE extended/overwritten by settings in ENGINE_ELECTRIC extended/overwritten by BODY_CAR extended/overwritten by red_car
which is subtly different.
This is a case of diamond inheritance, where the diagram goes:
root | COMPETITOR_VEHICLE / \ BODY_CAR ENGINE_ELECTRIC \ / red_car
Although this is more complex, it's still easy to override settings.
Let's suppose there's some cheating going on, and the standard ENGINE_PETROL family actually has a bit more power. Change the ENGINE_PETROL family to override the COMP_MAX_POWER_KW setting:
[[ENGINE_PETROL]] inherit = COMPETITOR_VEHICLE [[[environment]]] COMP_GEAR_RATIOS = 3.18 2.26 1.68 1.29 1.06 COMP_POWER_FRAC_VS_1000_RPM = 0.18 0.3 0.6 0.88 1.0 0.6 COMP_MAX_POWER_KW = 200 # Cheating!
Meanwhile, our red_car task has invested in some oversize wheels - change the red_car runtime to read:
[[red_car]] inherit = BODY_CAR, ENGINE_ELECTRIC [[[environment]]] COMP_COLOUR = red COMP_WHEEL_DIAMETER_M = 1.0 # Override the standard BODY_CAR setting
Run the suite again, and have a look at the output files - the overrides or overwriting of settings should have happened. COMP_WHEEL_DIAMETER_M should now be 1.0 for the red_car task, and the COMP_MAX_POWER_KW should be 200 in the blue_truck task.
If you like, have a go at overriding various settings in the tasks and families, and seeing at which points this becomes effective.
You can inherit from any number of families, not just two - for example, you could invent a scenario where you might write:
[[red_car]] inherit = BODY_CAR, ENGINE_ELECTRIC, SPOILER_OUTSIZE
The inheritance order will still be evaluated last-to-first, so both BODY_CAR and ENGINE_ELECTRIC (and any families they inherit from) can override SPOILER_OUTSIZE. The red_car task itself can override any inheritance.
For more information, see: