Understanding date cycling

I want to cycle through the year 1999 starting on the first Monday and running weekly on Monday.
I have the following in scheduling, the get_data script is run once in each cycle and the run and st_archive are ensembles of 10 members each. I’m confused by the dates cylc appears to cycle on:
19990103T1800-06 19990109T1800-06 19990116T1800-06 19990123T1800-06 19990130T1800-06 - why?

[scheduling]                                                                                           
  initial cycle point = 19990104T0000Z                                                                 
  final cycle point = 19991226T0000Z                                                                   
                                                                                                       
  [[dependencies]]                                                                                     
    [[[R1]]]                                                                                           
      graph = "get_data => run<member> => st_archive<member> "                                         
    [[[R/P1W]]] # Weekly Cycling                                                                       
      graph = """                                                                                      
             st_archive<member>[-P1W] => get_data => run<member>                                       
             run<member> => st_archive<member>                                                         
             """

Hi Jim,

Firstly, the T1800-06 is because your UTC (Z) initial and final cycle points are getting translated to local time (UTC-06) because you haven’t set UTC mode = True in the suite (or else used local time throughout).

Secondly, to make an ongoing weekly cycle starting at the initial cycle point, the full and abbreviated expressions are:

R/^/P1W  # full
R//P1W
P1W

The following expressions, however, make an ongoing weekly cycle up to the final cycle point (i.e. ending exactly on the final cycle point):

R/P1W/$  # full
P1W/$
R/P1W

So, I presume you meant to write R//P1W not R/P1W (a subtle difference I guess … this is powerful notation, but it has to be wielded carefully!). The two forms will generate the exact same sequence so long as the final cycle point is on-sequence - which in your case it isn’t, because 26 Dec 1999 was a Sunday, not a Monday.

The relevant section in the user guide starts here: https://cylc.github.io/doc/built-sphinx-single/index.html#graph-section-headings

Hilary

Thank you. I understand this is powerful notation, but I have a hard time grasping it.
I have had a request to run for every Monday in August from 1999 to 2019 - can this be expressed in the suite.rc?

Fair enough, I have to look up the documentation plenty myself. But on the upside it can generate almost any conceivable regular date-time sequence, and is also “standards based” (ISO 8601 recurrences). In my opinion, it is harder to make mistakes if you stick to the non-abbreviated recurrence forms (in case that helps).

That’s an interesting one. Cylc’s graph recurrence notation can define any regular sequence, with optional exclusions that can also be regular sequences, but I can’t see how to express a multi-year weekly cycle that excludes all months but August. (Maybe someone else can).

If you have to, you could resort to a simple weekly Monday cycle R/W-1/P1W and tasks that share a few lines of scripting to simply succeed without doing anything if the cycle point month is not August.

A more elegant but more involved way is a yearly-cycling suite that runs a Mondays-in-August sub-suite for each year:

[cylc]
   cycle point format = %Y
[scheduling]
   initial cycle point = 1999
   final cycle point = 2019
   [[dependencies]]
       [[[R1]]]
           graph = prep => august
       [[[P1Y]]]
           graph = august[-P1Y] => august
[runtime]
   [[prep]]
      script = """rm -r $HOME/cylc-run/august
cylc register august $HOME/suites/august"""
   [[august]]
      script = cylc run --no-detach --set=YEAR=$CYLC_TASK_CYCLE_POINT august

And the sub-suite, in $HOME/suites/august/suite.rc:

#!Jinja2
[cylc]
   cycle point format = %Y-%m-%d
[scheduling]
   initial cycle point = {{YEAR}}-08-01
   final cycle point = {{YEAR}}-08-31
   [[dependencies]]
      [[[R/W-1/P1W]]]
          graph = foo

Note there is no overlap between successive runs of the sub-suite, so I just re-used the same sub-suite run directory for each year. Result, in the sub-suite run directory, on running the main suite:

[drugs-and-money]$ find august -name 'job.out' | sort
august/log/job/1999-08-02/foo/01/job.out
august/log/job/1999-08-09/foo/01/job.out
august/log/job/1999-08-16/foo/01/job.out
august/log/job/1999-08-23/foo/01/job.out
august/log/job/1999-08-30/foo/01/job.out
august/log/job/2000-08-07/foo/01/job.out
august/log/job/2000-08-14/foo/01/job.out
august/log/job/2000-08-21/foo/01/job.out
august/log/job/2000-08-28/foo/01/job.out
...
august/log/job/2018-08-06/foo/01/job.out
august/log/job/2018-08-13/foo/01/job.out
august/log/job/2018-08-20/foo/01/job.out
august/log/job/2018-08-27/foo/01/job.out
august/log/job/2019-08-05/foo/01/job.out
august/log/job/2019-08-12/foo/01/job.out
august/log/job/2019-08-19/foo/01/job.out
august/log/job/2019-08-26/foo/01/job.out

Also, I always try to get users to experiment with trivial example workflows to see how these things work. Here’s the one I used for your first question:

[cylc]
   cycle point format = %Y-%m-%d
[scheduling]
   initial cycle point = 1999-01-04  # Monday
   #final cycle point = 1999-12-26  # Sunday!!!
   final cycle point = 1999-12-27  # Monday
   [[dependencies]]
        # from initial point:
        #[[[R/^/P1W]]]
        #[[[R//P1W]]]
        #[[[P1W]]]

        # to final point:
        [[[R/P1W]]]
             graph = foo

Then you can use cylc graph [START-POINT] [STOP-POINT] to see the generated cycle points, or cylc list --points=START,STOP, e.g.:

[drugs-and-money]$ cylc list --points=1999-01,2000-01 jim
foo.1999-01-04
foo.1999-01-11
foo.1999-01-18
...
foo.1999-12-13
foo.1999-12-20
foo.1999-12-27
1 Like

This is very helpful, thank you.

thank you hilary for posting the trivial example.
that does enlighten.

So I am trying a variation on this that will create suites for each month:

[cylc]
   cycle point format = %Y
   [[parameters]]
      mname = jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec 
[scheduling]
   initial cycle point = 1999
   final cycle point = 2019
   [[dependencies]]
       [[[R1]]]
           graph = prep => month<mname>
       [[[P1Y]]]
           graph = month<mname>[-P1Y] => month<mname>
[runtime]
   [[prep]]
      script = """
rm -fr $HOME/cylc-run/${CYLC_TASK_PARAM_mname}
cylc register ${CYLC_TASK_PARAM_mname} ${FCST_HOME}/cylc/70Lwaccm6/${CYLC_TASK_PARAM_mname}
"""
   [[month<mname>]]
      script = cylc run --no-detach --set=YEAR=$CYLC_TASK_CYCLE_POINT --set=MONTH=${CYLC_TASK_PARAM_mname} ${CYLC_TASK_PARAM_mname}

but I get an error

log/job/1999/prep/01/job: line 35: CYLC_TASK_PARAM_mname: unbound variable

Shouldn’t this variable be defined?

No, it shouldn’t be defined in the prep task, which is not parameterized by mname.

To reduce to a slightly simpler example, if you have a parameter m with values “cat”, “dog”, “fish” (say) then in the graph this:

graph = "prep => foo<m>"

is equivalent to this:

graph = """
     prep => foo_cat
     prep => foo_dog
     prep => foo_fish"""

(or if your prefer, prep => foo_cat & foo_dog & foo_fish)

For task definitions under runtime you would have something like this:

[runtime]
   [[prep]]
        # (prep runtime config)
   [[foo<m>]]
        # (foo<m> runtime config)

Like for the graph, that is equivalent (for the given parameter values) this:

[runtime]
    [[prep]]
          # (prep runtime config)
   [[foo_cat]]
          # (foo_cat runtime config)
   [[foo_dog]]
          # (foo_dog runtime config)
   # etc.

Now Cylc sets the variable CYLC_TASK_PARAM_m=cat in task foo_cat; and it sets CYLC_TASK_PARAM_m=dog in task foo_dog; and so on. I.e. parameterized tasks can retrieve their own specific parameter value (or values, if multiple parameters are used) from their job environment.

In your example, what value were you expecting $CYLC_TASK_PARAM_mname have in the runtime job environment of task prep, which is not parameterized by mname?

Looking back to my example, the only month you asked for was august, so “august” was not a parameter value. To do the same for multiple months you’d presumably want to loop over the list of months and register the sub-suite for each one, inside the prep task. Only parameterized tasks get access to the values of the parameters they are constructed from, as I just described (and then, only to the specific parameter value(s) for the task, not the whole range(s)). I.e. we don’t automatically pass all parameter lists to all tasks, as that’s almost never needed. To do that, you need to initialize your parameters with a Jinja2 variable, and then you can do whatever you want with the variable throughout the suite.

#!Jinja2
{% set months = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", 
[cylc]
     [[parameters]]
         mname = {{ months | join(',') }}
# ...
[runtime]
     [[prep]]
           script = """
{% for month in months %}
      cylc reg {{month}} blah...
{% endfor %}
# ...

Check the result of Jinja2 pre-processing with cylc view -j SUITE

Excellent, thank you.