roms-tools 2.6.2__py3-none-any.whl → 2.7.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 (51) hide show
  1. roms_tools/__init__.py +1 -0
  2. roms_tools/analysis/roms_output.py +11 -77
  3. roms_tools/analysis/utils.py +0 -66
  4. roms_tools/constants.py +2 -0
  5. roms_tools/download.py +46 -3
  6. roms_tools/plot.py +22 -5
  7. roms_tools/setup/cdr_forcing.py +1126 -0
  8. roms_tools/setup/datasets.py +742 -87
  9. roms_tools/setup/grid.py +42 -4
  10. roms_tools/setup/river_forcing.py +11 -84
  11. roms_tools/setup/tides.py +81 -411
  12. roms_tools/setup/utils.py +241 -37
  13. roms_tools/tests/test_setup/test_cdr_forcing.py +772 -0
  14. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +53 -1
  15. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/.zattrs +1 -1
  16. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/.zarray +20 -0
  17. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/.zattrs +6 -0
  18. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/0 +0 -0
  19. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/.zarray +20 -0
  20. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/.zattrs +6 -0
  21. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/0 +0 -0
  22. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +53 -1
  23. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_tracer/.zattrs +1 -1
  24. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/.zarray +20 -0
  25. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/.zattrs +6 -0
  26. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/0 +0 -0
  27. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/.zarray +20 -0
  28. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/.zattrs +6 -0
  29. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/0 +0 -0
  30. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zattrs +1 -2
  31. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zmetadata +27 -5
  32. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/.zarray +20 -0
  33. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/.zattrs +5 -0
  34. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/0 +0 -0
  35. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/omega/.zattrs +1 -3
  36. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Im/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Re/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Im/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Re/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_datasets.py +103 -1
  45. roms_tools/tests/test_setup/test_tides.py +112 -47
  46. roms_tools/utils.py +115 -1
  47. {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/METADATA +1 -1
  48. {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/RECORD +51 -33
  49. {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/WHEEL +1 -1
  50. {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/licenses/LICENSE +0 -0
  51. {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/top_level.txt +0 -0
roms_tools/setup/grid.py CHANGED
@@ -8,6 +8,7 @@ import matplotlib.pyplot as plt
8
8
  import yaml
9
9
  import importlib.metadata
10
10
  from typing import Dict, Union, List
11
+ from roms_tools.constants import R_EARTH
11
12
  from roms_tools.utils import save_datasets
12
13
  from roms_tools.setup.topography import _add_topography
13
14
  from roms_tools.setup.mask import _add_mask, _add_velocity_masks
@@ -918,8 +919,6 @@ class Grid:
918
919
  - lonq, latq: 2D arrays of longitudes and latitudes at cell corners.
919
920
  """
920
921
 
921
- r_earth = 6371315.0
922
-
923
922
  # initially define the domain to be longer in x-direction (dimension "length")
924
923
  # than in y-direction (dimension "width") to keep grid distortion minimal
925
924
  if self.size_y > self.size_x:
@@ -929,8 +928,8 @@ class Grid:
929
928
  domain_length, domain_width = self.size_x * 1e3, self.size_y * 1e3 # in m
930
929
  nl, nw = self.nx, self.ny
931
930
 
932
- domain_length_in_degrees = domain_length / r_earth
933
- domain_width_in_degrees = domain_width / r_earth
931
+ domain_length_in_degrees = domain_length / R_EARTH
932
+ domain_width_in_degrees = domain_width / R_EARTH
934
933
 
935
934
  # Generate 1D longitude arrays at cell centers and corners
936
935
  lon_array_1d_in_degrees = domain_length_in_degrees * (
@@ -1098,6 +1097,45 @@ class Grid:
1098
1097
 
1099
1098
  return ds
1100
1099
 
1100
+ def _infer_nominal_horizontal_resolution(self, lat=None):
1101
+ """Estimate the nominal horizontal resolution of the grid in degrees at a
1102
+ specified latitude.
1103
+
1104
+ This method calculates the nominal horizontal resolution of the grid by first
1105
+ determining the average grid spacing in meters. The spacing is then converted
1106
+ to degrees, accounting for the Earth's curvature, and the latitude where the
1107
+ resolution is being computed.
1108
+
1109
+ Parameters
1110
+ ----------
1111
+ lat : float, optional
1112
+ Latitude (in degrees) at which to estimate the horizontal resolution.
1113
+ If not provided, the resolution is calculated at the average latitude of
1114
+ the grid (`lat_rho`).
1115
+
1116
+ Returns
1117
+ -------
1118
+ float
1119
+ The estimated horizontal resolution in degrees, adjusted for the Earth's curvature.
1120
+ """
1121
+ if lat is None:
1122
+ # Center latitude in degrees
1123
+ lat = (self.ds.lat_rho.max() + self.ds.lat_rho.min()) / 2
1124
+
1125
+ # Convert latitude to radians
1126
+ lat_rad = np.deg2rad(lat)
1127
+
1128
+ # Mean resolution in meters
1129
+ resolution_in_m = ((1 / self.ds.pm).mean() + (1 / self.ds.pn).mean()) / 2
1130
+
1131
+ # Meters per degree at the equator
1132
+ meters_per_degree = 2 * np.pi * R_EARTH / 360
1133
+
1134
+ # Correct for latitude by multiplying by cos(latitude) for longitude
1135
+ resolution_in_degrees = resolution_in_m / (meters_per_degree * np.cos(lat_rad))
1136
+
1137
+ return resolution_in_degrees
1138
+
1101
1139
 
1102
1140
  def _rotate(coords, rot):
1103
1141
  """Rotate grid counterclockwise relative to surface of Earth by rot degrees."""
@@ -9,7 +9,8 @@ from pathlib import Path
9
9
  import matplotlib.pyplot as plt
10
10
  import matplotlib.cm as cm
11
11
  from roms_tools import Grid
12
- from roms_tools.plot import _get_projection, _add_field_to_ax
12
+ from roms_tools.constants import NUM_TRACERS
13
+ from roms_tools.plot import _plot, _get_projection
13
14
  from roms_tools.utils import save_datasets
14
15
  from roms_tools.setup.datasets import DaiRiverDataset
15
16
  from roms_tools.setup.utils import (
@@ -19,6 +20,7 @@ from roms_tools.setup.utils import (
19
20
  convert_to_roms_time,
20
21
  _to_yaml,
21
22
  _from_yaml,
23
+ add_tracer_metadata_to_ds,
22
24
  get_variable_metadata,
23
25
  )
24
26
 
@@ -297,7 +299,7 @@ class RiverForcing:
297
299
  ds = ds.assign_coords({"nriver": nriver})
298
300
 
299
301
  if self.include_bgc:
300
- ntracers = 2 + 32
302
+ ntracers = NUM_TRACERS
301
303
  else:
302
304
  ntracers = 2
303
305
  tracer_data = np.zeros(
@@ -311,52 +313,8 @@ class RiverForcing:
311
313
  tracer_data, dims=("river_time", "ntracers", "nriver")
312
314
  )
313
315
  river_tracer.attrs["long_name"] = "River tracer data"
314
-
315
- if self.include_bgc:
316
- tracer_names = xr.DataArray(
317
- [
318
- "temp",
319
- "salt",
320
- "PO4",
321
- "NO3",
322
- "SiO3",
323
- "NH4",
324
- "Fe",
325
- "Lig",
326
- "O2",
327
- "DIC",
328
- "DIC_ALT_CO2",
329
- "ALK",
330
- "ALK_ALT_CO2",
331
- "DOC",
332
- "DON",
333
- "DOP",
334
- "DOPr",
335
- "DONr",
336
- "DOCr",
337
- "zooC",
338
- "spChl",
339
- "spC",
340
- "spP",
341
- "spFe",
342
- "spCaCO3",
343
- "diatChl",
344
- "diatC",
345
- "diatP",
346
- "diatFe",
347
- "diatSi",
348
- "diazChl",
349
- "diazC",
350
- "diazP",
351
- "diazFe",
352
- ],
353
- dims="ntracers",
354
- )
355
- else:
356
- tracer_names = xr.DataArray(["temp", "salt"], dims="ntracers")
357
- tracer_names.attrs["long_name"] = "Tracer name"
358
- river_tracer.coords["tracer_name"] = tracer_names
359
316
  ds["river_tracer"] = river_tracer
317
+ ds = add_tracer_metadata_to_ds(ds, self.include_bgc)
360
318
 
361
319
  ds, time = convert_to_roms_time(
362
320
  ds, self.model_reference_date, self.climatology, time_name="river_time"
@@ -513,56 +471,25 @@ class RiverForcing:
513
471
  """Plots the original and updated river locations on a map projection."""
514
472
 
515
473
  field = self.grid.ds.mask_rho
516
- vmax = 3
517
- vmin = 0
518
- cmap = plt.colormaps.get_cmap("Blues")
519
- kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
520
-
521
474
  lon_deg = self.grid.ds.lon_rho
522
475
  lat_deg = self.grid.ds.lat_rho
523
-
524
- # check if North or South pole are in domain
525
- if lat_deg.max().values > 89 or lat_deg.min().values < -89:
526
- raise NotImplementedError(
527
- "Plotting is not implemented for the case that the domain contains the North or South pole."
528
- )
529
-
530
476
  if self.grid.straddle:
531
477
  lon_deg = xr.where(lon_deg > 180, lon_deg - 360, lon_deg)
532
478
  field = field.assign_coords({"lon": lon_deg, "lat": lat_deg})
533
479
 
534
- trans = _get_projection(lon_deg, lat_deg)
480
+ vmax = 6
481
+ vmin = 0
482
+ cmap = plt.colormaps.get_cmap("Blues")
483
+ kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
535
484
 
536
- lon_deg = lon_deg.values
537
- lat_deg = lat_deg.values
485
+ trans = _get_projection(lon_deg, lat_deg)
538
486
 
539
487
  fig, axs = plt.subplots(
540
488
  1, 2, figsize=(13, 13), subplot_kw={"projection": trans}
541
489
  )
542
490
 
543
491
  for ax in axs:
544
- _add_field_to_ax(
545
- ax,
546
- lon_deg,
547
- lat_deg,
548
- field,
549
- add_colorbar=False,
550
- kwargs=kwargs,
551
- )
552
- # Add gridlines with labels for latitude and longitude
553
- gridlines = ax.gridlines(
554
- draw_labels=True, linewidth=0.5, color="gray", alpha=0.7, linestyle="--"
555
- )
556
- gridlines.top_labels = False # Hide top labels
557
- gridlines.right_labels = False # Hide right labels
558
- gridlines.xlabel_style = {
559
- "size": 10,
560
- "color": "black",
561
- } # Customize longitude label style
562
- gridlines.ylabel_style = {
563
- "size": 10,
564
- "color": "black",
565
- } # Customize latitude label style
492
+ _plot(field, kwargs=kwargs, ax=ax, c=None, add_colorbar=False)
566
493
 
567
494
  proj = ccrs.PlateCarree()
568
495