-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsemantics.py
More file actions
135 lines (106 loc) · 3.57 KB
/
semantics.py
File metadata and controls
135 lines (106 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Semantic checks on cell methods.
"""
from cf_cell_methods import parse
def parse_if_str(cell_methods):
return parse(cell_methods) if isinstance(cell_methods, str) \
else cell_methods
def make_equality_comparator(comparison):
comparison = parse_if_str(comparison)
return lambda cell_methods: parse_if_str(cell_methods) == comparison
# Hydrology cell method comparators
is_streamflow_raw = make_equality_comparator("time: mean within days")
is_streamflow_climatology = make_equality_comparator(
"time: mean within days time: mean over days"
)
is_rp5_streamflow_single_model = make_equality_comparator(
"time: mean within days time: mean over days"
)
is_rp5_streamflow_climatology_single_model = make_equality_comparator(
"time: mean within days time: max over days time:mean over days"
)
is_rp5_streamflow_climatology_ensemble_mean = make_equality_comparator(
"time: mean within days time: max over days time: mean over days "
"models: mean"
)
def is_rp5_streamflow_ensemble_percentile(p, cell_methods):
cell_methods = parse_if_str(cell_methods)
return (
len(cell_methods) == 4
and is_rp5_streamflow_climatology_single_model(cell_methods[0:3])
and cell_methods[4] == parse(f"models: percentile[{p}]")[0]
)
# These comparators may or may not be useful to us and/or may be better
# reformulated with `match`. Kind of on hold here.
conventional_methods = {
"num",
"name",
"point",
"sum",
"maximum",
"maximum_absolute_value",
"median",
"mid_range",
"minimum",
"minimum_absolute_value",
"mean",
"mean_absolute_value",
"mean_of_upper_decile",
"mode",
"range",
"root_mean_square",
"standard_deviation",
"sum_of_squares",
"variance",
}
extended_methods = {
("percentile", 1),
}
def is_conventional_1(cell_method):
"""
Test if a cell_method is "conventional", which is to say does it conform
to CF Conventions, specifically:
- has a conventional method (e.g., "mean")
We can't test more than this because it requires the larger context of
the other cell_methods (for distinguishing climatological methods) or
the NetCDF file (for validating axis names).
Not much use, is this?
"""
return (
cell_method.method.name in conventional_methods
and len(cell_method.method.params) == 0
)
def is_extended_1(cell_method):
return (
is_conventional_1(cell_method)
or cell_method.method.signature() in extended_methods
)
def is_conventional_climatology(cell_methods):
if not all(is_conventional_1(cm) for cm in cell_methods):
return False
if not all(cm.name == "time" for cm in cell_methods):
return False
within_over = tuple((cm.within, cm.over) for cm in cell_methods)
if (within_over not in {
(("years", None), (None, "years")),
(("days", None), (None, "days")),
(("days", None), (None, "days"), (None, "years")),
}):
return False
return True
def is_conventional(cell_methods):
# Check methods
for cell_method in cell_methods:
if not is_conventional_1(cell_method):
return False
# Check climatological cases
if is_conventional_climatology(cell_methods):
return True
# Check non-climatological cases
# - over clause if present always accompanied by where clause
# - no within clause
if not all(cm.over is None or cm.where is not None for cm in cell_methods):
return False
if not all(cm.within is None for cm in cell_methods):
return False
return True