Include a task in all but the first cycle point

Hi there

In this section of the Cylc docs, it tells you how to include something in only the first cycle point of a suite.

How would I include a task in every cycle apart from the first one?

Thanks!

Jonny

Hi Jonny,

That’s easy to do with the full form of the graph recurrence notation: R[n]/A/D means Repeat (n times if given, else indefinitely) from start cycle point A, with interval D. And the start cycle point for the sequence can be given relative to the suite’s initial cycle point (denoted ^).

An example, for a yearly cycle:

[cylc]
    cycle point format = %Y
[scheduling]
    initial cycle point = 2000
    [[dependencies]]
        [[[R/^/P1Y]]]  # initial cycle point onward (can be shortened to just "P1Y")
             graph = "foo[-P1Y] => foo => bar"
        [[[R/^+P1Y/P1Y]]]  # second cycle point onward 
             graph = "foo => qux"

Result:

Hilary

1 Like

Hi,

There is some good documentation on recurrence sections in another part of the docs (https://cylc.github.io/doc/built-sphinx-single/index.html) I often look back to this list of examples (https://cylc.github.io/doc/built-sphinx-single/index.html#advanced-examples).

Hillary’s solution is the nicest (to those familiar with Cylc’s internals):

R/^+P1Y/P1Y

There is another approach which has it’s place which is to exclude (!) the intitial cycle point (^) from the recurrence:

R/P1Y!^

https://cylc.github.io/doc/built-sphinx-single/index.html#advanced-exclusion-syntax

2 Likes

Many thanks for your help Hilary and Oliver!

The suite I am working on is somewhat more complex than this however!

This is the section I want to change…

[[[ R/^/{{FMT}} ]]]
    graph = """
        {% if RUN %}
            coupled[-{{FMT}}] => coupled {{ '=> \\' if POSTPROC or HOUSEKEEP else '' }}
        {% if POSTPROC %}
            POSTPROC_GROUP{{ ':succeed-all => \\' if HOUSEKEEP else '' }}
        {% endif %}
        {% if HOUSEKEEP %}
            housekeeping
        {% endif %}
        {% if POSTPROC and SPLIT_PP %}
            postproc_atmos[-{{FMT}}] => postproc_atmos
            postproc_cice[-{{FMT}}] => postproc_cice
            postproc_nemo[-{{FMT}}] => postproc_nemo
        {% elif POSTPROC %}
            postproc[-{{FMT}}] => postproc
        {% endif %}
        {% endif %}
"""

Basically all I want to do is to change housekeeping to py_for_afterburner => housekeeping for every cycle point apart from the first one.

In this example would be easier (possible?!) to use an if statement instead?

Thanks :slight_smile:

Hi Jonny,

would be easier (possible?!) to use an if statement instead?

If you mean a Jinja2 `{% if … %}’ statement to test if the current cycle point is the initial cycle point - no you certainly can’t do that because Jinja2 is a template preprocessor: it is all “processed out” when the suite is parsed, to generate the final suite configuration that Cylc sees (i.e. it all happens before runtime so there is no “current cycle point” to compare).

You could run py_for_afterburner => housekeeping in all cycles including the first, but use a run time test in the py_for_afterburner job scripting to compare $CYLC_TASK_CYCLE_POINT with $CYLC_SUITE_INITIAL_CYCLE_POINT, and have the task succeed without doing anything in the initial cycle (and only do its real work in cycle point two onward). However, that makes the graph somewhat misleading. Better to do what Oliver and I suggested above, either method works (the complexity of your suite - as shown at least - is only in the Jinja2 switches to construct the graph based on input variables; in terms of cycling it is just a single straightforward sequence). Here it is with Oliver’s method:

  [[dependencies]]
     [[[ R1 ]]]  # first cycle point only
        graph = "stuff => housekeeping"
     [[[ {{FMT}}!^ ]]]  # every cycle point except for the first 
        graph = "stuff => py_for_afterburner => housekeeping"
1 Like

OK great, that works! :partying_face:

Here’s the fixed graph…

Thanks a lot for your help, and to Oliver too of course.

Jonny

1 Like