roms-tools 1.6.0__py3-none-any.whl → 1.6.1__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.
roms_tools/_version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # Do not change! Do not track in version control!
2
- __version__ = "1.6.0"
2
+ __version__ = "1.6.1"
@@ -649,7 +649,14 @@ class BoundaryForcing:
649
649
  if var_name not in self.ds:
650
650
  raise ValueError(f"Variable '{var_name}' is not found in dataset.")
651
651
 
652
- field = self.ds[var_name].isel(bry_time=time).load()
652
+ field = self.ds[var_name].isel(bry_time=time)
653
+
654
+ if self.use_dask:
655
+ from dask.diagnostics import ProgressBar
656
+
657
+ with ProgressBar():
658
+ field = field.load()
659
+
653
660
  title = field.long_name
654
661
 
655
662
  if "s_rho" in field.dims:
@@ -699,24 +706,26 @@ class BoundaryForcing:
699
706
  _line_plot(field, title=title)
700
707
 
701
708
  def save(
702
- self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None
709
+ self,
710
+ filepath: Union[str, Path],
711
+ np_eta: int = None,
712
+ np_xi: int = None,
713
+ group: bool = False,
703
714
  ) -> None:
704
- """Save the boundary forcing fields to netCDF4 files.
705
-
706
- This method saves the dataset by grouping it into subsets based on the data frequency. The subsets are then written
707
- to one or more netCDF4 files. The filenames of the output files reflect the temporal coverage of the data.
715
+ """Save the boundary forcing fields to one or more netCDF4 files.
708
716
 
709
- There are two modes of saving the dataset:
717
+ This method saves the dataset either as a single file or as multiple files depending on the partitioning and grouping options.
718
+ The dataset can be saved in two modes:
710
719
 
711
- 1. **Single File Mode (default)**:
720
+ 1. **Single File Mode (default)**:
721
+ - If both `np_eta` and `np_xi` are `None`, the entire dataset is saved as a single netCDF4 file.
722
+ - The file is named based on the `filepath`, with `.nc` automatically appended.
712
723
 
713
- If both `np_eta` and `np_xi` are `None`, the entire dataset, divided by temporal subsets, is saved as a single netCDF4 file
714
- with the base filename specified by `filepath.nc`.
724
+ 2. **Partitioned Mode**:
725
+ - If either `np_eta` or `np_xi` is specified, the dataset is partitioned into spatial tiles along the `eta` and `xi` axes.
726
+ - Each tile is saved as a separate netCDF4 file, and filenames are modified with an index (e.g., `"filepath_YYYYMM.0.nc"`, `"filepath_YYYYMM.1.nc"`).
715
727
 
716
- 2. **Partitioned Mode**:
717
-
718
- - If either `np_eta` or `np_xi` is specified, the dataset is divided into spatial tiles along the eta-axis and xi-axis.
719
- - Each spatial tile is saved as a separate netCDF4 file.
728
+ Additionally, if `group` is set to `True`, the dataset is first grouped into temporal subsets, resulting in multiple grouped files before partitioning and saving.
720
729
 
721
730
  Parameters
722
731
  ----------
@@ -728,6 +737,8 @@ class BoundaryForcing:
728
737
  The number of partitions along the `eta` direction. If `None`, no spatial partitioning is performed.
729
738
  np_xi : int, optional
730
739
  The number of partitions along the `xi` direction. If `None`, no spatial partitioning is performed.
740
+ group: bool, optional
741
+ If `True`, groups the dataset into multiple files based on temporal data frequency. Defaults to `False`.
731
742
 
732
743
  Returns
733
744
  -------
@@ -742,7 +753,18 @@ class BoundaryForcing:
742
753
  if filepath.suffix == ".nc":
743
754
  filepath = filepath.with_suffix("")
744
755
 
745
- dataset_list, output_filenames = group_dataset(self.ds.load(), str(filepath))
756
+ if self.use_dask:
757
+ from dask.diagnostics import ProgressBar
758
+
759
+ with ProgressBar():
760
+ self.ds.load()
761
+
762
+ if group:
763
+ dataset_list, output_filenames = group_dataset(self.ds, str(filepath))
764
+ else:
765
+ dataset_list = [self.ds]
766
+ output_filenames = [str(filepath)]
767
+
746
768
  saved_filenames = save_datasets(
747
769
  dataset_list, output_filenames, np_eta=np_eta, np_xi=np_xi
748
770
  )
@@ -796,7 +818,7 @@ class BoundaryForcing:
796
818
  # Write header
797
819
  file.write(header)
798
820
  # Write YAML data
799
- yaml.dump(yaml_data, file, default_flow_style=False)
821
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
800
822
 
801
823
  @classmethod
802
824
  def from_yaml(
roms_tools/setup/grid.py CHANGED
@@ -679,7 +679,7 @@ class Grid:
679
679
  # Write header
680
680
  file.write(header)
681
681
  # Write YAML data
682
- yaml.dump(yaml_data, file, default_flow_style=False)
682
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
683
683
 
684
684
  @classmethod
685
685
  def from_yaml(cls, filepath: Union[str, Path]) -> "Grid":
@@ -518,7 +518,12 @@ class InitialConditions:
518
518
  ):
519
519
  raise ValueError("For 2D fields, specify either eta or xi, not both.")
520
520
 
521
- self.ds[var_name].load()
521
+ if self.use_dask:
522
+ from dask.diagnostics import ProgressBar
523
+
524
+ with ProgressBar():
525
+ self.ds[var_name].load()
526
+
522
527
  field = self.ds[var_name].squeeze()
523
528
 
524
529
  if all(dim in field.dims for dim in ["eta_rho", "xi_rho"]):
@@ -681,7 +686,13 @@ class InitialConditions:
681
686
  if filepath.suffix == ".nc":
682
687
  filepath = filepath.with_suffix("")
683
688
 
684
- dataset_list = [self.ds.load()]
689
+ if self.use_dask:
690
+ from dask.diagnostics import ProgressBar
691
+
692
+ with ProgressBar():
693
+ self.ds.load()
694
+
695
+ dataset_list = [self.ds]
685
696
  output_filenames = [str(filepath)]
686
697
 
687
698
  saved_filenames = save_datasets(
@@ -719,15 +730,18 @@ class InitialConditions:
719
730
 
720
731
  initial_conditions_data = {
721
732
  "InitialConditions": {
722
- "source": self.source,
723
733
  "ini_time": self.ini_time.isoformat(),
724
- "model_reference_date": self.model_reference_date.isoformat(),
734
+ "source": self.source,
725
735
  }
726
736
  }
727
737
  # Include bgc_source if it's not None
728
738
  if self.bgc_source is not None:
729
739
  initial_conditions_data["InitialConditions"]["bgc_source"] = self.bgc_source
730
740
 
741
+ initial_conditions_data["InitialConditions"][
742
+ "model_reference_date"
743
+ ] = self.model_reference_date.isoformat()
744
+
731
745
  yaml_data = {
732
746
  **grid_yaml_data,
733
747
  **initial_conditions_data,
@@ -737,7 +751,7 @@ class InitialConditions:
737
751
  # Write header
738
752
  file.write(header)
739
753
  # Write YAML data
740
- yaml.dump(yaml_data, file, default_flow_style=False)
754
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
741
755
 
742
756
  @classmethod
743
757
  def from_yaml(
@@ -462,7 +462,13 @@ class SurfaceForcing:
462
462
  if var_name not in self.ds:
463
463
  raise ValueError(f"Variable '{var_name}' is not found in dataset.")
464
464
 
465
- field = self.ds[var_name].isel(time=time).load()
465
+ field = self.ds[var_name].isel(time=time)
466
+ if self.use_dask:
467
+ from dask.diagnostics import ProgressBar
468
+
469
+ with ProgressBar():
470
+ field = field.load()
471
+
466
472
  title = field.long_name
467
473
 
468
474
  # assign lat / lon
@@ -502,24 +508,26 @@ class SurfaceForcing:
502
508
  )
503
509
 
504
510
  def save(
505
- self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None
511
+ self,
512
+ filepath: Union[str, Path],
513
+ np_eta: int = None,
514
+ np_xi: int = None,
515
+ group: bool = False,
506
516
  ) -> None:
507
- """Save the surface forcing fields to netCDF4 files.
508
-
509
- This method saves the dataset by grouping it into subsets based on the data frequency. The subsets are then written
510
- to one or more netCDF4 files. The filenames of the output files reflect the temporal coverage of the data.
511
-
512
- There are two modes of saving the dataset:
517
+ """Save the surface forcing fields to one or more netCDF4 files.
513
518
 
514
- 1. **Single File Mode (default)**:
519
+ This method saves the dataset either as a single file or as multiple files depending on the partitioning and grouping options.
520
+ The dataset can be saved in two modes:
515
521
 
516
- If both `np_eta` and `np_xi` are `None`, the entire dataset, divided by temporal subsets, is saved as a single netCDF4 file
517
- with the base filename specified by `filepath.nc`.
522
+ 1. **Single File Mode (default)**:
523
+ - If both `np_eta` and `np_xi` are `None`, the entire dataset is saved as a single netCDF4 file.
524
+ - The file is named based on the `filepath`, with `.nc` automatically appended.
518
525
 
519
- 2. **Partitioned Mode**:
526
+ 2. **Partitioned Mode**:
527
+ - If either `np_eta` or `np_xi` is specified, the dataset is partitioned into spatial tiles along the `eta` and `xi` axes.
528
+ - Each tile is saved as a separate netCDF4 file, and filenames are modified with an index (e.g., `"filepath_YYYYMM.0.nc"`, `"filepath_YYYYMM.1.nc"`).
520
529
 
521
- - If either `np_eta` or `np_xi` is specified, the dataset is divided into spatial tiles along the eta-axis and xi-axis.
522
- - Each spatial tile is saved as a separate netCDF4 file.
530
+ Additionally, if `group` is set to `True`, the dataset is first grouped into temporal subsets, resulting in multiple grouped files before partitioning and saving.
523
531
 
524
532
  Parameters
525
533
  ----------
@@ -531,6 +539,8 @@ class SurfaceForcing:
531
539
  The number of partitions along the `eta` direction. If `None`, no spatial partitioning is performed.
532
540
  np_xi : int, optional
533
541
  The number of partitions along the `xi` direction. If `None`, no spatial partitioning is performed.
542
+ group: bool, optional
543
+ If `True`, groups the dataset into multiple files based on temporal data frequency. Defaults to `False`.
534
544
 
535
545
  Returns
536
546
  -------
@@ -545,7 +555,18 @@ class SurfaceForcing:
545
555
  if filepath.suffix == ".nc":
546
556
  filepath = filepath.with_suffix("")
547
557
 
548
- dataset_list, output_filenames = group_dataset(self.ds.load(), str(filepath))
558
+ if self.use_dask:
559
+ from dask.diagnostics import ProgressBar
560
+
561
+ with ProgressBar():
562
+ self.ds.load()
563
+
564
+ if group:
565
+ dataset_list, output_filenames = group_dataset(self.ds, str(filepath))
566
+ else:
567
+ dataset_list = [self.ds]
568
+ output_filenames = [str(filepath)]
569
+
549
570
  saved_filenames = save_datasets(
550
571
  dataset_list, output_filenames, np_eta=np_eta, np_xi=np_xi
551
572
  )
@@ -603,7 +624,7 @@ class SurfaceForcing:
603
624
  # Write header
604
625
  file.write(header)
605
626
  # Write YAML data
606
- yaml.dump(yaml_data, file, default_flow_style=False)
627
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
607
628
 
608
629
  @classmethod
609
630
  def from_yaml(
roms_tools/setup/tides.py CHANGED
@@ -300,7 +300,14 @@ class TidalForcing:
300
300
  >>> tidal_forcing.plot("ssh_Re", nc=0)
301
301
  """
302
302
 
303
- field = self.ds[var_name].isel(ntides=ntides).compute()
303
+ field = self.ds[var_name].isel(ntides=ntides)
304
+
305
+ if self.use_dask:
306
+ from dask.diagnostics import ProgressBar
307
+
308
+ with ProgressBar():
309
+ field = field.load()
310
+
304
311
  if all(dim in field.dims for dim in ["eta_rho", "xi_rho"]):
305
312
  field = field.where(self.grid.ds.mask_rho)
306
313
  field = field.assign_coords(
@@ -378,7 +385,13 @@ class TidalForcing:
378
385
  if filepath.suffix == ".nc":
379
386
  filepath = filepath.with_suffix("")
380
387
 
381
- dataset_list = [self.ds.load()]
388
+ if self.use_dask:
389
+ from dask.diagnostics import ProgressBar
390
+
391
+ with ProgressBar():
392
+ self.ds.load()
393
+
394
+ dataset_list = [self.ds]
382
395
  output_filenames = [str(filepath)]
383
396
 
384
397
  saved_filenames = save_datasets(
@@ -419,8 +432,8 @@ class TidalForcing:
419
432
  "TidalForcing": {
420
433
  "source": self.source,
421
434
  "ntides": self.ntides,
422
- "model_reference_date": self.model_reference_date.isoformat(),
423
435
  "allan_factor": self.allan_factor,
436
+ "model_reference_date": self.model_reference_date.isoformat(),
424
437
  }
425
438
  }
426
439
 
@@ -431,7 +444,7 @@ class TidalForcing:
431
444
  # Write header
432
445
  file.write(header)
433
446
  # Write YAML data
434
- yaml.dump(yaml_data, file, default_flow_style=False)
447
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
435
448
 
436
449
  @classmethod
437
450
  def from_yaml(
@@ -85,8 +85,8 @@ def test_boundary_forcing_creation_with_bgc(boundary_forcing_fixture, request):
85
85
  assert hasattr(boundary_forcing.ds, "climatology")
86
86
 
87
87
 
88
- def test_boundary_forcing_plot_save(boundary_forcing, tmp_path):
89
- """Test plot and save methods."""
88
+ def test_boundary_forcing_plot(boundary_forcing):
89
+ """Test plot."""
90
90
 
91
91
  boundary_forcing.plot(var_name="temp_south", layer_contours=True)
92
92
  boundary_forcing.plot(var_name="temp_east", layer_contours=True)
@@ -99,6 +99,10 @@ def test_boundary_forcing_plot_save(boundary_forcing, tmp_path):
99
99
  boundary_forcing.plot(var_name="vbar_north")
100
100
  boundary_forcing.plot(var_name="ubar_west")
101
101
 
102
+
103
+ def test_boundary_forcing_save(boundary_forcing, tmp_path):
104
+ """Test save method."""
105
+
102
106
  for file_str in ["test_bf", "test_bf.nc"]:
103
107
  # Create a temporary filepath using the tmp_path fixture
104
108
  for filepath in [
@@ -106,9 +110,19 @@ def test_boundary_forcing_plot_save(boundary_forcing, tmp_path):
106
110
  str(tmp_path / file_str),
107
111
  ]: # test for Path object and str
108
112
 
109
- # Test saving without partitioning
113
+ # Test saving without partitioning and grouping
110
114
  saved_filenames = boundary_forcing.save(filepath)
111
115
 
116
+ filepath_str = str(Path(filepath).with_suffix(""))
117
+ expected_filepath = Path(f"{filepath_str}.nc")
118
+
119
+ assert saved_filenames == [expected_filepath]
120
+ assert expected_filepath.exists()
121
+ expected_filepath.unlink()
122
+
123
+ # Test saving without partitioning but with grouping
124
+ saved_filenames = boundary_forcing.save(filepath, group=True)
125
+
112
126
  filepath_str = str(Path(filepath).with_suffix(""))
113
127
  expected_filepath = Path(f"{filepath_str}_202106.nc")
114
128
 
@@ -116,8 +130,8 @@ def test_boundary_forcing_plot_save(boundary_forcing, tmp_path):
116
130
  assert expected_filepath.exists()
117
131
  expected_filepath.unlink()
118
132
 
119
- # Test saving with partitioning
120
- saved_filenames = boundary_forcing.save(filepath, np_eta=2)
133
+ # Test saving with partitioning and grouping
134
+ saved_filenames = boundary_forcing.save(filepath, np_eta=2, group=True)
121
135
  expected_filepath_list = [
122
136
  Path(filepath_str + f"_202106.{index}.nc") for index in range(2)
123
137
  ]
@@ -129,16 +143,18 @@ def test_boundary_forcing_plot_save(boundary_forcing, tmp_path):
129
143
  expected_filepath.unlink()
130
144
 
131
145
 
132
- def test_bgc_boundary_forcing_plot_save(
133
- bgc_boundary_forcing_from_climatology, tmp_path
134
- ):
135
- """Test plot and save methods."""
146
+ def test_bgc_boundary_forcing_plot(bgc_boundary_forcing_from_climatology):
147
+ """Test plot method."""
136
148
 
137
149
  bgc_boundary_forcing_from_climatology.plot(var_name="ALK_south")
138
150
  bgc_boundary_forcing_from_climatology.plot(var_name="ALK_east")
139
151
  bgc_boundary_forcing_from_climatology.plot(var_name="ALK_north")
140
152
  bgc_boundary_forcing_from_climatology.plot(var_name="ALK_west")
141
153
 
154
+
155
+ def test_bgc_boundary_forcing_save(bgc_boundary_forcing_from_climatology, tmp_path):
156
+ """Test save method."""
157
+
142
158
  for file_str in ["test_bf", "test_bf.nc"]:
143
159
  # Create a temporary filepath using the tmp_path fixture
144
160
  for filepath in [
@@ -146,9 +162,20 @@ def test_bgc_boundary_forcing_plot_save(
146
162
  str(tmp_path / file_str),
147
163
  ]: # test for Path object and str
148
164
 
149
- # Test saving without partitioning
165
+ # Test saving without partitioning and grouping
150
166
  saved_filenames = bgc_boundary_forcing_from_climatology.save(filepath)
151
167
 
168
+ filepath_str = str(Path(filepath).with_suffix(""))
169
+ expected_filepath = Path(f"{filepath_str}.nc")
170
+ assert saved_filenames == [expected_filepath]
171
+ assert expected_filepath.exists()
172
+ expected_filepath.unlink()
173
+
174
+ # Test saving without partitioning but with grouping
175
+ saved_filenames = bgc_boundary_forcing_from_climatology.save(
176
+ filepath, group=True
177
+ )
178
+
152
179
  filepath_str = str(Path(filepath).with_suffix(""))
153
180
  expected_filepath = Path(f"{filepath_str}_clim.nc")
154
181
  assert saved_filenames == [expected_filepath]
@@ -157,7 +184,7 @@ def test_bgc_boundary_forcing_plot_save(
157
184
 
158
185
  # Test saving with partitioning
159
186
  saved_filenames = bgc_boundary_forcing_from_climatology.save(
160
- filepath, np_xi=2
187
+ filepath, np_xi=2, group=True
161
188
  )
162
189
 
163
190
  expected_filepath_list = [
@@ -207,9 +234,9 @@ def test_files_have_same_hash(boundary_forcing, tmp_path, use_dask):
207
234
  filepath2 = tmp_path / "test2.nc"
208
235
 
209
236
  boundary_forcing.to_yaml(yaml_filepath)
210
- boundary_forcing.save(filepath1)
237
+ boundary_forcing.save(filepath1, group=True)
211
238
  bdry_forcing_from_file = BoundaryForcing.from_yaml(yaml_filepath, use_dask=use_dask)
212
- bdry_forcing_from_file.save(filepath2)
239
+ bdry_forcing_from_file.save(filepath2, group=True)
213
240
 
214
241
  filepath_str1 = str(Path(filepath1).with_suffix(""))
215
242
  filepath_str2 = str(Path(filepath2).with_suffix(""))
@@ -235,9 +262,9 @@ def test_files_have_same_hash_clim(
235
262
  filepath2 = tmp_path / "test2.nc"
236
263
 
237
264
  bgc_boundary_forcing_from_climatology.to_yaml(yaml_filepath)
238
- bgc_boundary_forcing_from_climatology.save(filepath1)
265
+ bgc_boundary_forcing_from_climatology.save(filepath1, group=True)
239
266
  bdry_forcing_from_file = BoundaryForcing.from_yaml(yaml_filepath, use_dask=use_dask)
240
- bdry_forcing_from_file.save(filepath2)
267
+ bdry_forcing_from_file.save(filepath2, group=True)
241
268
 
242
269
  filepath_str1 = str(Path(filepath1).with_suffix(""))
243
270
  filepath_str2 = str(Path(filepath2).with_suffix(""))
@@ -176,10 +176,8 @@ def test_interpolation_from_climatology(
176
176
  )
177
177
 
178
178
 
179
- def test_initial_conditions_plot_save(
180
- initial_conditions_with_bgc_from_climatology, tmp_path
181
- ):
182
- """Test plot and save methods."""
179
+ def test_initial_conditions_plot(initial_conditions_with_bgc_from_climatology):
180
+ """Test plot method."""
183
181
 
184
182
  initial_conditions_with_bgc_from_climatology.plot(var_name="temp", s=0)
185
183
  initial_conditions_with_bgc_from_climatology.plot(
@@ -213,6 +211,12 @@ def test_initial_conditions_plot_save(
213
211
  initial_conditions_with_bgc_from_climatology.plot(var_name="ALK", s=0, xi=0)
214
212
  initial_conditions_with_bgc_from_climatology.plot(var_name="ALK", eta=0, xi=0)
215
213
 
214
+
215
+ def test_initial_conditions_save(
216
+ initial_conditions_with_bgc_from_climatology, tmp_path
217
+ ):
218
+ """Test save method."""
219
+
216
220
  for file_str in ["test_ic", "test_ic.nc"]:
217
221
  # Create a temporary filepath using the tmp_path fixture
218
222
  for filepath in [
@@ -187,12 +187,6 @@ def grid_that_straddles_180_degree_meridian():
187
187
  def test_successful_initialization_with_regional_data(grid_fixture, request, use_dask):
188
188
  """Test the initialization of SurfaceForcing with regional ERA5 data.
189
189
 
190
- This test checks the following:
191
- 1. SurfaceForcing object initializes successfully with provided regional data.
192
- 2. Attributes such as `start_time`, `end_time`, and `source` are set correctly.
193
- 3. The dataset contains expected variables, including "uwnd", "vwnd", "swrad", "lwrad", "Tair", "qair", and "rain".
194
- 4. Surface forcing plots for "uwnd", "vwnd", and "rain" are generated without errors.
195
-
196
190
  The test is performed twice:
197
191
  - First with the default fine grid.
198
192
  - Then with the coarse grid enabled.
@@ -513,8 +507,8 @@ def test_surface_forcing_pco2_replication(sfc_forcing_fixture, request):
513
507
  "coarse_surface_forcing",
514
508
  ],
515
509
  )
516
- def test_surface_forcing_plot_save(sfc_forcing_fixture, request, tmp_path):
517
- """Test plot and save methods."""
510
+ def test_surface_forcing_save(sfc_forcing_fixture, request, tmp_path):
511
+ """Test save method."""
518
512
  sfc_forcing = request.getfixturevalue(sfc_forcing_fixture)
519
513
  sfc_forcing.plot(var_name="uwnd", time=0)
520
514
 
@@ -525,16 +519,24 @@ def test_surface_forcing_plot_save(sfc_forcing_fixture, request, tmp_path):
525
519
  str(tmp_path / file_str),
526
520
  ]: # test for Path object and str
527
521
 
528
- # Test saving without partitioning
522
+ # Test saving without partitioning and grouping
529
523
  saved_filenames = sfc_forcing.save(filepath)
530
524
  filepath_str = str(Path(filepath).with_suffix(""))
525
+ expected_filepath = Path(f"{filepath_str}.nc")
526
+ assert saved_filenames == [expected_filepath]
527
+ assert expected_filepath.exists()
528
+ expected_filepath.unlink()
529
+
530
+ # Test saving without partitioning but with grouping
531
+ saved_filenames = sfc_forcing.save(filepath, group=True)
532
+ filepath_str = str(Path(filepath).with_suffix(""))
531
533
  expected_filepath = Path(f"{filepath_str}_202002.nc")
532
534
  assert saved_filenames == [expected_filepath]
533
535
  assert expected_filepath.exists()
534
536
  expected_filepath.unlink()
535
537
 
536
538
  # Test saving with partitioning
537
- saved_filenames = sfc_forcing.save(filepath, np_eta=1)
539
+ saved_filenames = sfc_forcing.save(filepath, np_eta=1, group=True)
538
540
 
539
541
  expected_filepath_list = [
540
542
  Path(filepath_str + f"_202002.{index}.nc") for index in range(1)
@@ -545,12 +547,15 @@ def test_surface_forcing_plot_save(sfc_forcing_fixture, request, tmp_path):
545
547
  expected_filepath.unlink()
546
548
 
547
549
 
548
- def test_surface_forcing_bgc_plot_save(bgc_surface_forcing, tmp_path):
549
- """Test plot and save methods."""
550
+ def test_surface_forcing_bgc_plot(bgc_surface_forcing):
551
+ """Test plot method."""
550
552
 
551
- # Check the values in the dataset
552
553
  bgc_surface_forcing.plot(var_name="pco2_air", time=0)
553
554
 
555
+
556
+ def test_surface_forcing_bgc_save(bgc_surface_forcing, tmp_path):
557
+ """Test save method."""
558
+
554
559
  for file_str in ["test_sf", "test_sf.nc"]:
555
560
  # Create a temporary filepath using the tmp_path fixture
556
561
  for filepath in [
@@ -558,16 +563,24 @@ def test_surface_forcing_bgc_plot_save(bgc_surface_forcing, tmp_path):
558
563
  str(tmp_path / file_str),
559
564
  ]: # test for Path object and str
560
565
 
561
- # Test saving without partitioning
566
+ # Test saving without partitioning and grouping
562
567
  saved_filenames = bgc_surface_forcing.save(filepath)
563
568
  filepath_str = str(Path(filepath).with_suffix(""))
569
+ expected_filepath = Path(f"{filepath_str}.nc")
570
+ assert saved_filenames == [expected_filepath]
571
+ assert expected_filepath.exists()
572
+ expected_filepath.unlink()
573
+
574
+ # Test saving without partitioning but with grouping
575
+ saved_filenames = bgc_surface_forcing.save(filepath, group=True)
576
+ filepath_str = str(Path(filepath).with_suffix(""))
564
577
  expected_filepath = Path(f"{filepath_str}_202002.nc")
565
578
  assert saved_filenames == [expected_filepath]
566
579
  assert expected_filepath.exists()
567
580
  expected_filepath.unlink()
568
581
 
569
582
  # Test saving with partitioning
570
- saved_filenames = bgc_surface_forcing.save(filepath, np_xi=5)
583
+ saved_filenames = bgc_surface_forcing.save(filepath, np_xi=5, group=True)
571
584
 
572
585
  expected_filepath_list = [
573
586
  Path(filepath_str + f"_202002.{index}.nc") for index in range(5)
@@ -578,13 +591,10 @@ def test_surface_forcing_bgc_plot_save(bgc_surface_forcing, tmp_path):
578
591
  expected_filepath.unlink()
579
592
 
580
593
 
581
- def test_surface_forcing_bgc_from_clim_plot_save(
594
+ def test_surface_forcing_bgc_from_clim_save(
582
595
  bgc_surface_forcing_from_climatology, tmp_path
583
596
  ):
584
- """Test plot and save methods."""
585
-
586
- # Check the values in the dataset
587
- bgc_surface_forcing_from_climatology.plot(var_name="pco2_air", time=0)
597
+ """Test save method."""
588
598
 
589
599
  for file_str in ["test_sf", "test_sf.nc"]:
590
600
  # Create a temporary filepath using the tmp_path fixture
@@ -593,17 +603,27 @@ def test_surface_forcing_bgc_from_clim_plot_save(
593
603
  str(tmp_path / file_str),
594
604
  ]: # test for Path object and str
595
605
 
596
- # Test saving without partitioning
606
+ # Test saving without partitioning and grouping
597
607
  saved_filenames = bgc_surface_forcing_from_climatology.save(filepath)
598
608
  filepath_str = str(Path(filepath).with_suffix(""))
609
+ expected_filepath = Path(f"{filepath_str}.nc")
610
+ assert saved_filenames == [expected_filepath]
611
+ assert expected_filepath.exists()
612
+ expected_filepath.unlink()
613
+
614
+ # Test saving without partitioning but with grouping
615
+ saved_filenames = bgc_surface_forcing_from_climatology.save(
616
+ filepath, group=True
617
+ )
618
+ filepath_str = str(Path(filepath).with_suffix(""))
599
619
  expected_filepath = Path(f"{filepath_str}_clim.nc")
600
620
  assert saved_filenames == [expected_filepath]
601
621
  assert expected_filepath.exists()
602
622
  expected_filepath.unlink()
603
623
 
604
- # Test saving with partitioning
624
+ # Test saving with partitioning and grouping
605
625
  saved_filenames = bgc_surface_forcing_from_climatology.save(
606
- filepath, np_eta=5
626
+ filepath, np_eta=5, group=True
607
627
  )
608
628
 
609
629
  expected_filepath_list = [
@@ -666,9 +686,9 @@ def test_files_have_same_hash(sfc_forcing_fixture, request, tmp_path, use_dask):
666
686
  filepath2 = tmp_path / "test2.nc"
667
687
 
668
688
  sfc_forcing.to_yaml(yaml_filepath)
669
- sfc_forcing.save(filepath1)
689
+ sfc_forcing.save(filepath1, group=True)
670
690
  sfc_forcing_from_file = SurfaceForcing.from_yaml(yaml_filepath, use_dask=use_dask)
671
- sfc_forcing_from_file.save(filepath2)
691
+ sfc_forcing_from_file.save(filepath2, group=True)
672
692
 
673
693
  filepath_str1 = str(Path(filepath1).with_suffix(""))
674
694
  filepath_str2 = str(Path(filepath2).with_suffix(""))
@@ -694,9 +714,9 @@ def test_files_have_same_hash_clim(
694
714
  filepath2 = tmp_path / "test2.nc"
695
715
 
696
716
  bgc_surface_forcing_from_climatology.to_yaml(yaml_filepath)
697
- bgc_surface_forcing_from_climatology.save(filepath1)
717
+ bgc_surface_forcing_from_climatology.save(filepath1, group=True)
698
718
  sfc_forcing_from_file = SurfaceForcing.from_yaml(yaml_filepath, use_dask=use_dask)
699
- sfc_forcing_from_file.save(filepath2)
719
+ sfc_forcing_from_file.save(filepath2, group=True)
700
720
 
701
721
  filepath_str1 = str(Path(filepath1).with_suffix(""))
702
722
  filepath_str2 = str(Path(filepath2).with_suffix(""))
@@ -169,13 +169,15 @@ def test_insufficient_number_of_consituents(grid_that_straddles_dateline, use_da
169
169
  )
170
170
 
171
171
 
172
- def test_tidal_forcing_plot_save(tidal_forcing, tmp_path):
173
- """Test plot and save methods in the same test since we dask arrays are already
174
- computed."""
175
- tidal_forcing.ds.load()
172
+ def test_tidal_forcing_plot(tidal_forcing):
173
+ """Test plot method."""
176
174
 
177
175
  tidal_forcing.plot(var_name="ssh_Re", ntides=0)
178
176
 
177
+
178
+ def test_tidal_forcing_save(tidal_forcing, tmp_path):
179
+ """Test save method."""
180
+
179
181
  for file_str in ["test_tides", "test_tides.nc"]:
180
182
  # Create a temporary filepath using the tmp_path fixture
181
183
  for filepath in [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: roms-tools
3
- Version: 1.6.0
3
+ Version: 1.6.1
4
4
  Summary: Tools for running and analysing UCLA-ROMS simulations
5
5
  Author-email: Nora Loose <nora.loose@gmail.com>, Thomas Nicholas <tom@cworthy.org>
6
6
  License: Apache-2
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
18
19
  Requires-Python: >=3.10
19
20
  Description-Content-Type: text/markdown
20
21
  License-File: LICENSE
@@ -1,32 +1,32 @@
1
1
  ci/environment.yml,sha256=2daWGcAMUMMuc4tNZ9BMivFIE6lh3Vz5ggPykhQPHio,191
2
2
  roms_tools/__init__.py,sha256=PQ7jWQ97DYS5b6YIFZVE2PYaRwXjN0Ykfhq0PKqN9ME,560
3
- roms_tools/_version.py,sha256=19-IoPJ1y0nMwmoLYAcRjMxXDRU1ZkTpc3XEXl66lNI,72
3
+ roms_tools/_version.py,sha256=R0F125tMbDXigLRrvuXWTAoA4KLSeQY0vbgGyoN8FRk,72
4
4
  roms_tools/utils.py,sha256=hlopIyqN-TLnglOvEPQm5H4EkUdV1QjL9CIu0v45d8E,12105
5
5
  roms_tools/setup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- roms_tools/setup/boundary_forcing.py,sha256=FX1O3MMy2E2DjISQ40RWssWcdQVPr6afJTchpUQ80Eo,36967
6
+ roms_tools/setup/boundary_forcing.py,sha256=SM6mOb48mhCsJzcT0ibdMH1HTn7RpwyNwKg3HA3TPrE,37754
7
7
  roms_tools/setup/datasets.py,sha256=xtphonHTFGo1WqrqkxxP97iLYErVrzcfcDE_Vm-hfe4,58560
8
8
  roms_tools/setup/download.py,sha256=JD48Xi5VT4oEBaBSCoGd08g46MVMl3_UW1KowSQI6ak,5102
9
9
  roms_tools/setup/fill.py,sha256=YQes_9uADZ-XZ6dBqXyvG7OAp7UrWhX-p3pR1gD6Od4,11120
10
- roms_tools/setup/grid.py,sha256=B0eKhLUT1LH25AesGlBfkLAR71khNvUJrGsUHGDMfws,45074
11
- roms_tools/setup/initial_conditions.py,sha256=zowJCh3a_9SHjRthj-lG5yUY2G-0whee5AVfahPCaWw,30639
10
+ roms_tools/setup/grid.py,sha256=IWzGwbWQlA3xugo-uc8jxoMXv9BLKrg7HKlpUUM9Ejg,45091
11
+ roms_tools/setup/initial_conditions.py,sha256=9pDuELgxOaGcEbERAjwECiivWDoffdND5EV7TjMRIds,30975
12
12
  roms_tools/setup/plot.py,sha256=g7jezPGQr8lPkIG9dCQwKqdEStFNu5k8Wz2afl-UNZQ,4856
13
13
  roms_tools/setup/regrid.py,sha256=moJWjqz5QCEYHYPgzfwtmDif39KUf2wGstTlV9BxUHU,5096
14
- roms_tools/setup/surface_forcing.py,sha256=I4naXwlQi5L661jRnwH57Oc8reoZDgvUhPlQjyA5xX0,23713
15
- roms_tools/setup/tides.py,sha256=1ZrGO0TUoPLxbHnF8Dan-gO_0ATijuKJVkDBUttiUR0,28652
14
+ roms_tools/setup/surface_forcing.py,sha256=0qb1-DtnO-CeEbCAbo88RBCNgKDs8HOuxHkRYIf8U3M,24499
15
+ roms_tools/setup/tides.py,sha256=DiLeBAQxRlUJNYUUyzUMxbHgMG-NOjzQ7coAlnuGqYI,28947
16
16
  roms_tools/setup/topography.py,sha256=E_gDNbMxbVn08fCCVL0eRfiWFXaq8UTknONrCIC5hX8,10348
17
17
  roms_tools/setup/utils.py,sha256=nJ9H9NWiacEyt1m76F1LAsFlvygXx2aEzzfwCs81ZXc,32651
18
18
  roms_tools/setup/vertical_coordinate.py,sha256=6Y6a1ouIZjorawzTFlJqZKQInoWQtvxQXXCI9iRZfKE,3023
19
19
  roms_tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  roms_tools/tests/test_utils.py,sha256=X16UHYzd8KmUgxBHJqmVP6cIHfOtScCdXPw905bgGMk,7966
21
21
  roms_tools/tests/test_setup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- roms_tools/tests/test_setup/test_boundary_forcing.py,sha256=DLCiGzSItMIr_xlJCJlYHd_7Rg5mb4zGrOnE-Y_WUNk,10307
22
+ roms_tools/tests/test_setup/test_boundary_forcing.py,sha256=B0GJHL30mIeq6q_0wSWb04GOojyoOIMnNoDNZBBuRZE,11424
23
23
  roms_tools/tests/test_setup/test_datasets.py,sha256=cFGtPdPIAMZlYEX1f_97KLiUJd8aAs6Cv29z6wctQPY,16267
24
24
  roms_tools/tests/test_setup/test_fill.py,sha256=gDHuM58d3ECQE317ZntChYt4hWCfo4eVhkW13NiZ1V4,3735
25
25
  roms_tools/tests/test_setup/test_grid.py,sha256=xaZcu0rM1hKOU93NcaBMX5gL8WqfTNvVhrX00h2IHjA,12177
26
- roms_tools/tests/test_setup/test_initial_conditions.py,sha256=tPKSKYAkGrK5Ypc57bBg8MxZzDHKNJShAC_DzR9RxEk,11095
26
+ roms_tools/tests/test_setup/test_initial_conditions.py,sha256=qjG7R6QwsisokqUGVEaWdSkmjoz4Vdc7uiqNHgLpIHw,11190
27
27
  roms_tools/tests/test_setup/test_regrid.py,sha256=NMzMkPHaFfO_9H0SbIpFL3VHlzhd71gUVLu81QmU-bs,1891
28
- roms_tools/tests/test_setup/test_surface_forcing.py,sha256=IH3q-v1DS39M8vjJrLQAa5pCll46RRhxLMbYASTk3lg,24493
29
- roms_tools/tests/test_setup/test_tides.py,sha256=p41hM6qU_UMXA2kgpawcjk8U5ShLerX05vmVwoiItCM,8604
28
+ roms_tools/tests/test_setup/test_surface_forcing.py,sha256=rRe0QqIfi7ffHbNSy-yR_gDE4c6Z8qfV5DD3sI49Di4,25367
29
+ roms_tools/tests/test_setup/test_tides.py,sha256=sLtImkSjZl9TFcOFnFdRSZKbG4-qzqIh-xo3G3_aCkI,8572
30
30
  roms_tools/tests/test_setup/test_topography.py,sha256=le0_yDCIOcbpfB4wWpAWEZC9okhJQufNcZvowYaWdM4,2581
31
31
  roms_tools/tests/test_setup/test_utils.py,sha256=lVeeiEEk_nR0zdmAdRHMlkBUNrAZMiZFrHaLQNy_lPE,585
32
32
  roms_tools/tests/test_setup/test_validation.py,sha256=RVSOgv2C6v-H7UtJA5zSsRUL8UnKjVIzjQ2gC8235Ds,2146
@@ -1018,8 +1018,8 @@ roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0,sha256=60jWZ
1018
1018
  roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/.zarray,sha256=2P8kKjSgdw5-3udU-vGJ3bzhNuRn7fZmWN811qBJn34,357
1019
1019
  roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/.zattrs,sha256=2z7WUPvCT9VfFs8VCBltFHLWgaGj1jcw3yZ4n0viLRg,197
1020
1020
  roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0,sha256=33Gl8otBmgqVarmAnZuEqTYS2_hVJUJh-iN1HzvaDuo,96
1021
- roms_tools-1.6.0.dist-info/LICENSE,sha256=CV14VH8hnprGy6SN5GqFIxNNxt5V9D2ev_kBUW6lsBE,11313
1022
- roms_tools-1.6.0.dist-info/METADATA,sha256=9EXxmH9O3aEDEK330t0QG77KM2OLKxTFu0PxnRTi114,4030
1023
- roms_tools-1.6.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1024
- roms_tools-1.6.0.dist-info/top_level.txt,sha256=aAf4T4nYQSkay5iKJ9kmTjlDgd4ETdp9OSlB4sJdt8Y,19
1025
- roms_tools-1.6.0.dist-info/RECORD,,
1021
+ roms_tools-1.6.1.dist-info/LICENSE,sha256=CV14VH8hnprGy6SN5GqFIxNNxt5V9D2ev_kBUW6lsBE,11313
1022
+ roms_tools-1.6.1.dist-info/METADATA,sha256=xd6a1V-bxvYo8EZT_mF9kowZK5K1FMhgrQfLT_W_XFc,4081
1023
+ roms_tools-1.6.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1024
+ roms_tools-1.6.1.dist-info/top_level.txt,sha256=aAf4T4nYQSkay5iKJ9kmTjlDgd4ETdp9OSlB4sJdt8Y,19
1025
+ roms_tools-1.6.1.dist-info/RECORD,,