oceanval 0.1.0__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 (45) hide show
  1. oceanval/__init__.py +1033 -0
  2. oceanval/chunkers.py +70 -0
  3. oceanval/data/.trackers/nctoolkit_rwi_eseqyqyonctoolkit +0 -0
  4. oceanval/data/001_methods.ipynb +117 -0
  5. oceanval/data/TM_WORLD_BORDERS-0.3.dbf +0 -0
  6. oceanval/data/TM_WORLD_BORDERS-0.3.prj +1 -0
  7. oceanval/data/TM_WORLD_BORDERS-0.3.shp +0 -0
  8. oceanval/data/TM_WORLD_BORDERS-0.3.shx +0 -0
  9. oceanval/data/_config.yml +14 -0
  10. oceanval/data/_toc.yml +4 -0
  11. oceanval/data/chunk_bias.py +62 -0
  12. oceanval/data/chunk_clim.py +164 -0
  13. oceanval/data/chunk_empty.py +1 -0
  14. oceanval/data/chunk_end.py +11 -0
  15. oceanval/data/chunk_globals.py +4 -0
  16. oceanval/data/chunk_point.py +897 -0
  17. oceanval/data/chunk_results.py +38 -0
  18. oceanval/data/chunk_seasonal.py +723 -0
  19. oceanval/data/chunk_start.py +73 -0
  20. oceanval/data/comparison_bias.ipynb +537 -0
  21. oceanval/data/comparison_point.ipynb +236 -0
  22. oceanval/data/comparison_regional.ipynb +362 -0
  23. oceanval/data/comparison_seasonal.ipynb +341 -0
  24. oceanval/data/comparison_spatial.ipynb +271 -0
  25. oceanval/data/global_subdomains.nc +0 -0
  26. oceanval/data/gridded_template.ipynb +1389 -0
  27. oceanval/data/intro.md +9 -0
  28. oceanval/data/intro_compare_simulations.md +10 -0
  29. oceanval/data/nwes_subdomains.nc +0 -0
  30. oceanval/data/pml_logo.jpg +0 -0
  31. oceanval/data/point_template.ipynb +443 -0
  32. oceanval/data/requirements.txt +1 -0
  33. oceanval/data/summary.ipynb +909 -0
  34. oceanval/fixers.py +66 -0
  35. oceanval/fvcom.py +264 -0
  36. oceanval/gridded.py +726 -0
  37. oceanval/matchall.py +1683 -0
  38. oceanval/parsers.py +878 -0
  39. oceanval/session.py +7 -0
  40. oceanval/tidiers.py +207 -0
  41. oceanval/utils.py +138 -0
  42. oceanval-0.1.0.dist-info/METADATA +72 -0
  43. oceanval-0.1.0.dist-info/RECORD +45 -0
  44. oceanval-0.1.0.dist-info/WHEEL +5 -0
  45. oceanval-0.1.0.dist-info/top_level.txt +1 -0
oceanval/__init__.py ADDED
@@ -0,0 +1,1033 @@
1
+ import pandas as pd
2
+ import shutil
3
+ import glob
4
+ import subprocess
5
+ import warnings
6
+ import nctoolkit as nc
7
+ nc.session_info["stamp"] = nc.session_info["stamp"] + "_ecoval_output_"
8
+ import copy
9
+ from oceanval.matchall import matchup
10
+ import dill
11
+ #from oceanval.fixers import tidy_name
12
+ from oceanval.session import session_info
13
+ import webbrowser
14
+ from oceanval.chunkers import add_chunks
15
+ import os
16
+ import re
17
+ from oceanval.fvcom import fvcom_preprocess
18
+ import importlib
19
+
20
+ from oceanval.parsers import Validator, definitions
21
+
22
+ def reset():
23
+ # add docstring
24
+ """
25
+ Reset the matchup definitions to their default state.
26
+ This function resets the matchup definitions used in oceanval to their default state.
27
+ """
28
+ definitions.reset()
29
+
30
+
31
+ notebook_dict = dict()
32
+
33
+
34
+ add_point_comparison = definitions.add_point_comparison
35
+ add_gridded_comparison = definitions.add_gridded_comparison
36
+ # add_gridded_comparison_2 = definitions.add_gridded_comparison_2
37
+
38
+ # loop through the keys and make sure all attributes are set
39
+ #for key in definitions.keys:
40
+ for key in session_info["keys"]:
41
+ try:
42
+ x = definitions[key].gridded
43
+ except AttributeError:
44
+ raise AttributeError(f"Variable '{key}' is missing 'gridded' attribute")
45
+ try:
46
+ x = definitions[key].point
47
+ except AttributeError:
48
+ raise AttributeError(f"Variable '{key}' is missing 'point' attribute")
49
+ try:
50
+ x = definitions[key].sources
51
+ except AttributeError:
52
+ raise AttributeError(f"Variable '{key}' is missing 'source' attribute")
53
+ try:
54
+ x = definitions[key].short_name
55
+ except AttributeError:
56
+ raise AttributeError(f"Variable '{key}' is missing 'short_name' attribute")
57
+ try:
58
+ x = definitions[key].long_name
59
+ except AttributeError:
60
+ raise AttributeError(f"Variable '{key}' is missing 'long_name' attribute")
61
+ # add a test to make sure definitions is complete
62
+
63
+
64
+ def fix_toc(concise = True, data_dir = None, out_dir = None):
65
+ short_titles = dill.load(open(f"{data_dir}/oceanval_matchups/short_titles.pkl", "rb"))
66
+ paths = glob.glob(f"{out_dir}/oceanval_report/notebooks/*.ipynb")
67
+ variables = dill.load(open(f"{data_dir}/oceanval_matchups/variables_matched.pkl", "rb"))
68
+ variables.sort()
69
+
70
+ vv_dict = dict()
71
+ for vv in variables:
72
+ vv_paths = [os.path.basename(x) for x in paths if f"_{vv}.ip" in x]
73
+ if len(vv_paths) > 0:
74
+ vv_dict[vv] = vv_paths
75
+ # get summary docs
76
+ ss_paths = [os.path.basename(x) for x in paths if "summary" in x]
77
+
78
+ out = f"{out_dir}/oceanval_report/_toc.yml"
79
+
80
+ # write line by line to out
81
+ i_chapter = 1
82
+ with open(out, "w") as f:
83
+ # "format: jb-book"
84
+ x = f.write("format: jb-book\n")
85
+ x = f.write("root: intro\n")
86
+ x = f.write("parts:\n")
87
+ x = f.write(f"- caption: Introduction\n")
88
+ x = f.write(" chapters:\n")
89
+ x = f.write(f" - file: notebooks/001_methods.ipynb\n")
90
+
91
+ # open notebook and replace book_chapter with i_chapter
92
+
93
+ # open notebook and replace book_chapter with i_chapter
94
+ with open(f"{out_dir}/oceanval_report/notebooks/001_methods.ipynb", "r") as file:
95
+ filedata = file.read()
96
+
97
+ # Replace the target string
98
+ filedata = filedata.replace("book_chapter", str(i_chapter))
99
+
100
+ with open(f"{out_dir}/oceanval_report/notebooks/001_methods.ipynb", "w") as file:
101
+ file.write(filedata)
102
+ i_chapter += 1
103
+
104
+ x = f.write(f"- caption: Summaries\n")
105
+ x = f.write(" chapters:\n")
106
+ for ff in ss_paths:
107
+ x = f.write(f" - file: notebooks/{ff}\n")
108
+ # open notebook and replace book_chapter with i_chapter
109
+ with open(f"{out_dir}/oceanval_report/notebooks/{ff}", "r") as file:
110
+ filedata = file.read()
111
+
112
+ filedata = filedata.replace("book_chapter", str(i_chapter))
113
+
114
+ # Replace the target string
115
+ # Write the file out again
116
+ with open(f"{out_dir}/oceanval_report/notebooks/{ff}", "w") as file:
117
+ file.write(filedata)
118
+ i_chapter += 1
119
+
120
+ # loop over variables in each vv_dict
121
+ # value is the file in the chapter section
122
+ # key is the variable name, so is the section
123
+ for vv in vv_dict.keys():
124
+ # capitalize if not ph
125
+ vv_out = short_titles[vv]
126
+
127
+ x = f.write(f"- caption: {vv_out}\n")
128
+ x = f.write(" chapters:\n")
129
+ for ff in vv_dict[vv]:
130
+ x = f.write(f" - file: notebooks/{ff}\n")
131
+
132
+ # open notebook and replace book_chapter with i_chapter
133
+ with open(f"{out_dir}/oceanval_report/notebooks/{ff}", "r") as file:
134
+ filedata = file.read()
135
+
136
+ # Replace the target string
137
+ filedata = filedata.replace("book_chapter", str(i_chapter))
138
+
139
+ # Write the file out again
140
+
141
+ with open(f"{out_dir}/oceanval_report/notebooks/{ff}", "w") as file:
142
+ file.write(filedata)
143
+ i_chapter += 1
144
+
145
+
146
+
147
+ def fix_toc_comparison():
148
+ book_dir = "oceanval_comparison"
149
+
150
+ out = f"{book_dir}/compare/_toc.yml"
151
+ # write line by line to out
152
+ with open(out, "w") as f:
153
+ # "format: jb-book"
154
+ x = f.write("format: jb-book\n")
155
+ x = f.write("root: intro\n")
156
+ x = f.write("parts:\n")
157
+ x = f.write(f"- caption: Comparisons with gridded surface observations\n")
158
+ x = f.write(" chapters:\n")
159
+ x = f.write(f" - file: notebooks/comparison_bias.ipynb\n")
160
+ x = f.write(f" - file: notebooks/comparison_spatial.ipynb\n")
161
+ x = f.write(f" - file: notebooks/comparison_seasonal.ipynb\n")
162
+ x = f.write(f" - file: notebooks/comparison_regional.ipynb\n")
163
+ x = f.write(f"- caption: Comparisons with point observations\n")
164
+ x = f.write(" chapters:\n")
165
+ x = f.write(f" - file: notebooks/comparison_point_surface.ipynb\n")
166
+
167
+
168
+
169
+
170
+ def validate(
171
+ lon_lim=None,
172
+ lat_lim=None,
173
+ concise = True,
174
+ variables="all",
175
+ fixed_scale = False,
176
+ region = None,
177
+ data_dir = ".",
178
+ out_dir = ".",
179
+ test=False,
180
+ ):
181
+ # docstring
182
+ """
183
+ Run the model evaluation for all of the available datasets, and generate a validation report.
184
+
185
+ Parameters
186
+ ----------
187
+ lon_lim : list or None
188
+ The longitude limits for the validation. Default is None
189
+ lat_lim : list or None
190
+ The latitude limits for the validation. Default is None
191
+ variables : str or list
192
+ The variables to run the model evaluation for. Default is "all"
193
+ fixed_scale : bool
194
+ Whether to use a fixed scale for the seasonal plots. Default is False. If True, the minimum and maximum values are capped to cover the 2nd and 98th percentiles of both model and observations.
195
+ region : str or None
196
+ The region being validated. Must be either "nwes" (northwest European Shelf) or "global". Default is None.
197
+ test : bool
198
+ Default is False. Ignore, unless you are testing oceanval.
199
+
200
+ Returns
201
+ -------
202
+ None
203
+ """
204
+ # convert data_dir to absolute path
205
+ data_dir = os.path.expanduser(data_dir)
206
+ data_dir = os.path.abspath(data_dir)
207
+ # regioncan only be nwes or global
208
+ if region is not None:
209
+ if region not in ["nwes", "global"]:
210
+ raise ValueError("region must be either 'nwes' or 'global'")
211
+ # ensure proper handling of ~
212
+ out_dir = os.path.expanduser(out_dir)
213
+ out_dir = os.path.abspath(out_dir)
214
+
215
+ book_dir = os.path.join(out_dir, "oceanval_report")
216
+ # if it doesn't exist, create it
217
+ if not os.path.exists(out_dir):
218
+ os.makedirs(out_dir)
219
+ # if lon_lim is not None, make sure it's a list
220
+ if lon_lim is not None:
221
+ if isinstance(lon_lim, list) == False:
222
+ raise ValueError("lon_lim must be a list")
223
+ else:
224
+ if len(lon_lim) != 2:
225
+ raise ValueError("lon_lim must be a list of length 2")
226
+ if lat_lim is not None:
227
+ if isinstance(lat_lim, list) == False:
228
+ raise ValueError("lat_lim must be a list")
229
+ else:
230
+ if len(lat_lim) != 2:
231
+ raise ValueError("lat_lim must be a list of length 2")
232
+
233
+
234
+ path_df = []
235
+
236
+ fast_plot = False
237
+
238
+
239
+ empty = True
240
+
241
+ # book directory is book, book1, book2, book10 etc.
242
+
243
+ # create a new name if one already exists
244
+ i = 0
245
+
246
+ if os.path.exists(book_dir):
247
+ # get user input to decide if it should be removed
248
+ while True:
249
+ files = glob.glob(f"{book_dir}/**/**/**", recursive=True)
250
+ # list all files in book, recursively
251
+ for ff in files:
252
+ if ff.startswith(f"{book_dir}/"):
253
+ try:
254
+ os.remove(ff)
255
+ except:
256
+ pass
257
+ files = glob.glob(f"{book_dir}/**/**/**", recursive=True)
258
+ # only list files
259
+ files = [x for x in files if os.path.isfile(x)]
260
+ if len(files) == 0:
261
+ break
262
+
263
+ # remove the results directory
264
+ x_path = "oceanval_results"
265
+ if os.path.exists(x_path):
266
+ if x_path == "oceanval_results":
267
+ shutil.rmtree(x_path)
268
+
269
+ if variables != "all":
270
+ if isinstance(variables, str):
271
+ variables = [variables]
272
+
273
+ if empty:
274
+ from shutil import copyfile
275
+
276
+ if not os.path.exists(book_dir):
277
+ os.mkdir(book_dir)
278
+ if not os.path.exists(f"{book_dir}/notebooks"):
279
+ os.mkdir(f"{book_dir}/notebooks")
280
+
281
+ data_path = importlib.resources.files(__name__).joinpath("data/001_methods.ipynb")
282
+ if not os.path.exists(f"{book_dir}/notebooks/001_methods.ipynb"):
283
+ copyfile(data_path, f"{book_dir}/notebooks/001_methods.ipynb")
284
+ # open this file and replace model_name with model
285
+
286
+
287
+ data_path = importlib.resources.files(__name__).joinpath("data/_toc.yml")
288
+
289
+ out = f"{book_dir}/" + os.path.basename(data_path)
290
+ copyfile(data_path, out)
291
+
292
+ data_path = importlib.resources.files(__name__).joinpath("data/requirements.txt")
293
+ out = f"{book_dir}/" + os.path.basename(data_path)
294
+ copyfile(data_path, out)
295
+
296
+ data_path = importlib.resources.files(__name__).joinpath("data/intro.md")
297
+ out = f"{book_dir}/" + os.path.basename(data_path)
298
+ copyfile(data_path, out)
299
+
300
+ # copy config
301
+
302
+ data_path = importlib.resources.files(__name__).joinpath("data/_config.yml")
303
+ out = f"{book_dir}/" + os.path.basename(data_path)
304
+
305
+ with open(data_path, "r") as file:
306
+ filedata = file.read()
307
+
308
+
309
+ # Write the file out again
310
+ with open(out, "w") as file:
311
+ file.write(filedata)
312
+
313
+ # copyfile(data_path, out)
314
+
315
+ path_df = []
316
+
317
+ # loop through the point matchups and generate notebooks
318
+
319
+ point_paths = glob.glob(f"{data_dir}/oceanval_matchups/point/**/**/**/**.csv")
320
+ point_paths = [x for x in point_paths if "unit" not in os.path.basename(x)]
321
+ # loop through the paths
322
+ for pp in point_paths:
323
+ ff_def = pp.replace(".csv", "_definitions.pkl")
324
+ definitions = dill.load(open(ff_def, "rb"))
325
+ vv = os.path.basename(pp).split("_")[2].replace(".csv", "")
326
+ if variables != "all":
327
+ if True:
328
+ if vv not in variables:
329
+ continue
330
+ source = os.path.basename(pp).split("_")[0]
331
+ variable = vv
332
+ layer = os.path.basename(pp).split("_")[1].replace(".csv", "")
333
+ Variable = definitions[variable].short_name
334
+
335
+ vv_file = pp
336
+ vv_file_find = pp.replace("../../", "")
337
+
338
+ if os.path.exists(vv_file_find):
339
+ if (
340
+ len(
341
+ glob.glob(
342
+ f"{book_dir}/notebooks/*point_{layer}_{variable}.ipynb"
343
+ )
344
+ )
345
+ == 0
346
+ ):
347
+ file1 = importlib.resources.files(__name__).joinpath("data/point_template.ipynb")
348
+ with open(file1, "r") as file:
349
+ filedata = file.read()
350
+
351
+ if layer in [ "all", "surface"]:
352
+ filedata = filedata.replace(
353
+ "chunk_point_surface", "chunk_point"
354
+ )
355
+ else:
356
+ filedata = filedata.replace("chunk_point_surface", "")
357
+ if layer in ["bottom", "all"]:
358
+ if vv.lower() not in ["pco2"]:
359
+ filedata = filedata.replace(
360
+ "chunk_point_bottom", "chunk_point"
361
+ )
362
+ else:
363
+ filedata = filedata.replace("chunk_point_bottom", "")
364
+ else:
365
+ filedata = filedata.replace("chunk_point_bottom", "")
366
+
367
+ # Replace the target string
368
+ out = f"{book_dir}/notebooks/{source}_{layer}_{variable}.ipynb"
369
+ filedata = filedata.replace("point_variable", variable)
370
+ n_levels = definitions[variable].n_levels
371
+ if layer != "all":
372
+ if n_levels > 1:
373
+ filedata = filedata.replace(
374
+ "Validation of point_layer", f"Validation of {layer}"
375
+ )
376
+ else:
377
+ filedata = filedata.replace(
378
+ "Validation of point_layer", f"Validation of "
379
+ )
380
+ else:
381
+ filedata = filedata.replace(
382
+ "Validation of point_layer", f"Validation of "
383
+ )
384
+
385
+ filedata = filedata.replace("point_layer", layer)
386
+ filedata = filedata.replace("point_obs_source", source)
387
+ filedata = filedata.replace("template_title", Variable)
388
+ filedata = filedata.replace("data_dir_value", data_dir)
389
+ filedata = filedata.replace("out_dir_value", out_dir)
390
+
391
+ # Write the file out again
392
+ with open(out, "w") as file:
393
+ file.write(filedata)
394
+
395
+ path_df.append(
396
+ pd.DataFrame(
397
+ {
398
+ "variable": [variable],
399
+ "path": out,
400
+ }
401
+ )
402
+ )
403
+
404
+ # Loop through the gridded matchups and generate notebooks
405
+ # identify gridded variables in matched data
406
+ gridded_paths = glob.glob(f"{data_dir}/oceanval_matchups/gridded/**/**.nc")
407
+
408
+ if len(gridded_paths) > 0:
409
+ for vv in [
410
+ os.path.basename(x).split("_")[1].replace(".nc", "")
411
+ for x in gridded_paths
412
+ ]:
413
+ for source in [
414
+ os.path.basename(x).split("_")[0]
415
+ for x in glob.glob(f"{data_dir}/oceanval_matchups/gridded/**/**_{vv}_**.nc")
416
+ ]:
417
+
418
+ variable = vv
419
+ if variables != "all":
420
+ if vv not in variables:
421
+ continue
422
+ if not os.path.exists(
423
+ f"{book_dir}/notebooks/{source}_{variable}.ipynb"
424
+ ):
425
+ ff_def = glob.glob(f"{data_dir}/oceanval_matchups/gridded/{variable}/{source}_*definitions*.pkl")[0]
426
+ definitions = dill.load(open(ff_def, "rb"))
427
+ Variable = definitions[variable].short_name
428
+ ff_nc = glob.glob(f"{data_dir}/oceanval_matchups/gridded/{variable}/{source}_*surface*.nc")[0]
429
+ ds = nc.open_data(ff_nc, checks = False)
430
+ try:
431
+ n_months = len(ds.months)
432
+ except:
433
+ n_months = 12
434
+ seasonal = n_months >= 12
435
+
436
+ file1 = importlib.resources.files(__name__).joinpath("data/gridded_template.ipynb")
437
+ if (
438
+ len(
439
+ glob.glob(
440
+ f"{book_dir}/notebooks/*{source}_{variable}.ipynb"
441
+ )
442
+ )
443
+ == 0
444
+ ):
445
+ with open(file1, "r") as file:
446
+ filedata = file.read()
447
+
448
+ # Replace the target string
449
+ filedata = filedata.replace("template_variable", variable)
450
+ filedata = filedata.replace("template_title", Variable)
451
+ filedata = filedata.replace("data_dir_value", data_dir)
452
+ filedata = filedata.replace("source_name", source)
453
+ if region == "nwes":
454
+ filedata = filedata.replace("zonal_height", "6000" )
455
+ else:
456
+ filedata = filedata.replace("zonal_height", "2000" )
457
+ # make every letter a capital
458
+ source_capital = source.upper()
459
+ filedata = filedata.replace("source_title", source_capital)
460
+ if seasonal is False:
461
+ filedata = filedata.replace(
462
+ "chunk_seasonal", ""
463
+ )
464
+ # change sub_regions_value to region
465
+ if region is not None:
466
+ filedata = filedata.replace(
467
+ "sub_regions_value", str(region)
468
+ )
469
+
470
+ # Write the file out again
471
+ with open(
472
+ f"{book_dir}/notebooks/{source}_{variable}.ipynb", "w"
473
+ ) as file:
474
+ file.write(filedata)
475
+
476
+ variable = vv
477
+ path_df.append(
478
+ pd.DataFrame(
479
+ {
480
+ "variable": [variable],
481
+ "path": [
482
+ f"{book_dir}/notebooks/{source}_{variable}.ipynb"
483
+ ],
484
+ }
485
+ )
486
+ )
487
+
488
+ # need to start by figuring out whether anything has already been run...
489
+
490
+ i = 0
491
+
492
+ for ff in [
493
+ x for x in glob.glob("{book_dir}/notebooks/*.ipynb") if "info" not in x
494
+ ]:
495
+ try:
496
+ i_ff = int(os.path.basename(ff).split("_")[0])
497
+ if i_ff > i:
498
+ i = i_ff
499
+ except:
500
+ pass
501
+
502
+ i_orig = i
503
+
504
+ if len(path_df) > 0:
505
+ path_df = pd.concat(path_df)
506
+ path_df = path_df.sort_values("variable").reset_index(drop=True)
507
+
508
+ for i in range(len(path_df)):
509
+ file1 = path_df.path.values[i]
510
+ # pad i with zeros using zfill
511
+ i_pad = str(i + 1).zfill(3)
512
+ new_file = (
513
+ os.path.dirname(file1) + "/" + i_pad + "_" + os.path.basename(file1)
514
+ )
515
+ os.rename(file1, new_file)
516
+ # print(key, value)
517
+
518
+ # copy the summary.ipynb notebook and add i_pad to the name
519
+
520
+ i = i + 2
521
+ i_pad = str(i).zfill(3)
522
+
523
+
524
+
525
+ file1 = importlib.resources.files(__name__).joinpath("data/summary.ipynb")
526
+ if len(glob.glob(f"{book_dir}/notebooks/*summary.ipynb")) == 0:
527
+ copyfile(file1, f"{book_dir}/notebooks/{i_pad}_summary.ipynb")
528
+ else:
529
+ if i > (i_orig + 1):
530
+ initial = glob.glob(f"{book_dir}/notebooks/*summary.ipynb")[0]
531
+ copyfile(initial, f"{book_dir}/notebooks/{i_pad}_summary.ipynb")
532
+ i += 1
533
+
534
+ # change domain_title to "Full domain"
535
+
536
+ with open(f"{book_dir}/notebooks/{i_pad}_summary.ipynb", "r") as file:
537
+ filedata = file.read()
538
+
539
+ # Replace the target string
540
+ filedata = filedata.replace("domain_title", "Full domain")
541
+ filedata = filedata.replace("data_dir_value", data_dir)
542
+ filedata = filedata.replace("out_dir_value", out_dir)
543
+
544
+ # Write the file out again
545
+ with open(f"{book_dir}/notebooks/{i_pad}_summary.ipynb", "w") as file:
546
+ file.write(filedata)
547
+
548
+ # pair the notebooks using jupyter text
549
+
550
+ os.system(
551
+ f"jupytext --set-formats ipynb,py:percent {book_dir}/notebooks/*.ipynb"
552
+ )
553
+
554
+ # add the chunks
555
+ add_chunks(out_dir)
556
+
557
+ # loop through the notebooks and set r warnings options
558
+ for ff in glob.glob(f"{book_dir}/notebooks/*.py"):
559
+ with open(ff, "r") as file:
560
+ filedata = file.read()
561
+
562
+ # loop through line by line, and rewrite the original file
563
+ lines = filedata.split("\n")
564
+ new_lines = []
565
+ for line in lines:
566
+ if "%%R" in line:
567
+ new_lines.append(line)
568
+ new_lines.append("options(warn=-1)")
569
+ else:
570
+ new_lines.append(line)
571
+ # loop through all lines in lines and replace the_test_status with True
572
+ for i in range(len(new_lines)):
573
+ new_lines[i] = new_lines[i].replace("latexpagebreak", "")
574
+ if "the_test_status" in new_lines[i]:
575
+ if test:
576
+ new_lines[i] = new_lines[i].replace("the_test_status", "True")
577
+ else:
578
+ new_lines[i] = new_lines[i].replace("the_test_status", "False")
579
+ if '"gam"' in new_lines[i]:
580
+ new_lines[i] = new_lines[i].replace('"gam"', '"lm"')
581
+
582
+ new_lines[i] = new_lines[i].replace("the_lon_lim", str(lon_lim))
583
+ new_lines[i] = new_lines[i].replace("the_lat_lim", str(lat_lim))
584
+ new_lines[i] = new_lines[i].replace("fixed_scale_value", str(fixed_scale))
585
+ # replace concice_value with concice
586
+ if "concise_value" in new_lines[i]:
587
+ if concise:
588
+ new_lines[i] = new_lines[i].replace(
589
+ "concise_value", "True"
590
+ )
591
+ else:
592
+ new_lines[i] = new_lines[i].replace("concise_value", "False")
593
+
594
+ # write the new lines to the file
595
+ with open(ff, "w") as file:
596
+ for line in new_lines:
597
+ file.write(line + "\n")
598
+
599
+ # sync the notebooks
600
+ #
601
+ os.system(f"jupytext --sync {book_dir}/notebooks/*.ipynb")
602
+
603
+
604
+ # loop through notebooks and change fast_plot_value to fast_plot
605
+
606
+ for ff in glob.glob(f"{book_dir}/notebooks/*.ipynb"):
607
+ with open(ff, "r") as file:
608
+ filedata = file.read()
609
+
610
+ # Replace the target string
611
+ filedata = filedata.replace("fast_plot_value", str(fast_plot))
612
+ filedata = filedata.replace("data_dir_value", data_dir)
613
+ filedata = filedata.replace("out_dir_value", out_dir)
614
+
615
+ # fix linees using the above
616
+ def fix_r_magic(x):
617
+ if "%%R" in x:
618
+ x = re.sub(r" -r\s+\d+", "", x)
619
+ x = x.replace("%%R", "%%R -r 120 ")
620
+ return x
621
+
622
+ # Write the file out again
623
+ with open(ff, "w") as file:
624
+ file.write(filedata)
625
+
626
+ # fix the toc using the function
627
+
628
+ fix_toc(concise = concise, data_dir = data_dir, out_dir = out_dir)
629
+
630
+ for ff in glob.glob(f"{book_dir}/notebooks/*.ipynb"):
631
+ ff_clean = ff.replace(".ipynb", ".py")
632
+ if os.path.exists(ff_clean):
633
+ os.remove(ff_clean)
634
+
635
+ # move pml_logo to book directory
636
+
637
+ shutil.copyfile(
638
+ importlib.resources.files(__name__).joinpath("data/pml_logo.jpg"), f"{book_dir}/pml_logo.jpg"
639
+ )
640
+
641
+ os.system(f"jupyter-book build {book_dir}/")
642
+
643
+ stamps = [
644
+ os.path.basename(x) for x in glob.glob(f"{book_dir}/notebooks/.trackers/*")
645
+ ]
646
+ stamps.append("nctoolkit_rwi_uhosarcenctoolkittmp")
647
+
648
+ delete = []
649
+ for x in stamps:
650
+ delete += glob.glob("/tmp/*" + x + "*")
651
+
652
+ for ff in delete:
653
+ if os.path.exists(ff):
654
+ if "nctoolkit" in x:
655
+ os.remove(ff)
656
+
657
+ out_ff = f"{book_dir}/_build/html/index.html"
658
+
659
+ # create a symlink to the html file
660
+ if os.path.exists(f"{out_dir}/oceanval_report.html"):
661
+ os.remove(f"{out_dir}/oceanval_report.html")
662
+ os.symlink(f"{book_dir}/_build/html/index.html", f"{out_dir}/oceanval_report.html")
663
+ webbrowser.open(
664
+ "file://" + os.path.abspath(f"{book_dir}/_build/html/index.html")
665
+ )
666
+
667
+
668
+ def rebuild():
669
+ """
670
+ Rebuild the validation report after modifying notebooks.
671
+ Use this if you have modified the notebooks generated and want to create a new validation report.
672
+
673
+ Parameters
674
+ ----------
675
+ build : str
676
+ The type of the existing build. Default is None. Options are "html" or "pdf"
677
+ """
678
+ # add a deprecation notice
679
+
680
+ os.system(f"jupyter-book build oceanval_report/")
681
+
682
+ webbrowser.open(
683
+ "file://" + os.path.abspath(f"oceanval_report/_build/html/index.html")
684
+ )
685
+
686
+
687
+
688
+
689
+ try:
690
+ from importlib.metadata import version as _version
691
+ except ImportError:
692
+ from importlib_metadata import version as _version
693
+
694
+ try:
695
+ __version__ = _version("oceanval")
696
+ except Exception:
697
+ __version__ = "999"
698
+
699
+
700
+ def compare(model_dict=None):
701
+ """
702
+ Compare pre-validated simulations.
703
+ This function will compare the validation output from two simulations.
704
+
705
+ Parameters
706
+ ----------
707
+ model_dict : dict
708
+ A dictionary of model names and the paths to the validation output. Default is None.
709
+ Example: {"model1": "/path/to/model1", "model2": "/path/to/model2"}
710
+ If the models have different grids, put the model with the smallest grid first.
711
+
712
+ """
713
+
714
+ for key in model_dict.keys():
715
+ # check that the path exists
716
+ if not os.path.exists(model_dict[key]):
717
+ raise ValueError(f"Path {model_dict[key]} does not exist")
718
+ # convert to an absolute path
719
+ model_dict[key] = os.path.abspath(model_dict[key])
720
+
721
+ if os.path.exists("oceanval_comparison"):
722
+ # get user input to decide if it should be removed
723
+ user_input = input(
724
+ "oceanval_comparison directory already exists. This will be emptied and replaced. Do you want to proceed? (y/n): "
725
+ )
726
+ if user_input.lower() == "y":
727
+ while True:
728
+ files = glob.glob("oceanval_comparison/**/**/**", recursive=True)
729
+ # list all files in oceanval_comparison, recursively
730
+ for ff in files:
731
+ if ff.startswith("oceanval_comparison"):
732
+ try:
733
+ os.remove(ff)
734
+ except:
735
+ pass
736
+ files = glob.glob("oceanval_comparison/**/**/**", recursive=True)
737
+ # only list files
738
+ files = [x for x in files if os.path.isfile(x)]
739
+ if len(files) == 0:
740
+ break
741
+ else:
742
+ print("Exiting")
743
+ return None
744
+
745
+
746
+ if not os.path.exists("oceanval_comparison/compare"):
747
+ # create directory recursively
748
+ os.makedirs("oceanval_comparison/compare")
749
+
750
+ # copy the pml logo
751
+ shutil.copyfile(
752
+ importlib.resources.files(__name__).joinpath("data/pml_logo.jpg"),
753
+ "oceanval_comparison/pml_logo.jpg",
754
+ )
755
+
756
+ # move toc etc to oceanval_comparison/compare
757
+
758
+ data_path = importlib.resources.files(__name__).joinpath("data/_toc.yml")
759
+
760
+ out = "oceanval_comparison/compare/" + os.path.basename(data_path)
761
+ shutil.copyfile(data_path, out)
762
+
763
+ fix_toc_comparison()
764
+
765
+ data_path = importlib.resources.files(__name__).joinpath("data/requirements.txt")
766
+
767
+ out = "oceanval_comparison/compare/" + os.path.basename(data_path)
768
+
769
+ shutil.copyfile(data_path, out)
770
+
771
+ data_path = importlib.resources.files(__name__).joinpath("data/intro.md")
772
+
773
+ out = "oceanval_comparison/compare/" + os.path.basename(data_path)
774
+
775
+ shutil.copyfile(data_path, out)
776
+
777
+ # copy config
778
+
779
+ data_path = importlib.resources.files(__name__).joinpath("data/_config.yml")
780
+
781
+ out = "oceanval_comparison/compare/" + os.path.basename(data_path)
782
+
783
+ shutil.copyfile(data_path, out)
784
+
785
+ # copy the comparison_seasonal notebook
786
+
787
+ # make sure the directory exists
788
+
789
+ if not os.path.exists("oceanval_comparison/compare/notebooks"):
790
+ # create directory recursively
791
+ os.makedirs("oceanval_comparison/compare/notebooks")
792
+
793
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_seasonal.ipynb")
794
+ if len(glob.glob("oceanval_comparison/compare/notebooks/*comparison_seasonal.ipynb")) == 0:
795
+ shutil.copyfile(file1, "oceanval_comparison/compare/notebooks/comparison_seasonal.ipynb")
796
+
797
+ # copy comparison_overall notebook
798
+
799
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_overall.ipynb")
800
+
801
+ if len(glob.glob("oceanval_comparison/compare/notebooks/*comparison_overall.ipynb")) == 0:
802
+ shutil.copyfile(file1, "oceanval_comparison/compare/notebooks/comparison_overall.ipynb")
803
+
804
+ model_dict_str = str(model_dict)
805
+
806
+ with open("oceanval_comparison/compare/notebooks/comparison_seasonal.ipynb", "r") as file:
807
+ filedata = file.read()
808
+
809
+ # Replace the target string
810
+ filedata = filedata.replace("model_dict_str", model_dict_str)
811
+
812
+ # Write the file out again
813
+
814
+ with open("oceanval_comparison/compare/notebooks/comparison_seasonal.ipynb", "w") as file:
815
+ file.write(filedata)
816
+
817
+ # now sort out the comparison_spatial notebook
818
+
819
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_spatial.ipynb")
820
+ if len(glob.glob("oceanval_comparison/compare/notebooks/*comparison_spatial.ipynb")) == 0:
821
+ shutil.copyfile(file1, "oceanval_comparison/compare/notebooks/comparison_spatial.ipynb")
822
+
823
+ model_dict_str = str(model_dict)
824
+
825
+ with open("oceanval_comparison/compare/notebooks/comparison_spatial.ipynb", "r") as file:
826
+ filedata = file.read()
827
+
828
+ # Replace the target string
829
+ filedata = filedata.replace("model_dict_str", model_dict_str)
830
+
831
+ # Write the file out again
832
+
833
+ with open("oceanval_comparison/compare/notebooks/comparison_spatial.ipynb", "w") as file:
834
+ file.write(filedata)
835
+
836
+ # move the regional book
837
+
838
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_regional.ipynb")
839
+ if len(glob.glob("oceanval_comparison/compare/notebooks/*comparison_regional.ipynb")) == 0:
840
+ shutil.copyfile(file1, "oceanval_comparison/compare/notebooks/comparison_regional.ipynb")
841
+
842
+ model_dict_str = str(model_dict)
843
+
844
+ with open("oceanval_comparison/compare/notebooks/comparison_regional.ipynb", "r") as file:
845
+ filedata = file.read()
846
+
847
+ # Replace the target string
848
+ filedata = filedata.replace("model_dict_str", model_dict_str)
849
+
850
+ # Write the file out again
851
+
852
+ with open("oceanval_comparison/compare/notebooks/comparison_regional.ipynb", "w") as file:
853
+ file.write(filedata)
854
+
855
+ # now to comparison_bias
856
+
857
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_bias.ipynb")
858
+
859
+ if len(glob.glob("oceanval_comparison/compare/notebooks/*comparison_bias.ipynb")) == 0:
860
+ shutil.copyfile(file1, "oceanval_comparison/compare/notebooks/comparison_bias.ipynb")
861
+
862
+ model_dict_str = str(model_dict)
863
+
864
+ with open("oceanval_comparison/compare/notebooks/comparison_bias.ipynb", "r") as file:
865
+ filedata = file.read()
866
+
867
+ # Replace the target string
868
+ filedata = filedata.replace("model_dict_str", model_dict_str)
869
+
870
+ # Write the file out again
871
+
872
+ with open("oceanval_comparison/compare/notebooks/comparison_bias.ipynb", "w") as file:
873
+ file.write(filedata)
874
+
875
+ # figure out if both simulations have point data
876
+
877
+ i = 0
878
+
879
+ if i == 0:
880
+ for ss in [ "surface"]:
881
+ file1 = importlib.resources.files(__name__).joinpath("data/comparison_point.ipynb")
882
+
883
+ if (
884
+ len(glob.glob(f"oceanval_comparison/compare/notebooks/*comparison_point_{ss}.ipynb"))
885
+ == 0
886
+ ):
887
+ shutil.copyfile(
888
+ file1, f"oceanval_comparison/compare/notebooks/comparison_point_{ss}.ipynb"
889
+ )
890
+
891
+ model_dict_str = str(model_dict)
892
+
893
+ with open(
894
+ f"oceanval_comparison/compare/notebooks/comparison_point_{ss}.ipynb", "r"
895
+ ) as file:
896
+ filedata = file.read()
897
+
898
+ # Replace the target string
899
+ filedata = filedata.replace("model_dict_str", model_dict_str)
900
+
901
+ # Write the file out again
902
+
903
+ with open(
904
+ f"oceanval_comparison/compare/notebooks/comparison_point_{ss}.ipynb", "w"
905
+ ) as file:
906
+ file.write(filedata)
907
+ # replace layer in the notebook with ss
908
+ with open(
909
+ f"oceanval_comparison/compare/notebooks/comparison_point_{ss}.ipynb", "r"
910
+ ) as file:
911
+ filedata = file.read()
912
+
913
+ # Replace the target string
914
+ filedata = filedata.replace("layer", ss)
915
+
916
+ # Write the file out again
917
+
918
+ with open(
919
+ f"oceanval_comparison/compare/notebooks/comparison_point_{ss}.ipynb", "w"
920
+ ) as file:
921
+ file.write(filedata)
922
+
923
+
924
+ # sync the notebooks
925
+
926
+ os.system("jupytext --set-formats ipynb,py:percent oceanval_comparison/compare/notebooks/*.ipynb")
927
+
928
+ add_chunks()
929
+
930
+ # replace the test status in the notebooks
931
+ books = glob.glob("oceanval_comparison/compare/notebooks/*.py")
932
+ for book in books:
933
+ with open(book, "r") as file:
934
+ filedata = file.read()
935
+
936
+ # Replace the target string
937
+ filedata = filedata.replace("the_test_status", "False")
938
+
939
+ # Write the file out again
940
+ with open(book, "w") as file:
941
+ file.write(filedata)
942
+
943
+ # fix the chunks
944
+ os.system("jupytext --sync oceanval_comparison/compare/notebooks/*.ipynb")
945
+
946
+ # loop through notebooks and change fast_plot_value to fast_plot
947
+
948
+ for ff in glob.glob("oceanval_comparison/compare/notebooks/*.ipynb"):
949
+ with open(ff, "r") as file:
950
+ filedata = file.read()
951
+
952
+ # Replace the target string
953
+ filedata = filedata.replace("fast_plot_value", "False")
954
+
955
+ # Write the file out again
956
+ with open(ff, "w") as file:
957
+ file.write(filedata)
958
+
959
+ os.system("jupyter-book build oceanval_comparison/compare/")
960
+ import webbrowser
961
+
962
+
963
+ webbrowser.open("file://" + os.path.abspath("oceanval_comparison/compare/_build/html/index.html"))
964
+
965
+ import platform
966
+ import tempfile
967
+
968
+
969
+ def temp_check():
970
+ """
971
+ Function to check temp files
972
+ """
973
+
974
+ if platform.system() == "Linux":
975
+ mylist = [f for f in glob.glob("/tmp/*")]
976
+ mylist = mylist + [f for f in glob.glob("/var/tmp/*")]
977
+ mylist = mylist + [f for f in glob.glob("/usr/tmp/*")]
978
+ mylist = [f for f in mylist if "nctoolkit" in f]
979
+
980
+ mylist = [x for x in mylist if "ecoval_output" in x]
981
+
982
+ session_info["old_files"] = mylist
983
+
984
+ if len(mylist) > 0:
985
+ if len(mylist) == 1:
986
+ print(
987
+ f"{len(mylist)} temporary file was created by oceanval in prior or current "
988
+ f"sessions. Consider running oceanval.deep_clean!"
989
+ )
990
+ else:
991
+ print(
992
+ f"{len(mylist)} temporary files were created by oceanval in prior or current"
993
+ f" sessions. Consider running oceanval.deep_clean!"
994
+ )
995
+
996
+ else:
997
+ temp_folder = tempfile.gettempdir()
998
+
999
+ mylist = [f for f in glob.glob(f"{temp_folder}/*")]
1000
+ mylist = [f for f in mylist if "nctoolkit" in f]
1001
+ mylist = [x for x in mylist if "ecovaloutput" in x]
1002
+
1003
+ if len(mylist) > 0:
1004
+ if len(mylist) == 1:
1005
+ print(
1006
+ f"{len(mylist)} temporary file was created by oceanval in prior or current "
1007
+ f"sessions. Consider running oceanval.deep_clean!"
1008
+ )
1009
+ else:
1010
+ print(
1011
+ f"{len(mylist)} temporary files were created by oceanval in prior or "
1012
+ f"current sessions. Consider running oceanval.deep_clean!"
1013
+ )
1014
+
1015
+ temp_check()
1016
+
1017
+
1018
+
1019
+
1020
+ def deep_clean():
1021
+ """
1022
+ Deep temp file cleaner.
1023
+ Remove all temporary files ever created by oceanval
1024
+ across all previous and current sesions
1025
+ """
1026
+
1027
+ candidates = session_info["old_files"]
1028
+
1029
+ mylist = [f for f in candidates if "nctoolkit" in f and "ecoval_output" in f]
1030
+ for ff in mylist:
1031
+ if ff in session_info["old_files"]:
1032
+ if "nctoolkit" in ff and "ecoval_output" in ff:
1033
+ os.remove(ff)