xopr.cf_units

  1# TODO: This is entirely AI generated and unchecked.
  2# I just wanted something to quickly demonstrate what units might looks like.
  3# Should be carefully reviewed.
  4
  5import numpy as np
  6
  7
  8def apply_cf_compliant_attrs(ds):
  9    """
 10    Apply CF-compliant units and comments to radar echogram dataset variables.
 11
 12    Parameters
 13    ----------
 14    ds : xarray.Dataset
 15        The input radar echogram dataset.
 16
 17    Returns
 18    -------
 19    xarray.Dataset
 20        Dataset with CF-compliant attributes applied.
 21    """
 22
 23    # Create a copy to avoid modifying the original dataset
 24    ds_cf = ds.copy()
 25
 26    # Define CF-compliant attributes for coordinates
 27    coordinate_attrs = {
 28        'slow_time': {
 29            #'units': 'seconds since 1970-01-01T00:00:00Z',
 30            'standard_name': 'time',
 31            'long_name': 'slow time',
 32            'comment': 'Time coordinate for radar pulse transmission along flight track'
 33        },
 34        'twtt': {
 35            'units': 's',
 36            'standard_name': 'time',
 37            'long_name': 'two-way travel time',
 38            'comment': 'Two-way travel time from radar to target and back'
 39        }
 40    }
 41
 42    # Define CF-compliant attributes for data variables
 43    data_var_attrs = {
 44        'Bottom': {
 45            'units': 's',
 46            'long_name': 'bottom surface two-way travel time',
 47            'comment': 'Two-way travel time to detected bottom surface. NaN where bottom not detected.',
 48            '_FillValue': np.nan
 49        },
 50        'Data': {
 51            'units': '1',  # TODO: Appropriate units for radar data -- can we calibrate to watts?
 52            'long_name': 'radar echo power',
 53            'comment': 'Radar echo power in linear scale',
 54            'coordinates': 'slow_time twtt'
 55        },
 56        'Elevation': {
 57            'units': 'm',
 58            'standard_name': 'height_above_reference_ellipsoid',
 59            'long_name': 'platform elevation above WGS84 ellipsoid',
 60            'comment': 'GPS-derived elevation of radar platform above WGS84 reference ellipsoid'
 61        },
 62        'Heading': {
 63            'units': 'radians',
 64            'standard_name': 'platform_orientation',
 65            'long_name': 'platform heading angle',
 66            'comment': 'Platform heading angle in radians from north, clockwise positive',
 67            'valid_min': -np.pi,
 68            'valid_max': np.pi,
 69            'valid_range': [-np.pi, np.pi],
 70        },
 71        'Latitude': {
 72            'units': 'degrees_north',
 73            'standard_name': 'latitude',
 74            'long_name': 'platform latitude',
 75            'comment': 'GPS-derived latitude of radar platform in WGS84 coordinate system',
 76            'valid_min': -90.0,
 77            'valid_max': 90.0,
 78            'valid_range': [-90.0, 90.0]
 79        },
 80        'Longitude': {
 81            'units': 'degrees_east',
 82            'standard_name': 'longitude',
 83            'long_name': 'platform longitude',
 84            'comment': 'GPS-derived longitude of radar platform in WGS84 coordinate system',
 85            'valid_min': -180.0,
 86            'valid_max': 180.0,
 87            'valid_range': [-180.0, 180.0]
 88        },
 89        'Pitch': {
 90            'units': 'radians',
 91            'standard_name': 'platform_pitch_angle',
 92            'long_name': 'platform pitch angle',
 93            'comment': 'Platform pitch angle in radians, positive nose up',
 94            'valid_min': -np.pi/2,
 95            'valid_max': np.pi/2,
 96            'valid_range': [-np.pi/2, np.pi/2]
 97        },
 98        'Roll': {
 99            'units': 'radians',
100            'standard_name': 'platform_roll_angle',
101            'long_name': 'platform roll angle',
102            'comment': 'Platform roll angle in radians, positive right wing down',
103            'valid_min': -np.pi,
104            'valid_max': np.pi,
105            'valid_range': [-np.pi, np.pi]
106        },
107        'Surface': {
108            'units': 's',
109            'long_name': 'surface two-way travel time',
110            'comment': 'Two-way travel time to detected surface. Zero indicates surface at platform level.',
111            'valid_min': 0.0
112        }
113    }
114
115    # Apply coordinate attributes
116    for coord_name, attrs in coordinate_attrs.items():
117        if coord_name in ds_cf.coords:
118            ds_cf[coord_name].attrs.update(attrs)
119
120    # Apply data variable attributes
121    for var_name, attrs in data_var_attrs.items():
122        if var_name in ds_cf.data_vars:
123            ds_cf[var_name].attrs.update(attrs)
124
125    # Add global attributes for CF compliance
126    global_attrs = {
127        'Conventions': 'CF-1.8',
128        'title': 'Radar Echogram Data',
129        'institution': 'Open Polar Radar (OPR)',
130        'source': 'Airborne/ground-based radar sounder',
131        'history': f'Converted to CF-compliant format on {np.datetime64("now").astype(str)}',
132        'references': 'https://gitlab.com/openpolarradar/opr',
133        'comment': 'Polar radar echogram data with CF-compliant metadata',
134        'geospatial_lat_min': float(ds_cf.Latitude.min()) if 'Latitude' in ds_cf else None,
135        'geospatial_lat_max': float(ds_cf.Latitude.max()) if 'Latitude' in ds_cf else None,
136        'geospatial_lon_min': float(ds_cf.Longitude.min()) if 'Longitude' in ds_cf else None,
137        'geospatial_lon_max': float(ds_cf.Longitude.max()) if 'Longitude' in ds_cf else None,
138        'time_coverage_start': str(ds_cf.slow_time.min().values) if 'slow_time' in ds_cf else None,
139        'time_coverage_end': str(ds_cf.slow_time.max().values) if 'slow_time' in ds_cf else None
140    }
141
142    # Remove None values from global attributes
143    global_attrs = {k: v for k, v in global_attrs.items() if v is not None}
144
145    # Update global attributes
146    ds_cf.attrs.update(global_attrs)
147
148    return ds_cf
def apply_cf_compliant_attrs(ds):
  9def apply_cf_compliant_attrs(ds):
 10    """
 11    Apply CF-compliant units and comments to radar echogram dataset variables.
 12
 13    Parameters
 14    ----------
 15    ds : xarray.Dataset
 16        The input radar echogram dataset.
 17
 18    Returns
 19    -------
 20    xarray.Dataset
 21        Dataset with CF-compliant attributes applied.
 22    """
 23
 24    # Create a copy to avoid modifying the original dataset
 25    ds_cf = ds.copy()
 26
 27    # Define CF-compliant attributes for coordinates
 28    coordinate_attrs = {
 29        'slow_time': {
 30            #'units': 'seconds since 1970-01-01T00:00:00Z',
 31            'standard_name': 'time',
 32            'long_name': 'slow time',
 33            'comment': 'Time coordinate for radar pulse transmission along flight track'
 34        },
 35        'twtt': {
 36            'units': 's',
 37            'standard_name': 'time',
 38            'long_name': 'two-way travel time',
 39            'comment': 'Two-way travel time from radar to target and back'
 40        }
 41    }
 42
 43    # Define CF-compliant attributes for data variables
 44    data_var_attrs = {
 45        'Bottom': {
 46            'units': 's',
 47            'long_name': 'bottom surface two-way travel time',
 48            'comment': 'Two-way travel time to detected bottom surface. NaN where bottom not detected.',
 49            '_FillValue': np.nan
 50        },
 51        'Data': {
 52            'units': '1',  # TODO: Appropriate units for radar data -- can we calibrate to watts?
 53            'long_name': 'radar echo power',
 54            'comment': 'Radar echo power in linear scale',
 55            'coordinates': 'slow_time twtt'
 56        },
 57        'Elevation': {
 58            'units': 'm',
 59            'standard_name': 'height_above_reference_ellipsoid',
 60            'long_name': 'platform elevation above WGS84 ellipsoid',
 61            'comment': 'GPS-derived elevation of radar platform above WGS84 reference ellipsoid'
 62        },
 63        'Heading': {
 64            'units': 'radians',
 65            'standard_name': 'platform_orientation',
 66            'long_name': 'platform heading angle',
 67            'comment': 'Platform heading angle in radians from north, clockwise positive',
 68            'valid_min': -np.pi,
 69            'valid_max': np.pi,
 70            'valid_range': [-np.pi, np.pi],
 71        },
 72        'Latitude': {
 73            'units': 'degrees_north',
 74            'standard_name': 'latitude',
 75            'long_name': 'platform latitude',
 76            'comment': 'GPS-derived latitude of radar platform in WGS84 coordinate system',
 77            'valid_min': -90.0,
 78            'valid_max': 90.0,
 79            'valid_range': [-90.0, 90.0]
 80        },
 81        'Longitude': {
 82            'units': 'degrees_east',
 83            'standard_name': 'longitude',
 84            'long_name': 'platform longitude',
 85            'comment': 'GPS-derived longitude of radar platform in WGS84 coordinate system',
 86            'valid_min': -180.0,
 87            'valid_max': 180.0,
 88            'valid_range': [-180.0, 180.0]
 89        },
 90        'Pitch': {
 91            'units': 'radians',
 92            'standard_name': 'platform_pitch_angle',
 93            'long_name': 'platform pitch angle',
 94            'comment': 'Platform pitch angle in radians, positive nose up',
 95            'valid_min': -np.pi/2,
 96            'valid_max': np.pi/2,
 97            'valid_range': [-np.pi/2, np.pi/2]
 98        },
 99        'Roll': {
100            'units': 'radians',
101            'standard_name': 'platform_roll_angle',
102            'long_name': 'platform roll angle',
103            'comment': 'Platform roll angle in radians, positive right wing down',
104            'valid_min': -np.pi,
105            'valid_max': np.pi,
106            'valid_range': [-np.pi, np.pi]
107        },
108        'Surface': {
109            'units': 's',
110            'long_name': 'surface two-way travel time',
111            'comment': 'Two-way travel time to detected surface. Zero indicates surface at platform level.',
112            'valid_min': 0.0
113        }
114    }
115
116    # Apply coordinate attributes
117    for coord_name, attrs in coordinate_attrs.items():
118        if coord_name in ds_cf.coords:
119            ds_cf[coord_name].attrs.update(attrs)
120
121    # Apply data variable attributes
122    for var_name, attrs in data_var_attrs.items():
123        if var_name in ds_cf.data_vars:
124            ds_cf[var_name].attrs.update(attrs)
125
126    # Add global attributes for CF compliance
127    global_attrs = {
128        'Conventions': 'CF-1.8',
129        'title': 'Radar Echogram Data',
130        'institution': 'Open Polar Radar (OPR)',
131        'source': 'Airborne/ground-based radar sounder',
132        'history': f'Converted to CF-compliant format on {np.datetime64("now").astype(str)}',
133        'references': 'https://gitlab.com/openpolarradar/opr',
134        'comment': 'Polar radar echogram data with CF-compliant metadata',
135        'geospatial_lat_min': float(ds_cf.Latitude.min()) if 'Latitude' in ds_cf else None,
136        'geospatial_lat_max': float(ds_cf.Latitude.max()) if 'Latitude' in ds_cf else None,
137        'geospatial_lon_min': float(ds_cf.Longitude.min()) if 'Longitude' in ds_cf else None,
138        'geospatial_lon_max': float(ds_cf.Longitude.max()) if 'Longitude' in ds_cf else None,
139        'time_coverage_start': str(ds_cf.slow_time.min().values) if 'slow_time' in ds_cf else None,
140        'time_coverage_end': str(ds_cf.slow_time.max().values) if 'slow_time' in ds_cf else None
141    }
142
143    # Remove None values from global attributes
144    global_attrs = {k: v for k, v in global_attrs.items() if v is not None}
145
146    # Update global attributes
147    ds_cf.attrs.update(global_attrs)
148
149    return ds_cf

Apply CF-compliant units and comments to radar echogram dataset variables.

Parameters
  • ds (xarray.Dataset): The input radar echogram dataset.
Returns
  • xarray.Dataset: Dataset with CF-compliant attributes applied.