Skip to content

Commit d045489

Browse files
committed
Enhance metadata of produce files
1 parent 2fbf81b commit d045489

File tree

2 files changed

+55
-90
lines changed

2 files changed

+55
-90
lines changed

src/py_eddy_tracker/__init__.py

Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,8 @@ def parse_args(self, *args, **kwargs):
9999
units='days since 1950-01-01 00:00:00',
100100
calendar='proleptic_gregorian',
101101
axis='T',
102-
longname='time of gridded file',
103-
description='date of this observation',
104-
)
105-
),
106-
ocean_time=dict(
107-
attr_name=None,
108-
nc_name='ocean_time',
109-
nc_type='float64',
110-
nc_dims=('obs',),
111-
nc_attr=dict(
112-
units='ROMS ocean_time (seconds)',
102+
longname='Time',
103+
description='Date of this observation',
113104
)
114105
),
115106
type_cyc=dict(
@@ -121,7 +112,7 @@ def parse_args(self, *args, **kwargs):
121112
nc_attr=dict(
122113
longname='cyclonic',
123114
units='boolean',
124-
description='cyclonic -1; anti-cyclonic +1',
115+
description='Cyclonic -1; anti-cyclonic +1',
125116
)
126117
),
127118
segment_size=dict(
@@ -147,13 +138,15 @@ def parse_args(self, *args, **kwargs):
147138
),
148139
virtual=dict(
149140
attr_name=None,
150-
nc_name='virtual',
141+
nc_name='observation_flag',
142+
old_nc_name=['virtual'],
151143
nc_type='byte',
152144
nc_dims=('obs',),
153145
nc_attr=dict(
154146
longname='virtual_position',
155147
units='boolean',
156-
description='Virtual observation: 0 for real',
148+
description='Flag indicating if the value is interpolated between two'
149+
' observations or not (0: observed, 1: interpolated)',
157150
)
158151
),
159152
cost_association=dict(
@@ -176,7 +169,7 @@ def parse_args(self, *args, **kwargs):
176169
nc_attr=dict(
177170
units='degrees_east',
178171
axis='X',
179-
description='observation longitude',
172+
description='Observation longitude',
180173
longname='longitude of measurement',
181174
standard_name='longitude',
182175
)
@@ -193,7 +186,7 @@ def parse_args(self, *args, **kwargs):
193186
axis='Y',
194187
longname='latitude of measurement',
195188
standard_name='latitude',
196-
description='observation latitude',
189+
description='Observation latitude',
197190
)
198191
),
199192
lon_max=dict(
@@ -206,7 +199,7 @@ def parse_args(self, *args, **kwargs):
206199
nc_attr=dict(
207200
units='degrees_east',
208201
axis='X',
209-
description='observation longitude',
202+
description='Observation longitude',
210203
longname='longitude of amplitude max',
211204
standard_name='longitude',
212205
)
@@ -221,7 +214,7 @@ def parse_args(self, *args, **kwargs):
221214
nc_attr=dict(
222215
units='degrees_north',
223216
axis='Y',
224-
description='observation latitude',
217+
description='Observation latitude',
225218
longname='latitude of amplitude max',
226219
standard_name='latitude',
227220
)
@@ -237,7 +230,7 @@ def parse_args(self, *args, **kwargs):
237230
nc_attr=dict(
238231
longname='amplitude',
239232
units='m',
240-
description='magnitude of the height difference between the extremum of ADT within '
233+
description='Magnitude of the height difference between the extremum of ADT within '
241234
'the eddy and the ADT around the contour defining the eddy perimeter',
242235
)
243236
),
@@ -252,8 +245,7 @@ def parse_args(self, *args, **kwargs):
252245
nc_attr=dict(
253246
longname='maximum circum-averaged speed',
254247
units='m/s',
255-
description='average speed of the contour defining the '
256-
'speed radius',
248+
description='Average speed of the contour defining the radius scale “speed_radius”',
257249
)
258250
),
259251
uavg_profile=dict(
@@ -266,7 +258,7 @@ def parse_args(self, *args, **kwargs):
266258
nc_attr=dict(
267259
longname='radial profile of uavg',
268260
units='m/s',
269-
description='profile speed average values from effective contour inwards to smallest inner contour',
261+
description='Speed average values from effective contour inwards to smallest inner contour',
270262
)
271263
),
272264
i=dict(
@@ -276,7 +268,7 @@ def parse_args(self, *args, **kwargs):
276268
nc_dims=('obs',),
277269
nc_attr=dict(
278270
longname='longitude index in the grid of the detection',
279-
description='longitude index in the grid of the detection',
271+
description='Longitude index in the grid of the detection',
280272
)
281273
),
282274
j=dict(
@@ -286,7 +278,7 @@ def parse_args(self, *args, **kwargs):
286278
nc_dims=('obs',),
287279
nc_attr=dict(
288280
longname='latitude index in the grid of the detection',
289-
description='latitude index in the grid of the detection',
281+
description='Latitude index in the grid of the detection',
290282
)
291283
),
292284
eke=dict(
@@ -297,7 +289,7 @@ def parse_args(self, *args, **kwargs):
297289
nc_attr=dict(
298290
longname='sum EKE within contour Ceff',
299291
units='m^2/s^2',
300-
description='sum of eddy kinetic energy within contour '
292+
description='Sum of eddy kinetic energy within contour '
301293
'defining the effective radius',
302294
)
303295
),
@@ -312,7 +304,7 @@ def parse_args(self, *args, **kwargs):
312304
nc_attr=dict(
313305
longname='effective radius scale',
314306
units='m',
315-
description='radius of a circle whose area is equal to that enclosed by the effective contour',
307+
description='Radius of a circle whose area is equal to that enclosed by the effective contour',
316308
)
317309
),
318310
radius_s=dict(
@@ -326,7 +318,7 @@ def parse_args(self, *args, **kwargs):
326318
nc_attr=dict(
327319
longname='speed radius scale',
328320
units='m',
329-
description='radius of a circle whose area is equal to that enclosed by the contour of maximum circum-average speed',
321+
description='Radius of a circle whose area is equal to that enclosed by the contour of maximum circum-average speed',
330322
)
331323
),
332324
track=dict(
@@ -337,7 +329,7 @@ def parse_args(self, *args, **kwargs):
337329
nc_attr=dict(
338330
longname='track number',
339331
units='ordinal',
340-
description='eddy identification number',
332+
description='Eddy identification number',
341333
)
342334
),
343335
n=dict(
@@ -349,7 +341,7 @@ def parse_args(self, *args, **kwargs):
349341
nc_attr=dict(
350342
longname='observation number',
351343
units='ordinal',
352-
description='observation sequence number, days from eddy start',
344+
description='Observation sequence number, days from eddy first detection',
353345
)
354346
),
355347
contour_lon_e=dict(
@@ -363,7 +355,7 @@ def parse_args(self, *args, **kwargs):
363355
nc_dims=('obs', 'NbSample'),
364356
nc_attr=dict(
365357
longname='effective contour longitudes',
366-
description='longitudes of effective contour',
358+
description='Longitudes of effective contour',
367359
units='degrees_east',
368360
axis='X',
369361
)
@@ -378,7 +370,7 @@ def parse_args(self, *args, **kwargs):
378370
nc_dims=('obs', 'NbSample'),
379371
nc_attr=dict(
380372
longname='effective contour latitudes',
381-
description='latitudes of effective contour',
373+
description='Latitudes of effective contour',
382374
units='degrees_east',
383375
axis='X',
384376
)
@@ -394,7 +386,7 @@ def parse_args(self, *args, **kwargs):
394386
nc_dims=('obs', 'NbSample'),
395387
nc_attr=dict(
396388
longname='speed contour longitudes',
397-
description='longitudes of speed contour',
389+
description='Longitudes of speed contour',
398390
units='degrees_east',
399391
axis='X',
400392
)
@@ -409,7 +401,7 @@ def parse_args(self, *args, **kwargs):
409401
nc_dims=('obs', 'NbSample'),
410402
nc_attr=dict(
411403
longname='speed contour latitudes',
412-
description='latitudes of speed contour',
404+
description='Latitudes of speed contour',
413405
units='degrees_east',
414406
axis='X',
415407
)
@@ -480,11 +472,14 @@ def parse_args(self, *args, **kwargs):
480472
),
481473
nb_contour_selected=dict(
482474
attr_name=None,
483-
nc_name='nb_contour_selected',
475+
nc_name='num_contours',
476+
old_nc_name=['nb_contour_selected'],
484477
nc_type='u2',
485478
nc_dims=('obs',),
486479
nc_attr=dict(
487-
units='1',
480+
longname='number of contour',
481+
units='ordinal',
482+
description='Number of contour selected for this eddy',
488483
)
489484
),
490485
)

src/py_eddy_tracker/observations.py

Lines changed: 25 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929
"""
3030
from numpy import zeros, empty, absolute, arange, where, unique, \
3131
ma, concatenate, cos, radians, isnan, ones, ndarray, \
32-
interp, floor
32+
interp, floor, array
3333
from netCDF4 import Dataset
3434
from .generic import distance_grid, distance
3535
from shapely.geometry import Polygon
3636
from shapely.geos import TopologicalError
3737
from . import VAR_DESCR, VAR_DESCR_inv
3838
import logging
39-
from datetime import datetime
39+
from datetime import datetime, timedelta
4040
from numba import njit, types as numba_types
4141

4242

@@ -627,8 +627,9 @@ def to_netcdf(self, handler):
627627
handler.array_variables = ','.join(self.array_variables)
628628
# Iter on variables to create:
629629
fields = [field[0] for field in self.observations.dtype.descr]
630-
fields.sort()
631-
for ori_name in fields:
630+
fields_ = array([VAR_DESCR[field[0]]['nc_name'] for field in self.observations.dtype.descr])
631+
i = fields_.argsort()
632+
for ori_name in array(fields)[i]:
632633
# Patch for a transition
633634
name = ori_name
634635
#
@@ -643,20 +644,7 @@ def to_netcdf(self, handler):
643644
scale_factor=VAR_DESCR[name].get('scale_factor', None),
644645
add_offset=VAR_DESCR[name].get('add_offset', None)
645646
)
646-
# Add cyclonic information
647-
if self.sign_type is not None:
648-
self.create_variable(
649-
handler,
650-
dict(varname=VAR_DESCR['type_cyc']['nc_name'],
651-
datatype=VAR_DESCR['type_cyc']['nc_type'],
652-
dimensions=VAR_DESCR['type_cyc']['nc_dims']),
653-
VAR_DESCR['type_cyc']['nc_attr'],
654-
self.sign_type)
655-
656-
handler.Metadata_Conventions = 'Unidata Dataset Discovery v1.0'
657-
handler.comment = 'Surface product; mesoscale eddies'
658-
handler.framework_used = 'https://bitbucket.org/emason/py-eddy-tracker'
659-
handler.standard_name_vocabulary ='NetCDF Climate and Forecast (CF) Metadata Convention Standard Name Table'
647+
self.set_global_attr_netcdf(handler)
660648

661649
def create_variable(self, handler_nc, kwargs_variable, attr_variable,
662650
data, scale_factor=None, add_offset=None):
@@ -692,41 +680,14 @@ def write_netcdf(self, path='./', filename='%(path)s/%(sign_type)s.nc'):
692680
eddy_size = len(self.observations)
693681
filename = filename % dict(path=path, sign_type=self.sign_legend, prod_time=datetime.now().strftime('%Y%m%d'))
694682
logging.info('Store in %s', filename)
695-
with Dataset(filename, 'w', format='NETCDF4') as h_nc:
696-
logging.info('Create file %s', filename)
697-
# Create dimensions
698-
logging.debug('Create Dimensions "obs" : %d', eddy_size)
699-
h_nc.createDimension('obs', eddy_size)
700-
if self.track_array_variables != 0:
701-
h_nc.createDimension('NbSample', self.track_array_variables)
702-
# Iter on variables to create:
703-
for field in self.observations.dtype.descr:
704-
name = field[0]
705-
logging.debug('Create Variable %s', VAR_DESCR[name]['nc_name'])
706-
self.create_variable(
707-
h_nc,
708-
dict(varname=VAR_DESCR[name]['nc_name'],
709-
datatype=VAR_DESCR[name]['output_type'],
710-
dimensions=VAR_DESCR[name]['nc_dims']),
711-
VAR_DESCR[name]['nc_attr'],
712-
self.observations[name],
713-
scale_factor=VAR_DESCR[name].get('scale_factor', None),
714-
add_offset=VAR_DESCR[name].get('add_offset', None)
715-
)
716-
717-
# Add cyclonic information
718-
self.create_variable(
719-
h_nc,
720-
dict(varname=VAR_DESCR['type_cyc']['nc_name'],
721-
datatype=VAR_DESCR['type_cyc']['nc_type'],
722-
dimensions=VAR_DESCR['type_cyc']['nc_dims']),
723-
VAR_DESCR['type_cyc']['nc_attr'],
724-
self.sign_type)
725-
# Global attr
726-
self.set_global_attr_netcdf(h_nc)
683+
with Dataset(filename, 'w', format='NETCDF4') as handler:
684+
self.to_netcdf(handler)
727685

728686
def set_global_attr_netcdf(self, h_nc):
729-
pass
687+
h_nc.Metadata_Conventions = 'Unidata Dataset Discovery v1.0'
688+
h_nc.comment = 'Surface product; mesoscale eddies'
689+
h_nc.framework_used = 'https://bitbucket.org/emason/py-eddy-tracker'
690+
h_nc.standard_name_vocabulary ='NetCDF Climate and Forecast (CF) Metadata Convention Standard Name Table'
730691

731692
def display(self, ax, ref=None, **kwargs):
732693
if ref is None:
@@ -875,7 +836,16 @@ def elements(self):
875836
def set_global_attr_netcdf(self, h_nc):
876837
"""Set global attr
877838
"""
878-
if self.sign_type == -1:
879-
h_nc.title = 'Cyclonic'
880-
else:
881-
h_nc.title = 'Anticyclonic' + ' eddy tracks'
839+
h_nc.title = 'Cyclonic' if self.sign_type == -1 else 'Anticyclonic'
840+
h_nc.Metadata_Conventions = 'Unidata Dataset Discovery v1.0'
841+
h_nc.comment = 'Surface product; mesoscale eddies'
842+
h_nc.framework_used = 'https://bitbucket.org/emason/py-eddy-tracker'
843+
h_nc.standard_name_vocabulary = 'NetCDF Climate and Forecast (CF) Metadata Convention Standard Name Table'
844+
h_nc.date_created = datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')
845+
t = h_nc.variables[VAR_DESCR_inv['j1']]
846+
delta = t.max - t.min + 1
847+
h_nc.time_coverage_duration = 'P%dD' % delta
848+
d_start = datetime(1950, 1, 1) + timedelta(int(t.min))
849+
d_end = datetime(1950, 1, 1) + timedelta(int(t.max))
850+
h_nc.time_coverage_start = d_start.strftime('%Y-%m-%dT00:00:00Z')
851+
h_nc.time_coverage_end = d_end.strftime('%Y-%m-%dT00:00:00Z')

0 commit comments

Comments
 (0)