CMIP7-data-request-api 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. CMIP7_data_request_api-1.1.2.dist-info/LICENSE +21 -0
  2. CMIP7_data_request_api-1.1.2.dist-info/METADATA +210 -0
  3. CMIP7_data_request_api-1.1.2.dist-info/RECORD +36 -0
  4. CMIP7_data_request_api-1.1.2.dist-info/WHEEL +5 -0
  5. CMIP7_data_request_api-1.1.2.dist-info/entry_points.txt +2 -0
  6. CMIP7_data_request_api-1.1.2.dist-info/top_level.txt +1 -0
  7. data_request_api/__init__.py +1 -0
  8. data_request_api/command_line/__init__.py +0 -0
  9. data_request_api/command_line/export_dreq_lists_json.py +136 -0
  10. data_request_api/dev/JA/__init__.py +0 -0
  11. data_request_api/dev/JA/check_plev_requests.py +416 -0
  12. data_request_api/dev/JA/read_feedback_spreadsheet.py +141 -0
  13. data_request_api/dev/JA/workflow_example_GRtest.py +275 -0
  14. data_request_api/dev/JA/workflow_example_test.py +222 -0
  15. data_request_api/dev/MM/checksum.py +68 -0
  16. data_request_api/dev/MM/walking_data_request.ipynb +380 -0
  17. data_request_api/dev/MS/dreq_content_and_walking_data_request.ipynb +3755 -0
  18. data_request_api/dev/__init__.py +0 -0
  19. data_request_api/stable/__init__.py +0 -0
  20. data_request_api/stable/content/README.MD +106 -0
  21. data_request_api/stable/content/__init__.py +0 -0
  22. data_request_api/stable/content/dreq_api/__init__.py +0 -0
  23. data_request_api/stable/content/dreq_api/consolidate_export.py +488 -0
  24. data_request_api/stable/content/dreq_api/dreq_content.py +593 -0
  25. data_request_api/stable/content/dreq_api/mapping_table.py +335 -0
  26. data_request_api/stable/content/dreq_api/test_dreq_content.py +194 -0
  27. data_request_api/stable/content/dump_transformation.py +550 -0
  28. data_request_api/stable/query/__init__.py +0 -0
  29. data_request_api/stable/query/data_request.py +1120 -0
  30. data_request_api/stable/query/dreq_classes.py +372 -0
  31. data_request_api/stable/query/dreq_query.py +981 -0
  32. data_request_api/stable/query/vocabulary_server.py +208 -0
  33. data_request_api/stable/utilities/__init__.py +0 -0
  34. data_request_api/stable/utilities/logger.py +71 -0
  35. data_request_api/stable/utilities/tools.py +49 -0
  36. data_request_api/version.py +16 -0
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+
6
+ """
7
+ from __future__ import division, print_function, unicode_literals, absolute_import
8
+
9
+ import pprint
10
+ from collections import defaultdict
11
+
12
+ import six
13
+
14
+ import json
15
+
16
+ from data_request_api.stable.content.dreq_api import dreq_content as dc
17
+ from data_request_api.stable.query.data_request import DataRequest
18
+ from data_request_api.stable.utilities.logger import change_log_file, change_log_level
19
+
20
+ # Set up log file (default to stdout) and log level
21
+ change_log_file(default=True)
22
+ change_log_level("debug")
23
+
24
+ ### Step 1: Get the content of the DR
25
+ # Define content version to be used
26
+ use_dreq_version = 'v1.0beta'
27
+ # use_dreq_version = "first_export"
28
+ # use_dreq_version = 'new_export_15Oct2024'
29
+ # Download specified version of data request content (if not locally cached)
30
+ # dc.retrieve(use_dreq_version)
31
+ # Load content into python dict
32
+ # content = dc.load(use_dreq_version)
33
+
34
+ ### Step 2: Load it into the software of the DR
35
+ # DR = DataRequest.from_input(json_input=content, version=use_dreq_version)
36
+ # path = f'../sandbox/MS/dreq_api/dreq_res/{use_dreq_version}'
37
+ path = f'../MS/dreq_api/dreq_res/{use_dreq_version}'
38
+ DR = DataRequest.from_separated_inputs(DR_input=f"{path}/DR_content.json",
39
+ VS_input=f"{path}/VS_content.json")
40
+
41
+
42
+ GR_demo = False
43
+ if GR_demo:
44
+ ### Step 3: Get information from the DR
45
+ # -> Print DR content
46
+ print(DR)
47
+ # -> Print an experiment group content
48
+ print(DR.get_experiments_groups()[0])
49
+ # -> Get all variables' id associated with an opportunity
50
+ print(DR.find_variables_per_opportunity(DR.get_opportunities()[0]))
51
+ # -> Get all experiments' id associated with an opportunity
52
+ print(DR.find_experiments_per_opportunity(DR.get_opportunities()[0]))
53
+ # -> Get information about the shapes of the variables of all variables groups
54
+ rep = dict()
55
+ for elt in DR.get_variables_groups():
56
+ rep[elt.id] = dict(spatial_shape=set(), frequency=set(), temporal_shape=set(), physical_parameter=set())
57
+ for var in elt.get_variables():
58
+ for key in ["spatial_shape", "frequency", "temporal_shape", "physical_parameter"]:
59
+ rep[elt.id][key] = rep[elt.id][key].union(set([elt.get("name", "???") if isinstance(elt, dict) else elt
60
+ for elt in var.__getattribute__(key)]))
61
+
62
+ rep = defaultdict(lambda: defaultdict(set))
63
+ for elt in DR.get_variables_groups():
64
+ for var in elt.get_variables():
65
+ param = var.physical_parameter["name"]
66
+ freq = var.frequency["name"]
67
+ realm = set([elt if isinstance(elt, six.string_types) else elt.get("name", "???") for elt in var.modelling_realm])
68
+ spt_shp = set([elt if isinstance(elt, six.string_types) else elt.get("name", "???") for elt in var.spatial_shape])
69
+ tmp_shp = set([elt if isinstance(elt, six.string_types) else elt.get("name", "???") for elt in var.temporal_shape])
70
+ for (rlm, freq, sshp, tshp) in zip(realm, [freq, ], spt_shp, tmp_shp):
71
+ rep[rlm][param].add(f"{freq} // {sshp} // {tshp}")
72
+ pprint.pprint(rep)
73
+ # pprint.pprint(rep_data)
74
+
75
+
76
+
77
+
78
+ # from copy import deepcopy
79
+ # DR0 = deepcopy(DR)
80
+
81
+ print(type(DR))
82
+
83
+ opp = DR.get_opportunities()[0]
84
+
85
+
86
+ # simpler way to do this?
87
+ def get_name(x):
88
+ return x.vs.get_element(x.DR_type, x.id, 'name')
89
+
90
+ title = 'Ocean Extremes'
91
+ opp = [opp for opp in DR.get_opportunities() if get_name(opp) == 'Ocean Extremes'][0]
92
+
93
+ # print()
94
+ # print(opp)
95
+
96
+ # print()
97
+ # for theme in opp.get_themes():
98
+ # print(theme)
99
+
100
+ # print()
101
+ # for expt_group in opp.get_experiments_groups():
102
+ # print(expt_group)
103
+
104
+ # print()
105
+ # for var_group in opp.get_variables_groups():
106
+ # print(var_group)
107
+
108
+ # print()
109
+
110
+
111
+ # print(len(opp_vars), len(opp_expts))
112
+
113
+ # var = opp_vars[0]
114
+
115
+ # copied this out of VS_content.json, surely there's a way to get this lookup info from DR object?
116
+ lookup = {
117
+ "priority_level": {
118
+ # note, this info is keyed on the uid, which is found in the export
119
+ # e.g. in dreq_release_export.json for v1.0beta:
120
+ # "Name": "High",
121
+ # "Notes": "High priority should be used sparingly",
122
+ # "UID": "527f5c94-8c97-11ef-944e-41a8eb05f654",
123
+ # "Value": 2,
124
+ "527f5c94-8c97-11ef-944e-41a8eb05f654": {
125
+ "name": "High",
126
+ "notes": "High priority should be used sparingly",
127
+ "value": 2
128
+ },
129
+ "527f5c95-8c97-11ef-944e-41a8eb05f654": {
130
+ "name": "Medium",
131
+ "value": 3
132
+ },
133
+ "527f5c96-8c97-11ef-944e-41a8eb05f654": {
134
+ "name": "Low",
135
+ "value": 4
136
+ },
137
+ "527f5c97-8c97-11ef-944e-41a8eb05f654": {
138
+ "name": "Core",
139
+ "notes": "Top priority -- adopted by panels",
140
+ "value": 1
141
+ }
142
+ }
143
+ }
144
+ priority_levels = [info['name'] for info in lookup['priority_level'].values()]
145
+
146
+ def get_unique_var_name(var):
147
+ return var.compound_name
148
+
149
+
150
+ use_opps = []
151
+ use_opps.append('Baseline Climate Variables for Earth System Modelling')
152
+ use_opps.append('Synoptic systems and impacts')
153
+ # use_opps.append('Climate impact assessments on freshwater ecosystems')
154
+ # use_opps.append('Ocean Extremes')
155
+
156
+ use_opps = 'all'
157
+
158
+ # lookup table of opportunities by their title
159
+ opps = {}
160
+ for opp in DR.get_opportunities():
161
+ title = get_name(opp)
162
+ assert title not in opps, f'opp title not unique: {title}'
163
+ opps[title] = opp
164
+
165
+ request = {} # dict to hold aggregated request
166
+
167
+ check = not True
168
+
169
+ if use_opps == 'all':
170
+ use_opps = list(opps.keys())
171
+
172
+ use_opps = sorted(use_opps)
173
+ for title in use_opps:
174
+
175
+ opp = opps[title]
176
+
177
+ if check:
178
+ opp_expts = set()
179
+ for expt_group in opp.experiments_groups:
180
+ opp_expts.update([expt.name for expt in expt_group.get_experiments()])
181
+ opp_expts0 = opp_expts
182
+
183
+ # -> Get all experiments' id associated with an opportunity
184
+ opp_expts = DR.find_experiments_per_opportunity(opp)
185
+ opp_expts = set([expt.name for expt in opp_expts])
186
+
187
+ if check:
188
+ assert opp_expts == opp_expts0
189
+ del opp_expts0
190
+
191
+ if check:
192
+ # -> Get all variables' id associated with an opportunity
193
+ opp_vars = DR.find_variables_per_opportunity(opp)
194
+ opp_vars0 = set([get_unique_var_name(var) for var in opp_vars])
195
+
196
+ # Loop over variable groups to get opportunity's variables separated by priority level
197
+ opp_vars = {p : set() for p in priority_levels}
198
+ for vg in opp.variables_groups:
199
+
200
+ assert isinstance(vg.priority, list) and len(vg.priority) == 1
201
+ priority_info = lookup['priority_level'][vg.priority[0]]
202
+ priority_level = priority_info['name'] # e.g. "Core", "High", ...
203
+
204
+ for var in vg.variables:
205
+ var_name = get_unique_var_name(var)
206
+ # Add this variable to the list of requested variables at the specified priority
207
+ opp_vars[priority_level].add(var_name)
208
+
209
+ if check:
210
+ opp_vars1 = set()
211
+ for priority_level in opp_vars:
212
+ opp_vars1.update(opp_vars[priority_level])
213
+ assert opp_vars1 == opp_vars0 # confirm that DR.find_variables_per_opportunity(opp) lumps all priority levels together
214
+ del opp_vars0, opp_vars1
215
+
216
+ # Aggregate this Opportunity's request into the master list of requests
217
+ for expt_name in opp_expts:
218
+ if expt_name not in request:
219
+ # If we haven't encountered this experiment yet, initialize an expt_request object for it
220
+ request[expt_name] = {p : set() for p in priority_levels}
221
+
222
+ # Add this Opportunity's variables request to the expt_request object
223
+ for priority_level, var_names in opp_vars.items():
224
+ request[expt_name][priority_level].update(opp_vars[priority_level])
225
+
226
+
227
+ # Remove any overlaps in variable lists between different priority levels
228
+ priority_hierarchy = ['Core', 'High', 'Medium', 'Low'] # ordered from highest to lowest priority
229
+ assert set(priority_hierarchy) == set(priority_levels)
230
+ assert len(set(priority_hierarchy)) == len(priority_hierarchy)
231
+ for expt_request in request.values():
232
+ for k,p in enumerate(priority_hierarchy):
233
+ for p_higher in priority_hierarchy[:k]:
234
+ expt_request[p] = expt_request[p].difference(expt_request[p_higher])
235
+ # print(p,p_higher)
236
+ # print()
237
+
238
+ # convert sets to lists for json output
239
+ for p in expt_request:
240
+ expt_request[p] = sorted(expt_request[p], key=str.lower)
241
+
242
+ expt_vars = {
243
+ 'Header' : {
244
+ 'Opportunities' : use_opps,
245
+ 'dreq version' : use_dreq_version,
246
+ },
247
+ 'experiment' : request,
248
+ }
249
+
250
+
251
+ if len(expt_vars['experiment']) > 0:
252
+
253
+ # Show user what was found
254
+ print(f'\nFor data request version {use_dreq_version}, number of requested variables found by experiment:')
255
+ priority_levels = ['Core', 'High', 'Medium', 'Low']
256
+ for expt, req in sorted(expt_vars['experiment'].items()):
257
+ d = {p : 0 for p in priority_levels}
258
+ for p in priority_levels:
259
+ if p in req:
260
+ d[p] = len(req[p])
261
+ n_total = sum(d.values())
262
+ print(f' {expt} : ' + ' ,'.join(['{p}={n}'.format(p=p,n=d[p]) for p in priority_levels]) + f', TOTAL={n_total}')
263
+
264
+ # Write the results to json
265
+ filename = 'requested2.json'
266
+ with open(filename, 'w') as f:
267
+ json.dump(expt_vars, f, indent=4, sort_keys=True)
268
+ print('\nWrote requested variables to ' + filename)
269
+
270
+ else:
271
+ print(f'\nFor data request version {use_dreq_version}, no requested variables were found')
272
+
273
+
274
+
275
+
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env python
2
+ '''
3
+ Example script for basic use of CMIP7 data request content
4
+
5
+ Getting started
6
+ ---------------
7
+ First create an environment with the required dependencies:
8
+
9
+ conda env create -n my_dreq_env --file env.yml
10
+
11
+ (replacing my_dreq_env with your preferred env name). Then activate it and run the script:
12
+
13
+ conda activate my_dreq_env
14
+ python workflow_example.py
15
+
16
+ will load the data request content and save a json file of requested variables in the current dir.
17
+ To run interactively in ipython:
18
+
19
+ run -i workflow_example.py
20
+
21
+ '''
22
+ # try: tables
23
+ # except: tables = {}
24
+
25
+ # use_export = 'release'
26
+ # use_export = 'raw'
27
+
28
+ # if True:
29
+ if False:
30
+
31
+ for use_export in tables:
32
+
33
+ print(f'\n*** {use_export} ***')
34
+
35
+ VarGroups = tables[use_export]['VarGroups']
36
+ Opps = tables[use_export]['Opps']
37
+
38
+ titles = []
39
+ titles.append('Temperature variability')
40
+ titles.append('Ocean Extremes')
41
+
42
+ for title in titles:
43
+ print()
44
+ opp = Opps.get_attr_record('title', title)
45
+ print(opp.title)
46
+ for link in opp.variable_groups:
47
+ vg = VarGroups.get_record(link)
48
+ print(vg.name)
49
+
50
+ stop
51
+
52
+ import json
53
+ from data_request_api.stable.content.dreq_api import dreq_content as dc
54
+ from data_request_api.stable.query import dreq_query as dq
55
+
56
+ from importlib import reload
57
+ reload(dq)
58
+
59
+
60
+ test = True
61
+
62
+
63
+ # Specify opportunities that modelling group chooses to support
64
+ # This can be a subset:
65
+ use_opps = []
66
+ use_opps.append('Baseline Climate Variables for Earth System Modelling')
67
+ # use_opps.append('Synoptic systems and impacts')
68
+ # use_opps.append('Climate impact assessments on freshwater ecosystems')
69
+ use_opps.append('Ocean Extremes')
70
+
71
+ # Or to use all opportunities in the data request:
72
+ use_opps = 'all'
73
+
74
+
75
+ if test:
76
+
77
+ import os
78
+
79
+ use_dreq_version = 'v1.0beta'
80
+
81
+ use_export = 'release'
82
+ use_export = 'raw'
83
+
84
+ use_consolidated = not True
85
+
86
+ load_manually = not True
87
+
88
+ if load_manually:
89
+ # just for testing
90
+ path = '/home/rja001/code/dreq/CMIP7_DReq_Content/airtable_export'
91
+ filepath = os.path.join(path, 'dreq_working.json')
92
+ with open(filepath, 'r') as f:
93
+ content = json.load(f)
94
+ print('loaded ' + filepath)
95
+
96
+ use_consolidated = False
97
+
98
+ else:
99
+ # Download specified version of data request content (if not locally cached)
100
+ dc.retrieve(use_dreq_version, export=use_export)
101
+ # Load content into python dict
102
+ content = dc.load(use_dreq_version, export=use_export, consolidate=use_consolidated)
103
+
104
+
105
+
106
+
107
+ else:
108
+
109
+ use_dreq_version = 'v1.0beta'
110
+
111
+ # Download specified version of data request content (if not locally cached)
112
+ dc.retrieve(use_dreq_version)
113
+ # Load content into python dict
114
+ content = dc.load(use_dreq_version)
115
+
116
+
117
+ # Get consolidated list of requested variables that supports these opportunities
118
+ dq.DREQ_VERSION = use_dreq_version
119
+
120
+ if test:
121
+
122
+ use_old_get = False
123
+
124
+ if use_old_get:
125
+
126
+ if len(content.keys()) == 1:
127
+ k = 'Data Request'
128
+ if k in content:
129
+ content[f'{k} {use_dreq_version}'] = content[k]
130
+ content.pop(k)
131
+ expt_vars = dq._get_requested_variables(content, use_opps, priority_cutoff='Low')
132
+
133
+ else:
134
+
135
+ expt_vars = dq.get_requested_variables(content, use_opps, priority_cutoff='Low', verbose=False, consolidated=use_consolidated)
136
+
137
+
138
+
139
+
140
+ if False:
141
+ # return Opps, VarGroups, PriorityLevel, ExptGroups, Expts
142
+
143
+ Opps, VarGroups, PriorityLevel, ExptGroups, Expts = expt_vars
144
+ del expt_vars
145
+
146
+ tables[use_export] = {
147
+ 'Opps' : Opps, 'VarGroups' : VarGroups,
148
+ }
149
+
150
+ opps = []
151
+ opps.append( Opps.get_attr_record('title', 'Temperature variability') )
152
+
153
+ # opps.append( Opps.get_attr_record('title', 'Ocean Extremes') )
154
+
155
+ for title in [
156
+ "Ocean Extremes",
157
+ "Ocean changes, drivers and impacts",
158
+ "Rapid Evaluation Framework",
159
+ "Paleoclimate research at the interface between past, present, and future",
160
+ "Robust Risk Assessment of Tipping Points",
161
+ ]:
162
+ opps.append( Opps.get_attr_record('title', title) )
163
+
164
+ # achtung!
165
+ # "Ocean Extremes",
166
+ # "Ocean changes, drivers and impacts",
167
+ # "Rapid Evaluation Framework",
168
+ # "Paleoclimate research at the interface between past, present, and future",
169
+ # "Robust Risk Assessment of Tipping Points",
170
+
171
+ # opp = opps[0]
172
+ # opp_expts0 = dq.get_opp_expts(opp, ExptGroups, Expts, verbose=False)
173
+
174
+ for opp in opps:
175
+ print('\n' + opp.title)
176
+ # opp_expts = dq.get_opp_expts(opp, ExptGroups, Expts, verbose=False)
177
+ # print(opp_expts.difference(opp_expts0))
178
+ for link in opp.variable_groups:
179
+ vg = VarGroups.get_record(link)
180
+ if isinstance(vg.priority_level, str):
181
+ assert PriorityLevel is None
182
+ print(vg.priority_level)
183
+ else:
184
+ link = vg.priority_level[0]
185
+ pl = PriorityLevel.get_record(link)
186
+ print(' ' + pl.name)
187
+ stop
188
+
189
+
190
+ else:
191
+
192
+ expt_vars = dq.get_requested_variables(content, use_opps, priority_cutoff='Low')
193
+
194
+
195
+ if len(expt_vars['experiment']) > 0:
196
+
197
+ # Show user what was found
198
+ print(f'\nFor data request version {use_dreq_version}, number of requested variables found by experiment:')
199
+ priority_levels = ['Core', 'High', 'Medium', 'Low']
200
+ for expt, req in expt_vars['experiment'].items():
201
+ d = {p : 0 for p in priority_levels}
202
+ for p in priority_levels:
203
+ if p in req:
204
+ d[p] = len(req[p])
205
+ n_total = sum(d.values())
206
+ print(f' {expt} : ' + ' ,'.join(['{p}={n}'.format(p=p,n=d[p]) for p in priority_levels]) + f', TOTAL={n_total}')
207
+
208
+ # Write the results to json
209
+ # filename = 'requested.json'
210
+ filename = f'requested_{use_export}.json'
211
+
212
+ with open(filename, 'w') as f:
213
+ json.dump(expt_vars, f, indent=4, sort_keys=True)
214
+ print('\nWrote requested variables to ' + filename)
215
+
216
+ else:
217
+ print(f'\nFor data request version {use_dreq_version}, no requested variables were found')
218
+
219
+ # To remove locally cached version:
220
+ # dc.delete(use_dreq_version)
221
+ # To remove all locally cached versions:
222
+ # dc.delete()
@@ -0,0 +1,68 @@
1
+ '''
2
+ https://gist.github.com/matthew-mizielinski/643ca1841dc760edf230473a8b81d396
3
+ '''
4
+
5
+ import copy
6
+ import json
7
+ import hashlib
8
+
9
+
10
+ def set_checksum(dictionary, overwrite=True):
11
+ """
12
+ Calculate the checksum for the ``dictionary``, then add the
13
+ value to ``dictionary`` under the ``checksum`` key. ``dictionary``
14
+ is modified in place.
15
+
16
+ Parameters
17
+ ----------
18
+ dictionary: dict
19
+ The dictionary to set the checksum to.
20
+ overwrite: bool
21
+ Overwrite the existing checksum (default True).
22
+
23
+ Raises
24
+ ------
25
+ RuntimeError
26
+ If the ``checksum`` key already exists and ``overwrite`` is
27
+ False.
28
+ """
29
+ if 'checksum' in dictionary:
30
+ if not overwrite:
31
+ raise RuntimeError('Checksum already exists.')
32
+ del dictionary['checksum']
33
+ checksum = _checksum(dictionary)
34
+ dictionary['checksum'] = checksum
35
+
36
+
37
+ def validate_checksum(dictionary):
38
+ """
39
+ Validate the checksum in the ``dictionary``.
40
+
41
+ Parameters
42
+ ----------
43
+ dictionary: dict
44
+ The dictionary containing the ``checksum`` to validate.
45
+
46
+ Raises
47
+ ------
48
+ KeyError
49
+ If the ``checksum`` key does not exist.
50
+ RuntimeError
51
+ If the ``checksum`` value is invalid.
52
+ """
53
+ if 'checksum' not in dictionary:
54
+ raise KeyError('No checksum to validate')
55
+ dictionary_copy = copy.deepcopy(dictionary)
56
+ del dictionary_copy['checksum']
57
+ checksum = _checksum(dictionary_copy)
58
+ if dictionary['checksum'] != checksum:
59
+ msg = ('Expected checksum "{}"\n'
60
+ 'Calculated checksum "{}"').format(dictionary['checksum'],
61
+ checksum)
62
+ raise RuntimeError(msg)
63
+
64
+
65
+ def _checksum(obj):
66
+ obj_str = json.dumps(obj, sort_keys=True)
67
+ checksum_hex = hashlib.md5(obj_str.encode('utf8')).hexdigest()
68
+ return 'md5: {}'.format(checksum_hex)