Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Isolated start-up and shut-down graphs. #5090

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ workflows with many-to-many dependencies (e.g. `<a> => <b>`).

### Enhancements

[#5184](https://github.com/cylc/cylc-flow/pull/5184) - Scan for active
runs of the same workflow at install time.

[#5032](https://github.com/cylc/cylc-flow/pull/5032) - Set a default limit of

[#5229](https://github.com/cylc/cylc-flow/pull/5229) -
- Added a single command to validate a previously run workflow against changes
to its source and reinstall a workflow.
Expand Down
1 change: 1 addition & 0 deletions changes.d/5090.feat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement initial and final graphs, distinct from the main cycling graph.
44 changes: 33 additions & 11 deletions cylc/flow/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
get_sequence, get_sequence_cls, init_cyclers, get_dump_format,
INTEGER_CYCLING_TYPE, ISO8601_CYCLING_TYPE
)
from cylc.flow.cycling.nocycle import (
NocycleSequence,
NOCYCLE_SEQ_ALPHA,
NOCYCLE_SEQ_OMEGA
)
from cylc.flow.id import Tokens
from cylc.flow.cycling.integer import IntegerInterval
from cylc.flow.cycling.iso8601 import ingest_time, ISO8601Interval
Expand Down Expand Up @@ -277,6 +282,7 @@
self.start_point: 'PointBase'
self.stop_point: Optional['PointBase'] = None
self.final_point: Optional['PointBase'] = None
self.nocycle_sequences: Set['NocycleSequence'] = set()
self.sequences: List['SequenceBase'] = []
self.actual_first_point: Optional['PointBase'] = None
self._start_point_for_actual_first_point: Optional['PointBase'] = None
Expand Down Expand Up @@ -616,9 +622,16 @@
if (
'cycling mode' not in self.cfg['scheduling'] and
self.cfg['scheduling'].get('initial cycle point', '1') == '1' and
all(item in ['graph', '1', 'R1'] for item in graphdict)
all(
item in [
'graph', '1', 'R1',
str(NOCYCLE_SEQ_ALPHA),
str(NOCYCLE_SEQ_OMEGA)
]
for item in graphdict
)
):
# Pure acyclic graph, assume integer cycling mode with '1' cycle
# Non-cycling graph, assume integer cycling mode with '1' cycle
self.cfg['scheduling']['cycling mode'] = INTEGER_CYCLING_TYPE
for key in ('initial cycle point', 'final cycle point'):
if key not in self.cfg['scheduling']:
Expand Down Expand Up @@ -2106,15 +2119,24 @@
try:
seq = get_sequence(section, icp, fcp)
except (AttributeError, TypeError, ValueError, CylcError) as exc:
if cylc.flow.flags.verbosity > 1:
traceback.print_exc()
msg = 'Cannot process recurrence %s' % section
msg += ' (initial cycle point=%s)' % icp
msg += ' (final cycle point=%s)' % fcp
if isinstance(exc, CylcError):
msg += ' %s' % exc.args[0]
raise WorkflowConfigError(msg)
self.sequences.append(seq)
try:
seq = NocycleSequence(section)
except ValueError:
if cylc.flow.flags.verbosity > 1:
traceback.print_exc()

Check warning on line 2126 in cylc/flow/config.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/config.py#L2126

Added line #L2126 was not covered by tests
msg = (
f"Cannot process recurrence {section}"
f" (initial cycle point={icp})"
f" (final cycle point={fcp})"
)
if isinstance(exc, CylcError):
msg += ' %s' % exc.args[0]
raise WorkflowConfigError(msg)
else:
self.nocycle_sequences.add(seq)
else:
self.sequences.append(seq)

parser = GraphParser(
family_map,
self.parameters,
Expand Down
6 changes: 5 additions & 1 deletion cylc/flow/cycling/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,11 @@ def TYPE_SORT_KEY(self) -> int:
@classmethod
@abstractmethod # Note: stacked decorator not strictly enforced in Py2.x
def get_async_expr(cls, start_point=0):
"""Express a one-off sequence at the initial cycle point."""
"""Express a one-off sequence at the initial cycle point.

Note "async" has nothing to do with asyncio. It was a (bad)
name for one-off (non-cycling) graphs in early Cylc versions.
"""
pass

@abstractmethod
Expand Down
7 changes: 6 additions & 1 deletion cylc/flow/cycling/integer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
import re

from cylc.flow.cycling import (
PointBase, IntervalBase, SequenceBase, ExclusionBase, parse_exclusion, cmp
PointBase,
IntervalBase,
SequenceBase,
ExclusionBase,
parse_exclusion,
cmp
)
from cylc.flow.exceptions import (
CylcMissingContextPointError,
Expand Down
163 changes: 163 additions & 0 deletions cylc/flow/cycling/nocycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
Cycling logic for isolated non-cycling startup and shutdown graphs.
"""

from cylc.flow.cycling import PointBase, SequenceBase, cmp

# TODO: scheduler check DB to be sure alpha and omega sections have run or not.

# cycle point values
NOCYCLE_PT_ALPHA = "alpha"
NOCYCLE_PT_OMEGA = "omega"

NOCYCLE_POINTS = (
NOCYCLE_PT_ALPHA,
NOCYCLE_PT_OMEGA
)

CYCLER_TYPE_NOCYCLE = "nocycle"
CYCLER_TYPE_SORT_KEY_NOCYCLE = 1


class NocyclePoint(PointBase):
"""A string-valued point."""

TYPE = CYCLER_TYPE_NOCYCLE
TYPE_SORT_KEY = CYCLER_TYPE_SORT_KEY_NOCYCLE

__slots__ = ('value')

def __init__(self, value: str) -> None:
if value not in [NOCYCLE_PT_ALPHA, NOCYCLE_PT_OMEGA]:
raise ValueError(f"Illegal Nocycle value {value}")
self.value = value

def __hash__(self):
return hash(self.value)

def __eq__(self, other):
return str(other) == self.value

def __le__(self, other):
"""less than or equal only if equal."""
return str(other) == self.value

def __lt__(self, other):
"""never less than."""
return False

def __gt__(self, other):
"""never greater than."""
return False

def __str__(self):
return self.value

def _cmp(self, other):
return cmp(int(self), int(other))

Check warning on line 73 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L73

Added line #L73 was not covered by tests

def add(self, other):
# NOT USED
return None

Check warning on line 77 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L77

Added line #L77 was not covered by tests

def sub(self, other):
# NOT USED
return None

Check warning on line 81 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L81

Added line #L81 was not covered by tests


class NocycleSequence(SequenceBase):
"""A single point sequence."""

def __init__(self, dep_section, p_context_start=None, p_context_stop=None):
"""Workflow cycling context is ignored."""
self.point = NocyclePoint(dep_section)

def __hash__(self):
return hash(str(self.point))

def is_valid(self, point):
"""Is point on-sequence and in-bounds?"""
return str(point) == self.point

def get_first_point(self, point):
"""First point is the only point"""
return self.point

def get_start_point(self, point):
"""First point is the only point"""
return self.point

Check warning on line 104 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L104

Added line #L104 was not covered by tests

def get_next_point(self, point):
"""There is no next point"""
return None

def get_next_point_on_sequence(self, point):
"""There is no next point"""
return None

def __eq__(self, other):
try:
return other.point == self.point
except AttributeError:

Check warning on line 117 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L117

Added line #L117 was not covered by tests
# (other is not a nocycle sequence)
return False

Check warning on line 119 in cylc/flow/cycling/nocycle.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/cycling/nocycle.py#L119

Added line #L119 was not covered by tests

def __str__(self):
return str(self.point)

def TYPE(self):
raise NotImplementedError

def TYPE_SORT_KEY(self):
raise NotImplementedError

def get_async_expr(cls, start_point=0):
raise NotImplementedError

def get_interval(self):
"""Return the cycling interval of this sequence."""
raise NotImplementedError

def get_offset(self):
"""Deprecated: return the offset used for this sequence."""
raise NotImplementedError

def set_offset(self, i_offset):
"""Deprecated: alter state to offset the entire sequence."""
raise NotImplementedError

def is_on_sequence(self, point):
"""Is point on-sequence, disregarding bounds?"""
raise NotImplementedError

def get_prev_point(self, point):
"""Return the previous point < point, or None if out of bounds."""
raise NotImplementedError

def get_nearest_prev_point(self, point):
"""Return the largest point < some arbitrary point."""
raise NotImplementedError

def get_stop_point(self):
"""Return the last point in this sequence, or None if unbounded."""
raise NotImplementedError


NOCYCLE_SEQ_ALPHA = NocycleSequence(NOCYCLE_PT_ALPHA)
NOCYCLE_SEQ_OMEGA = NocycleSequence(NOCYCLE_PT_OMEGA)
Loading
Loading