Skip to content

Commit 4e61d86

Browse files
authored
Improve timestamp adjustment function in Glorys obc generation workflow (NOAA-GFDL#137)
* fixed the timestamp adjustment function * update glorys python codes to fix timestamp issue
1 parent 0a5dc47 commit 4e61d86

File tree

2 files changed

+60
-14
lines changed

2 files changed

+60
-14
lines changed

tools/boundary/boundary.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ def add_coords(self, ds):
496496
def regrid_velocity(
497497
self, usource, vsource,
498498
method='nearest_s2d', periodic=False, write=True,
499-
flood=False, fill='b', xdim='lon', ydim='lat', zdim='z', rotate=True, **kwargs):
499+
flood=False, fill='b', xdim='lon', ydim='lat', zdim='z', rotate=True,
500+
time_attrs=None, time_encoding=None, **kwargs):
500501
"""Interpolate velocity onto segment and (optionally) write to file.
501502
502503
Args:
@@ -607,6 +608,12 @@ def regrid_velocity(
607608

608609
ds_uv = self.rename_dims(ds_uv)
609610

611+
# Restore time attributes and encoding
612+
if time_attrs:
613+
ds_uv['time'].attrs = time_attrs
614+
if time_encoding:
615+
ds_uv['time'].encoding = time_encoding
616+
610617
if write:
611618
self.to_netcdf(ds_uv, 'uv', **kwargs)
612619

@@ -616,7 +623,8 @@ def regrid_tracer(
616623
self, tsource,
617624
method='nearest_s2d', periodic=False, write=True,
618625
flood=False, fill='b', xdim='lon', ydim='lat', zdim='z',
619-
regrid_suffix='t', source_var=None, **kwargs):
626+
regrid_suffix='t', source_var=None,
627+
time_attrs=None, time_encoding=None, **kwargs):
620628
"""Regrid a tracer onto segment and (optionally) write to file.
621629
622630
Args:
@@ -685,6 +693,12 @@ def regrid_tracer(
685693

686694
tdest = self.rename_dims(tdest)
687695
tdest = tdest.rename({name: f'{name}_{self.segstr}'})
696+
697+
# Restore time attributes and encoding
698+
if time_attrs:
699+
tdest['time'].attrs = time_attrs
700+
if time_encoding:
701+
tdest['time'].encoding = time_encoding
688702

689703
if write:
690704
self.to_netcdf(tdest, name, **kwargs)

tools/boundary/write_glorys_boundary_daily.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from os import path
3232

3333
import xarray
34+
import numpy as np
3435
import yaml
3536
from boundary import Segment
3637

@@ -53,18 +54,24 @@ def write_day(date, glorys_dir, segments, variables, output_prefix):
5354
return
5455

5556
glorys = (
56-
xarray.open_dataset(file_path)
57+
xarray.open_dataset(file_path, decode_times=False)
5758
.rename({'latitude': 'lat', 'longitude': 'lon', 'depth': 'z'})
5859
)
5960

61+
# Capture time attributes and encoding
62+
time_attrs = glorys['time'].attrs if 'time' in glorys.coords else None
63+
time_encoding = glorys['time'].encoding if 'time' in glorys.coords else None
64+
6065
for segment in segments:
6166
for variable in variables:
6267
if variable == 'uv':
6368
print(f"Processing {segment.border} {variable}")
64-
segment.regrid_velocity(glorys['uo'], glorys['vo'], suffix=f"{date:%Y%m%d}", flood=False)
69+
segment.regrid_velocity(glorys['uo'], glorys['vo'], suffix=f"{date:%Y%m%d}", flood=False,
70+
time_attrs=time_attrs, time_encoding=time_encoding )
6571
elif variable in ['thetao', 'so', 'zos']:
6672
print(f"Processing {segment.border} {variable}")
67-
segment.regrid_tracer(glorys[variable], suffix=f"{date:%Y%m%d}", flood=False)
73+
segment.regrid_tracer(glorys[variable], suffix=f"{date:%Y%m%d}", flood=False,
74+
time_attrs=time_attrs, time_encoding=time_encoding)
6875

6976
def concatenate_files(nsegments, output_dir, variables, ncrcat_names, first_date, last_date, adjust_timestamps=False):
7077
"""Concatenate annual files using ncrcat."""
@@ -93,16 +100,41 @@ def concatenate_files(nsegments, output_dir, variables, ncrcat_names, first_date
93100
adjust_file_timestamps(output_file)
94101

95102
def adjust_file_timestamps(file_path):
96-
"""Adjust timestamps for the first and last records in a file."""
97-
with xarray.open_dataset(file_path) as ds:
98-
if 'time' in ds:
99-
time = ds['time'].copy()
100-
adjusted_time = time.astype('datetime64[ns]')
101-
102-
adjusted_time[0] = adjusted_time[0].dt.floor('D')
103-
adjusted_time[-1] = adjusted_time[-1].dt.ceil('D')
103+
"""
104+
Adjust timestamps for the first and last records in a file while preserving attributes and raw numerical format.
105+
"""
106+
with xarray.open_dataset(file_path, decode_times=False) as ds:
107+
# Explicitly load the dataset into memory if it's lazy-loaded
108+
ds.load()
104109

105-
ds = ds.assign_coords(time=adjusted_time)
110+
if 'time' in ds:
111+
# Extract the time variable, attributes, and encoding
112+
time = ds['time']
113+
time_attrs = time.attrs # Save the original attributes
114+
time_encoding = time.encoding # Save the original encoding
115+
time_values = time.values.copy()
116+
117+
# Ensure the 'time' variable has more than one entry
118+
if len(time_values) > 1:
119+
# Adjust the first and last timestamps in raw numerical format
120+
time_values[0] = np.floor(time_values[0]) # Floor to the start of the day
121+
time_values[-1] = np.ceil(time_values[-1]) # Ceil to the end of the day
122+
123+
# Create a new DataArray for time while preserving attributes
124+
new_time = xarray.DataArray(
125+
time_values,
126+
dims=time.dims,
127+
attrs=time_attrs,
128+
name='time'
129+
)
130+
131+
# Assign the new time variable back to the dataset
132+
ds = ds.assign_coords(time=new_time)
133+
134+
# Reapply the original encoding to ensure consistency
135+
ds['time'].encoding = time_encoding
136+
137+
# Save the updated dataset
106138
ds.to_netcdf(file_path)
107139
print(f"Timestamps adjusted for {file_path}")
108140

0 commit comments

Comments
 (0)