""" Cython wrapper around the NASA TRMM RSL library. """ cimport pyart.io._rsl_h as _rsl_h # the next line is required so that RSL_F_LIST and RSL_INVF_LIST can be # properly wrapped as Cython does not export the typedef from _rsl_h # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings] ctypedef unsigned short Range import numpy as np cimport numpy as np from datetime import datetime, timedelta _RSL_VERSION_STR = _rsl_h._RSL_VERSION_STR cpdef copy_volume(_RslVolume volume): """ copy_volume(volume) Return a copy of a _RslVolume object. Parameters ---------- volume : _RslVolume _RslVolume object to create a copy of. Returns ------- nvolume : _RslVolume Copy of volume. """ volume_copy = _rsl_h.RSL_copy_volume(volume._Volume) rslvolume = _RslVolume() rslvolume.load(volume_copy) rslvolume._dealloc = 1 return rslvolume cpdef create_volume( np.ndarray[np.float32_t, ndim=2] arr, np.ndarray[np.int32_t, ndim=1] rays_per_sweep, int vol_num=1): """ create_volume(arr, rays_per_sweep, vol_num=1) Create a _RslVolume object from a 2D float32 array. No headers parameters except nsweeps, nrays and nbins are not set in the resulting _RslVolume object. Parameters ---------- arr : array, 2D, float32 Two dimensional float32 array. rays_per_sweep: array, 1D, int32 Array listing number of rays in each sweep. vol_num : int Volume number used to set f and invf in the header. The default is for velocity fields. Useful values are 0 for reflectivity and 1 for velocity. Returns ------- volumes : _RslVolume _RslVolume containing array data. """ # these variables can be moved to the module level if used elsewhere cdef (float (*)(_rsl_h.Range) noexcept) * RSL_F_LIST = [ _rsl_h.DZ_F, _rsl_h.VR_F, _rsl_h.SW_F, _rsl_h.CZ_F, _rsl_h.ZT_F, _rsl_h.DR_F, _rsl_h.LR_F, _rsl_h.ZD_F, _rsl_h.DM_F, _rsl_h.RH_F, _rsl_h.PH_F, _rsl_h.XZ_F, _rsl_h.CD_F, _rsl_h.MZ_F, _rsl_h.MD_F, _rsl_h.ZE_F, _rsl_h.VE_F, _rsl_h.KD_F, _rsl_h.TI_F, _rsl_h.DX_F, _rsl_h.CH_F, _rsl_h.AH_F, _rsl_h.CV_F, _rsl_h.AV_F, _rsl_h.SQ_F, _rsl_h.VS_F, _rsl_h.VL_F, _rsl_h.VG_F, _rsl_h.VT_F, _rsl_h.NP_F, _rsl_h.HC_F, _rsl_h.VC_F, _rsl_h.VR_F, _rsl_h.SW_F, _rsl_h.VR_F, _rsl_h.SW_F, _rsl_h.DZ_F, _rsl_h.CZ_F, _rsl_h.PH_F, _rsl_h.SD_F, _rsl_h.DZ_F, _rsl_h.DZ_F] cdef (_rsl_h.Range (*)(float) noexcept) * RSL_INVF_LIST = [ _rsl_h.DZ_INVF, _rsl_h.VR_INVF, _rsl_h.SW_INVF, _rsl_h.CZ_INVF, _rsl_h.ZT_INVF, _rsl_h.DR_INVF, _rsl_h.LR_INVF, _rsl_h.ZD_INVF, _rsl_h.DM_INVF, _rsl_h.RH_INVF, _rsl_h.PH_INVF, _rsl_h.XZ_INVF, _rsl_h.CD_INVF, _rsl_h.MZ_INVF, _rsl_h.MD_INVF, _rsl_h.ZE_INVF, _rsl_h.VE_INVF, _rsl_h.KD_INVF, _rsl_h.TI_INVF, _rsl_h.DX_INVF, _rsl_h.CH_INVF, _rsl_h.AH_INVF, _rsl_h.CV_INVF, _rsl_h.AV_INVF, _rsl_h.SQ_INVF, _rsl_h.VS_INVF, _rsl_h.VL_INVF, _rsl_h.VG_INVF, _rsl_h.VT_INVF, _rsl_h.NP_INVF, _rsl_h.HC_INVF, _rsl_h.VC_INVF, _rsl_h.VR_INVF, _rsl_h.SW_INVF, _rsl_h.VR_INVF, _rsl_h.SW_INVF, _rsl_h.DZ_INVF, _rsl_h.CZ_INVF, _rsl_h.PH_INVF, _rsl_h.SD_INVF, _rsl_h.DZ_INVF, _rsl_h.DZ_INVF] cdef _rsl_h.Volume * volume cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray cdef int ray_i nsweeps = rays_per_sweep.shape[0] nbins = arr.shape[1] volume = _rsl_h.RSL_new_volume(nsweeps) volume.h.nsweeps = nsweeps ray_index = 0 for nsweep in range(nsweeps): nrays = rays_per_sweep[nsweep] sweep = _rsl_h.RSL_new_sweep(nrays) volume.sweep[nsweep] = sweep sweep.h.nrays = nrays for nray in range(nrays): ray = _rsl_h.RSL_new_ray(nbins) sweep.ray[nray] = ray ray.h.nbins = nbins ray.h.f = RSL_F_LIST[vol_num] ray.h.invf = RSL_INVF_LIST[vol_num] for nbin in range(nbins): ray.range[nbin] = ray.h.invf(arr[ray_index, nbin]) ray_index += 1 rslvolume = _RslVolume() rslvolume.load(volume) rslvolume._dealloc = 1 return rslvolume cpdef _label_volume(_RslVolume volume, radar): """ _label_volume(volume, radar) Add labels for dealiasing to a _RslVolume object from a radar object. This function does not set all parameter in the _RslVolume suitable for writing out the volume, rather it set those parameters which must be set prior to using :py:func:`pyart.correct._fourdd_interface.fourdd_dealias`. Parameters ---------- volume : _RslVolume Volume object to which parameters will be set as needed prior to dealiasing. Object is manipulated in-place. radar : Radar Radar object from which parameters are taken. """ cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray cdef int ray_index vol = volume._Volume nsweeps = vol.h.nsweeps nbins = vol.sweep[0].ray[0].h.nbins gate_size = int(radar.range['meters_between_gates']) range_bin1 = int(radar.range['meters_to_center_of_first_gate']) if 'shape' in dir(radar.altitude['data']): if radar.altitude['data'].shape == (): alt = float(radar.altitude['data']) else: alt = radar.altitude['data'][0] else: alt = radar.altitude['data'] nyq_vels = radar.instrument_parameters['nyquist_velocity']['data'] azimuths = radar.azimuth['data'] elevs = radar.elevation['data'] # label the volume ray_index = 0 vol.h.nsweeps = nsweeps for nsweep in range(nsweeps): sweep = vol.sweep[nsweep] nrays = sweep.h.nrays for nray in range(nrays): ray = sweep.ray[nray] ray.h.azimuth = azimuths[ray_index] ray.h.elev = elevs[ray_index] ray.h.nyq_vel = nyq_vels[ray_index] ray.h.range_bin1 = range_bin1 ray.h.gate_size = gate_size ray.h.alt = alt ray_index += 1 return cdef class _RslRay: """ A object for accessing RSL Ray data and header information This class should not be initalized from within Python. _RslRay object are returned from the :py:func:`_RslSweep.get_ray` method. Attributes ---------- month : int Date for this ray, month (1-12). day : int Date for this ray, day (1-31). year : int Date for this ray, year (eg. 1993). hour : int Time for this ray, hour (0-23). minute : int Time for this ray, minute (0-59). sec : float Time for this ray, second + fractor of second. unam_rng : float Unambiguous range in km. azimuth : float Mean azimuth angle in degrees for the ray, must be positive. 0 for north, 90 for east, 270 for west. ray_num : int Ray number within a scan. elev : float Elevation angle in degrees. elev_num : int Elevation number within the volume scan. range_bin1 : int Range to first gate in meters. gate_size : int Gate size in meters. vel_res : float Doppler velocity resolution. sweep_rate : float Sweep rate, full sweeps / minute. prf : int Pulse repetition frequency in Hz. prf2 : int Second pulse repition frequenct for dual PRF data. azim_rate : float Sweep rate in degrees / second. fix_angle : float Elevation angle for the sweep in degrees. pitch : float Pitch angle. roll : float Roll angle. heading : float Heading. pitch_rate : float Pitch rate in angle / sec. roll_rate : float Roll rate in angle / sec. heading_rate : float Heading rate in angle / sec. lat : float Latitude in degrees. lon : float Longitude in degrees. alt : int Altitude in meters. rvs : float Radial velocity correction in meters / second. vel_east : float Platform velocity to the east in meters / second. Negative values for velocity to the west. vel_north : float Platform velocity to the north in meters / second. Negative values for velocity to the south. vel_up : float Platform velocity upward in meters / second. Negative values for velocity downward. pulse_count : int Pulses used in a single dwell time. pulse_width : float Pulse width in microseconds. beam_width : float Beamwidth in degrees. frequency : float Carrier frequency in GHz. wavelength : float Wavelength in meters. nyq_vel : float Nyquist velocity in meters / second. nbins : int Number of array elements in ray data. """ cdef _rsl_h.Ray * _Ray cdef int _dealloc def __dealloc__(self): if self._dealloc == 1: _rsl_h.RSL_free_ray(self._Ray) cdef load(self, _rsl_h.Ray * Ray): """ Load the _RslRay object, must be called after creation. """ if Ray is NULL: raise ValueError('cannot load _RslRay with NULL') self._Ray = Ray self._dealloc = 0 def get_datetime(self): """ get_datetime() Return a datetime describing the date and time of the ray. """ s = self full_seconds, fractional_seconds = divmod(s.sec, 1) microseconds = int(fractional_seconds * 1e6) # Some UF writers incorrectly specify midnight as 24:00:00 rather # than 00:00:00. Handle this case explicitly if s.hour == 24: s.hour = 23 s.minute = 0 full_seconds = 0 dt = datetime(s.year, s.month, s.day, s.hour, s.minute, full_seconds, microseconds) return dt + timedelta(seconds=1) return datetime(s.year, s.month, s.day, s.hour, s.minute, int(full_seconds), microseconds) def get_data(self): """ get_data() Return the one-dimensional data contained in the ray. """ cdef _rsl_h.Range raw cdef np.ndarray[np.float32_t, ndim = 1] data shape = (self._Ray.h.nbins) data = np.zeros(shape, dtype='float32') + 1.31072000e+05 for nbin in range(self._Ray.h.nbins): raw = self._Ray.range[nbin] data[nbin] = self._Ray.h.f(raw) return data # header properties mapped to class attributes. property month: def __get__(self): return self._Ray.h.month def __set__(self, int month): self._Ray.h.month = month property day: def __get__(self): return self._Ray.h.day def __set__(self, int day): self._Ray.h.day = day property year: def __get__(self): return self._Ray.h.year def __set__(self, int year): self._Ray.h.year = year property hour: def __get__(self): return self._Ray.h.hour def __set__(self, int hour): self._Ray.h.hour = hour property minute: def __get__(self): return self._Ray.h.minute def __set__(self, int minute): self._Ray.h.minute = minute property sec: def __get__(self): return self._Ray.h.sec def __set__(self, float sec): self._Ray.h.sec = sec property unam_rng: def __get__(self): return self._Ray.h.unam_rng def __set__(self, float unam_rng): self._Ray.h.unam_rng = unam_rng property azimuth: def __get__(self): return self._Ray.h.azimuth def __set__(self, float azimuth): self._Ray.h.azimuth = azimuth property ray_num: def __get__(self): return self._Ray.h.ray_num def __set__(self, int ray_num): self._Ray.h.ray_num = ray_num property elev: def __get__(self): return self._Ray.h.elev def __set__(self, float elev): self._Ray.h.elev = elev property elev_num: def __get__(self): return self._Ray.h.elev_num def __set__(self, int elev_num): self._Ray.h.elev_num = elev_num property range_bin1: def __get__(self): return self._Ray.h.range_bin1 def __set__(self, int range_bin1): self._Ray.h.range_bin1 = range_bin1 property gate_size: def __get__(self): return self._Ray.h.gate_size def __set__(self, int gate_size): self._Ray.h.gate_size = gate_size property vel_res: def __get__(self): return self._Ray.h.vel_res def __set__(self, float vel_res): self._Ray.h.vel_res = vel_res property sweep_rate: def __get__(self): return self._Ray.h.sweep_rate def __set__(self, float sweep_rate): self._Ray.h.sweep_rate = sweep_rate property prf: def __get__(self): return self._Ray.h.prf def __set__(self, int prf): self._Ray.h.prf = prf property prf2: def __get__(self): return self._Ray.h.prf2 def __set__(self, int prf2): self._Ray.h.prf2 = prf2 property azim_rate: def __get__(self): return self._Ray.h.azim_rate def __set__(self, float azim_rate): self._Ray.h.azim_rate = azim_rate property fix_angle: def __get__(self): return self._Ray.h.fix_angle def __set__(self, float fix_angle): self._Ray.h.fix_angle = fix_angle property pitch: def __get__(self): return self._Ray.h.pitch def __set__(self, float pitch): self._Ray.h.pitch = pitch property roll: def __get__(self): return self._Ray.h.roll def __set__(self, float roll): self._Ray.h.roll = roll property heading: def __get__(self): return self._Ray.h.heading def __set__(self, float heading): self._Ray.h.heading = heading property pitch_rate: def __get__(self): return self._Ray.h.pitch_rate def __set__(self, float pitch_rate): self._Ray.h.pitch_rate = pitch_rate property roll_rate: def __get__(self): return self._Ray.h.roll_rate def __set__(self, float roll_rate): self._Ray.h.roll_rate = roll_rate property heading_rate: def __get__(self): return self._Ray.h.heading_rate def __set__(self, float heading_rate): self._Ray.h.heading_rate = heading_rate property lat: def __get__(self): return self._Ray.h.lat def __set__(self, float lat): self._Ray.h.lat = lat property lon: def __get__(self): return self._Ray.h.lon def __set__(self, float lon): self._Ray.h.lon = lon property alt: def __get__(self): return self._Ray.h.alt def __set__(self, int alt): self._Ray.h.alt = alt property rvc: def __get__(self): return self._Ray.h.rvc def __set__(self, float rvc): self._Ray.h.rvc = rvc property vel_east: def __get__(self): return self._Ray.h.vel_east def __set__(self, float vel_east): self._Ray.h.vel_east = vel_east property vel_north: def __get__(self): return self._Ray.h.vel_north def __set__(self, float vel_north): self._Ray.h.vel_north = vel_north property vel_up: def __get__(self): return self._Ray.h.vel_up def __set__(self, float vel_up): self._Ray.h.vel_up = vel_up property pulse_count: def __get__(self): return self._Ray.h.pulse_count def __set__(self, int pulse_count): self._Ray.h.pulse_count = pulse_count property pulse_width: def __get__(self): return self._Ray.h.pulse_width def __set__(self, float pulse_width): self._Ray.h.pulse_width = pulse_width property beam_width: def __get__(self): return self._Ray.h.beam_width def __set__(self, float beam_width): self._Ray.h.beam_width = beam_width property frequency: def __get__(self): return self._Ray.h.frequency def __set__(self, float frequency): self._Ray.h.frequency = frequency property wavelength: def __get__(self): return self._Ray.h.wavelength def __set__(self, float wavelength): self._Ray.h.wavelength = wavelength property nyq_vel: def __get__(self): return self._Ray.h.nyq_vel def __set__(self, float nyq_vel): self._Ray.h.nyq_vel = nyq_vel property nbins: def __get__(self): return self._Ray.h.nbins def __set__(self, int nbins): self._Ray.h.nbins = nbins cdef class _RslSweep: """ A object for accessing RSL Sweep data and header information. This class should not be initalized from within Python. _RslSweep objects are returned from the :py:func:`_RslVolume.get_sweep` method. Attributes ---------- sweep_num : int Interger sweep number. elev : float Mean elevation angle for thr sweep. -999.0 for RHI sweeps. azimuth : float Azumuth for the sweep. -999.0 for PPI scans. beam_width : float Beam width in degrees. Can also be found in _RslRay objects. vert_half_bw : float Vertical beam width divided by 2. horz_half_bw : float Horizontal beam width divided by 2. nrays : int Number of rays in the sweep. """ cdef _rsl_h.Sweep * _Sweep cdef int _dealloc def __dealloc__(self): if self._dealloc == 1: _rsl_h.RSL_free_sweep(self._Sweep) cdef load(self, _rsl_h.Sweep * Sweep): """ Load the _RslSweep object, must be called after creation. """ if Sweep is NULL: raise ValueError("cannot load _RslSweep with NULL") self._Sweep = Sweep self._dealloc = 0 def get_ray(self, int ray_number): """ get_ray(ray_number) Return a _RslRay for a given ray. Parameters ---------- ray_number : int Ray number to retrieve Returns ------- ray : _RslRay _RslRay object containing the requested ray. """ if ray_number < 0 or ray_number >= self._Sweep.h.nrays: raise ValueError('invalid ray_number') rslray = _RslRay() rslray.load(self._Sweep.ray[ray_number]) return rslray def get_data(self): """ get_data() Return the two-dimensional data contained in the sweep. If a given ray has few bins than the first ray, the missing bins will be filled with 131072.0 """ cdef _rsl_h.Range raw cdef _rsl_h.Ray * ray cdef np.ndarray[np.float32_t, ndim = 2] data sweep = self._Sweep nrays = sweep.h.nrays nbins = sweep.ray[0].h.nbins shape = (nrays, nbins) data = np.zeros(shape, dtype='float32') + 1.31072000e+05 for nray in range(nrays): ray = sweep.ray[nray] assert ray is not NULL nbins = ray.h.nbins for nbin in range(nbins): raw = ray.range[nbin] data[nray, nbin] = ray.h.f(raw) return data # header properties mapped to class attributes. property sweep_num: def __get__(self): return self._Sweep.h.sweep_num def __set__(self, int sweep_num): self._Sweep.h.sweep_num = sweep_num property elev: def __get__(self): return self._Sweep.h.elev def __set__(self, float elev): self._Sweep.h.elev = elev property azimuth: def __get__(self): return self._Sweep.h.azimuth def __set__(self, float azimuth): self._Sweep.h.azimuth = azimuth property beam_width: def __get__(self): return self._Sweep.h.beam_width def __set__(self, float beam_width): self._Sweep.h.beam_width = beam_width property vert_half_bw: def __get__(self): return self._Sweep.h.vert_half_bw def __set__(self, float vert_half_bw): self._Sweep.h.vert_half_bw = vert_half_bw property horz_half_bw: def __get__(self): return self._Sweep.h.horz_half_bw def __set__(self, float horz_half_bw): self._Sweep.h.horz_half_bw = horz_half_bw property nrays: def __get__(self): return self._Sweep.h.nrays def __set__(self, int nrays): self._Sweep.h.nrays = nrays cdef class _RslVolume: """ A object for accessing RSL Volume data and header information. This class should not be initalized from within Python. _RslVolume objects are returned from the :py:func:`RslFile.get_volume` and other functions/methods. Attributes ---------- nsweeps : int Sweep number. calibr_const : float Calibration constant. """ def __dealloc__(self): if self._dealloc == 1: _rsl_h.RSL_free_volume(self._Volume) cdef load(self, _rsl_h.Volume * Volume): """ Load the _RslVolume object, must be called after creation. """ if Volume is NULL: raise ValueError('cannot load _RslVolume with NULL') self._Volume = Volume self._dealloc = 0 def total_rays(self): """ total_rays() Return the total number of rays present in all sweeps of the volume. """ return np.sum(self.get_nray_array()) def get_nray_array(self): """ get_nray_array() Return an array of the number of rays for each sweep. """ cdef _rsl_h.Sweep * sweep nrays = np.empty((self.nsweeps), dtype='int32') for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL nrays[i] = sweep.h.nrays return nrays def get_sweep(self, int sweep_number): """ get_sweep(sweep_numer) Return a _RslSweep for a given sweep number. Parameters ---------- sweep_number : int Sweep number to retrieve Returns ------- sweep : _RslSweep _RslSweep object containing the requested sweep. """ if sweep_number < 0 or sweep_number >= self._Volume.h.nsweeps: raise ValueError('invalid sweep_number') rslsweep = _RslSweep() rslsweep.load(self._Volume.sweep[sweep_number]) return rslsweep def get_azimuth_and_elev_array(self): """ get_azimuth_and_elev_array() Return azimuth and elevation array for each sweep and ray. """ cdef int nrays = self._Volume.sweep[0].h.nrays cdef int ray_count cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray # create empty azimuth and elev output arrays total_rays = self.total_rays() azimuth = np.empty([total_rays], dtype='float32') elev = np.empty([total_rays], dtype='float32') # loop over the sweeps and rays storing azimuth and elev ray_count = 0 for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL nrays = sweep.h.nrays for j in range(nrays): ray = sweep.ray[j] assert ray is not NULL azimuth[ray_count + j] = ray.h.azimuth elev[ray_count + j] = ray.h.elev ray_count += nrays return azimuth, elev def get_sweep_fix_angles(self): """ get_sweep_fix_angles() Return array of fix angle for each sweep. Angles determined from the first ray in each sweep. """ cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray fix_angles = np.empty((self.nsweeps), dtype='float32') for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL ray = sweep.ray[0] assert ray is not NULL fix_angles[i] = ray.h.fix_angle return fix_angles def get_sweep_azimuths(self): """ get_sweep_azimuths() Return azimuth array for each sweep. """ cdef _rsl_h.Sweep * sweep azimuth = np.empty((self.nsweeps), dtype='float32') for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL azimuth[i] = sweep.h.azimuth return azimuth def get_sweep_elevs(self): """ get_sweep_elevs() Return elevation array for each sweep. """ cdef _rsl_h.Sweep * sweep elev = np.empty((self.nsweeps), dtype='float32') for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL elev[i] = sweep.h.elev return elev def get_instr_params(self): """ get_instr_params() Return instrumental parameter for the volume. Returns ------- pm_data : array, (nsweeps) Array of prt modes. nv_data : array, (total_rays) Array of nyquist velocities. pr_data : array, (total_rays) Array of pulse repetition frequency in Hz. ur_data : array, (total_rays) Array of unambiguous ranges, in km. """ cdef int nrays = self._Volume.sweep[0].h.nrays cdef int ray_count cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray # calculate the total number of rays in the volume # initalize empty instrument parameter arrays total_rays = self.total_rays() nyq_vel = self._Volume.sweep[0].ray[0].h.nyq_vel valid_nyq_vel = abs(nyq_vel) > 0.1 pm_data = np.empty(self.nsweeps, dtype='|S24') nv_data = np.empty((total_rays), dtype='float32') pr_data = np.empty((total_rays), dtype='float32') ur_data = np.empty((total_rays), dtype='float32') # loop over sweeps and rays storing instrument parameters ray_count = 0 for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL nrays = sweep.h.nrays for j in range(nrays): ray = sweep.ray[j] assert ray is not NULL if j == 0: pm_data[i] = self._prtmode(ray.h) if valid_nyq_vel: nv_data[ray_count + j] = ray.h.nyq_vel else: nv_data[ray_count + j] = (ray.h.wavelength * ray.h.prf / 4.0) if ray.h.prf == 0: pr_data[ray_count + j] = -999. else: pr_data[ray_count + j] = 1. / ray.h.prf ur_data[ray_count + j] = ray.h.unam_rng * 1000.0 ray_count += nrays return pm_data, nv_data, pr_data, ur_data def get_data(self): """ get_data() Return the two-dimensional data contained in the volume. If a given ray has few bins than the first ray, the missing bins will be filled with 131072.0 """ cdef _rsl_h.Range raw cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray cdef int ray_count, nsweeps, nrays, nbins, nray, nsweep, nbin cdef np.ndarray[np.float32_t, ndim = 2] data vol = self._Volume nbins = vol.sweep[0].ray[0].h.nbins total_rays = self.total_rays() shape = (total_rays, nbins) data = np.zeros(shape, dtype='float32') + 1.31072000e+05 ray_count = 0 nsweeps = vol.h.nsweeps for nsweep in range(nsweeps): sweep = vol.sweep[nsweep] assert sweep is not NULL nrays = sweep.h.nrays for nray in range(nrays): ray = sweep.ray[nray] assert ray is not NULL nbins = ray.h.nbins for nbin in range(nbins): raw = ray.range[nbin] data[ray_count + nray, nbin] = ray.h.f(raw) ray_count += nrays return data def is_range_bins_uniform(self): """ is_range_bins_uniform() Return True is the locations of the range bin are identical for all rays, False if locations change in one or more rays. """ cdef int nrays = self._Volume.sweep[0].h.nrays cdef _rsl_h.Sweep * sweep cdef _rsl_h.Ray * ray # loop over the sweeps and rays checking that the gate_size and # range_bin1 are the same as the that in the first ray sweep = self._Volume.sweep[0] assert sweep is not NULL ray = sweep.ray[0] assert ray is not NULL ref_gate_size = ray.h.gate_size ref_range_bin1 = ray.h.range_bin1 for i in range(self.nsweeps): sweep = self._Volume.sweep[i] assert sweep is not NULL nrays = sweep.h.nrays for j in range(nrays): ray = sweep.ray[j] assert ray is not NULL if ray.h.gate_size != ref_gate_size: return False if ray.h.range_bin1 != ref_range_bin1: return False return True cdef _prtmode(self, _rsl_h.Ray_header h): """ Return the prt mode of a given Ray header. """ # TODO need to add additional logic here if h.prf2 != h.prf: mode = 'dual ' else: mode = 'fixed ' return mode # header properties mapped to class attributes. property nsweeps: def __get__(self): return self._Volume.h.nsweeps def __set__(self, int nsweeps): self._Volume.h.nsweeps = nsweeps property calibr_const: def __get__(self): return self._Volume.h.calibr_const def __set__(self, float calibr_const): self._Volume.h.calibr_const = calibr_const cdef class RslFile: """ RslFile(filename) A object for accessing Radar data and parameter using the RSL library. Parameters ---------- filename : str Radar file to read. Attributes ---------- month : int Date, month (1-12). day : int Date, day (1-31). year : int Date, year (eg. 1993). hour : int Time, hour (0-23). minute : int Time, minute (0-59). sec : float Time, second + fractions of second. nvolumes : int Number of volume slots in the file. number : int Arbitrary number for this radar site. latd, latm, lats : int Latitude degrees, minutes and seconds for the site. lond, lonm, lons : int Longitude degrees, minutes and seconds for the site. height : int Height of site in meters above sea level. spulse : int Length of short pulse in ns. lpulse : int Length of long pulse in ns. scan_mode : int Scan mode, 0 for PPI, 1 for RHI. vcp : int Volume coverage pattern, WSR-88D only. """ cdef _rsl_h.Radar * _Radar cdef _rsl_h.Volume * _Volume cdef _rsl_h.Sweep * _Sweep cdef _rsl_h.Ray * _Ray def __cinit__(self, filename, radar_format=None, callid=None): """ Initalize the _RslFile object. """ if radar_format == 'wsr88d': if callid is None: raise ValueError('callid must be provided.') self._Radar = _rsl_h.RSL_wsr88d_to_radar(filename, callid) elif radar_format is None: self._Radar = _rsl_h.RSL_anyformat_to_radar(filename) else: raise ValueError('invalid radar_format:', radar_format) if self._Radar is NULL: raise IOError('file cannot be read.') def __dealloc__(self): """ Free memory used by object. """ _rsl_h.RSL_free_radar(self._Radar) def get_volume(self, int volume_number): """ get_volume(volume_number) Return a _RslVolume for a given volume number. Parameters ---------- volume_number : int Volume number to retrieve Returns ------- volume : _RslVolume _RslVolume object containing requested volume. """ if volume_number < 0 or volume_number >= self._Radar.h.nvolumes: raise ValueError('invalid volume_number') rslvolume = _RslVolume() rslvolume.load(self._Radar.v[volume_number]) return rslvolume def available_moments(self): """ available_moments() Return a list of available volume moments. """ av = [] for i in range(self._Radar.h.nvolumes): if self._Radar.v[i] is not NULL: av.append(i) return av def get_radar_header(self): """ get_radar_headers() Return a dictionary of radar header parameters. """ return self._Radar.h def get_volume_array(self, int volume_num): """ get_volume_array(volume_number) Return the three-dimensional data contained in a given volume. Parameters ---------- volume_number : int Returns ------- volume : array (nsweep, nrays, nbins), float32 Array containing data for the given volume. """ return self.get_volume(volume_num).get_data() # header properties mapped to class attributes. property month: def __get__(self): return self._Radar.h.month def __set__(self, int month): self._Radar.h.month = month property day: def __get__(self): return self._Radar.h.day def __set__(self, int day): self._Radar.h.day = day property year: def __get__(self): return self._Radar.h.year def __set__(self, int year): self._Radar.h.year = year property hour: def __get__(self): return self._Radar.h.hour def __set__(self, int hour): self._Radar.h.hour = hour property minute: def __get__(self): return self._Radar.h.minute def __set__(self, int minute): self._Radar.h.minute = minute property sec: def __get__(self): return self._Radar.h.sec def __set__(self, float sec): self._Radar.h.sec = sec property nvolumes: def __get__(self): return self._Radar.h.nvolumes def __set__(self, int nvolumes): self._Radar.h.nvolumes = nvolumes property number: def __get__(self): return self._Radar.h.number def __set__(self, int number): self._Radar.h.number = number property latd: def __get__(self): return self._Radar.h.latd def __set__(self, int latd): self._Radar.h.latd = latd property latm: def __get__(self): return self._Radar.h.latm def __set__(self, int latm): self._Radar.h.latm = latm property lats: def __get__(self): return self._Radar.h.lats def __set__(self, int lats): self._Radar.h.lats = lats property lond: def __get__(self): return self._Radar.h.lond def __set__(self, int lond): self._Radar.h.lond = lond property lonm: def __get__(self): return self._Radar.h.lonm def __set__(self, int lonm): self._Radar.h.lonm = lonm property lons: def __get__(self): return self._Radar.h.lons def __set__(self, int lons): self._Radar.h.lons = lons property height: def __get__(self): return self._Radar.h.height def __set__(self, int height): self._Radar.h.height = height property spulse: def __get__(self): return self._Radar.h.spulse def __set__(self, int spulse): self._Radar.h.spulse = spulse property lpulse: def __get__(self): return self._Radar.h.lpulse def __set__(self, int lpulse): self._Radar.h.lpulse = lpulse property scan_mode: def __get__(self): return self._Radar.h.scan_mode def __set__(self, int scan_mode): self._Radar.h.scan_mode = scan_mode property vcp: def __get__(self): return self._Radar.h.vcp def __set__(self, int vcp): self._Radar.h.vcp = vcp