Creating a basic ingest of a NetCDF file#

### Sometimes a file might be in the netCDF file format but not conform to cfradial standards and can't
### be read with Py-ART. One way of working around this is to create a basic ingest, here is a hypothetically
### example, this file can be read with Py-ART, but lets act like it doesn't! :)
import netCDF4
import pyart
import numpy as np
## You are using the Python ARM Radar Toolkit (Py-ART), an open source
## library for working with weather radar data. Py-ART is partly
## supported by the U.S. Department of Energy as part of the Atmospheric
## Radiation Measurement (ARM) Climate Research Facility, an Office of
## Science user facility.
##
## If you use this software to prepare a publication, please cite:
##
##     JJ Helmus and SM Collis, JORS 2016, doi: 10.5334/jors.119
# We will read the nc data with netCDF4.Dataset
data = netCDF4.Dataset("test_radar.nc")
# Lets get an idea of the shapes for rays and gates and the keys in this dataset.
data.variables.keys()
dict_keys(['time', 'range', 'azimuth', 'elevation', 'corrected_reflectivity_horizontal', 'reflectivity_horizontal', 'recalculated_diff_phase', 'specific_attenuation', 'unf_dp_phase_shift', 'mean_doppler_velocity', 'diff_phase', 'rain_rate_A', 'norm_coherent_power', 'dp_phase_shift', 'diff_reflectivity', 'proc_dp_phase_shift', 'copol_coeff', 'sweep_number', 'fixed_angle', 'sweep_start_ray_index', 'sweep_end_ray_index', 'sweep_mode', 'latitude', 'longitude', 'altitude', 'time_coverage_start', 'time_coverage_end', 'time_reference', 'volume_number', 'platform_type', 'instrument_type', 'primary_axis'])
data["azimuth"][:].shape
(400,)
data["range"][:].shape
(667,)
# Make a empty radar with the dimensions of the dataset.
radar = pyart.testing.make_empty_ppi_radar(667, 400, 1)
# Start filling the radar attributes with variables in the dataset.
radar.time["data"] = np.array(data["time"][:])
data["longitude"][:]
masked_array(data=-97.59416667,
             mask=False,
       fill_value=1e+20)
radar.latitude["data"] = np.array([data["latitude"][:]])
radar.longitude["data"] = np.array([data["longitude"][:]])
radar.longitude["data"]
array([-97.59416667])
radar.range["data"] = np.array(data["range"][:])
# Sometimes the dataset might just contain gate spacing, but if the gate spacing is uniform,
# there is a way around it, we see a gate spacing of 60 above.
radar.range["data"] = np.linspace(0.0, 60.0 * (667 - 1), 667)
# As you can see below we obtained the same range data. This isn't needed
# if the range data is present, but using gate spacing and ngates is another way around it.
radar.range["data"]
array([    0.,    60.,   120.,   180.,   240.,   300.,   360.,   420.,
         480.,   540.,   600.,   660.,   720.,   780.,   840.,   900.,
         960.,  1020.,  1080.,  1140.,  1200.,  1260.,  1320.,  1380.,
        1440.,  1500.,  1560.,  1620.,  1680.,  1740.,  1800.,  1860.,
        1920.,  1980.,  2040.,  2100.,  2160.,  2220.,  2280.,  2340.,
        2400.,  2460.,  2520.,  2580.,  2640.,  2700.,  2760.,  2820.,
        2880.,  2940.,  3000.,  3060.,  3120.,  3180.,  3240.,  3300.,
        3360.,  3420.,  3480.,  3540.,  3600.,  3660.,  3720.,  3780.,
        3840.,  3900.,  3960.,  4020.,  4080.,  4140.,  4200.,  4260.,
        4320.,  4380.,  4440.,  4500.,  4560.,  4620.,  4680.,  4740.,
        4800.,  4860.,  4920.,  4980.,  5040.,  5100.,  5160.,  5220.,
        5280.,  5340.,  5400.,  5460.,  5520.,  5580.,  5640.,  5700.,
        5760.,  5820.,  5880.,  5940.,  6000.,  6060.,  6120.,  6180.,
        6240.,  6300.,  6360.,  6420.,  6480.,  6540.,  6600.,  6660.,
        6720.,  6780.,  6840.,  6900.,  6960.,  7020.,  7080.,  7140.,
        7200.,  7260.,  7320.,  7380.,  7440.,  7500.,  7560.,  7620.,
        7680.,  7740.,  7800.,  7860.,  7920.,  7980.,  8040.,  8100.,
        8160.,  8220.,  8280.,  8340.,  8400.,  8460.,  8520.,  8580.,
        8640.,  8700.,  8760.,  8820.,  8880.,  8940.,  9000.,  9060.,
        9120.,  9180.,  9240.,  9300.,  9360.,  9420.,  9480.,  9540.,
        9600.,  9660.,  9720.,  9780.,  9840.,  9900.,  9960., 10020.,
       10080., 10140., 10200., 10260., 10320., 10380., 10440., 10500.,
       10560., 10620., 10680., 10740., 10800., 10860., 10920., 10980.,
       11040., 11100., 11160., 11220., 11280., 11340., 11400., 11460.,
       11520., 11580., 11640., 11700., 11760., 11820., 11880., 11940.,
       12000., 12060., 12120., 12180., 12240., 12300., 12360., 12420.,
       12480., 12540., 12600., 12660., 12720., 12780., 12840., 12900.,
       12960., 13020., 13080., 13140., 13200., 13260., 13320., 13380.,
       13440., 13500., 13560., 13620., 13680., 13740., 13800., 13860.,
       13920., 13980., 14040., 14100., 14160., 14220., 14280., 14340.,
       14400., 14460., 14520., 14580., 14640., 14700., 14760., 14820.,
       14880., 14940., 15000., 15060., 15120., 15180., 15240., 15300.,
       15360., 15420., 15480., 15540., 15600., 15660., 15720., 15780.,
       15840., 15900., 15960., 16020., 16080., 16140., 16200., 16260.,
       16320., 16380., 16440., 16500., 16560., 16620., 16680., 16740.,
       16800., 16860., 16920., 16980., 17040., 17100., 17160., 17220.,
       17280., 17340., 17400., 17460., 17520., 17580., 17640., 17700.,
       17760., 17820., 17880., 17940., 18000., 18060., 18120., 18180.,
       18240., 18300., 18360., 18420., 18480., 18540., 18600., 18660.,
       18720., 18780., 18840., 18900., 18960., 19020., 19080., 19140.,
       19200., 19260., 19320., 19380., 19440., 19500., 19560., 19620.,
       19680., 19740., 19800., 19860., 19920., 19980., 20040., 20100.,
       20160., 20220., 20280., 20340., 20400., 20460., 20520., 20580.,
       20640., 20700., 20760., 20820., 20880., 20940., 21000., 21060.,
       21120., 21180., 21240., 21300., 21360., 21420., 21480., 21540.,
       21600., 21660., 21720., 21780., 21840., 21900., 21960., 22020.,
       22080., 22140., 22200., 22260., 22320., 22380., 22440., 22500.,
       22560., 22620., 22680., 22740., 22800., 22860., 22920., 22980.,
       23040., 23100., 23160., 23220., 23280., 23340., 23400., 23460.,
       23520., 23580., 23640., 23700., 23760., 23820., 23880., 23940.,
       24000., 24060., 24120., 24180., 24240., 24300., 24360., 24420.,
       24480., 24540., 24600., 24660., 24720., 24780., 24840., 24900.,
       24960., 25020., 25080., 25140., 25200., 25260., 25320., 25380.,
       25440., 25500., 25560., 25620., 25680., 25740., 25800., 25860.,
       25920., 25980., 26040., 26100., 26160., 26220., 26280., 26340.,
       26400., 26460., 26520., 26580., 26640., 26700., 26760., 26820.,
       26880., 26940., 27000., 27060., 27120., 27180., 27240., 27300.,
       27360., 27420., 27480., 27540., 27600., 27660., 27720., 27780.,
       27840., 27900., 27960., 28020., 28080., 28140., 28200., 28260.,
       28320., 28380., 28440., 28500., 28560., 28620., 28680., 28740.,
       28800., 28860., 28920., 28980., 29040., 29100., 29160., 29220.,
       29280., 29340., 29400., 29460., 29520., 29580., 29640., 29700.,
       29760., 29820., 29880., 29940., 30000., 30060., 30120., 30180.,
       30240., 30300., 30360., 30420., 30480., 30540., 30600., 30660.,
       30720., 30780., 30840., 30900., 30960., 31020., 31080., 31140.,
       31200., 31260., 31320., 31380., 31440., 31500., 31560., 31620.,
       31680., 31740., 31800., 31860., 31920., 31980., 32040., 32100.,
       32160., 32220., 32280., 32340., 32400., 32460., 32520., 32580.,
       32640., 32700., 32760., 32820., 32880., 32940., 33000., 33060.,
       33120., 33180., 33240., 33300., 33360., 33420., 33480., 33540.,
       33600., 33660., 33720., 33780., 33840., 33900., 33960., 34020.,
       34080., 34140., 34200., 34260., 34320., 34380., 34440., 34500.,
       34560., 34620., 34680., 34740., 34800., 34860., 34920., 34980.,
       35040., 35100., 35160., 35220., 35280., 35340., 35400., 35460.,
       35520., 35580., 35640., 35700., 35760., 35820., 35880., 35940.,
       36000., 36060., 36120., 36180., 36240., 36300., 36360., 36420.,
       36480., 36540., 36600., 36660., 36720., 36780., 36840., 36900.,
       36960., 37020., 37080., 37140., 37200., 37260., 37320., 37380.,
       37440., 37500., 37560., 37620., 37680., 37740., 37800., 37860.,
       37920., 37980., 38040., 38100., 38160., 38220., 38280., 38340.,
       38400., 38460., 38520., 38580., 38640., 38700., 38760., 38820.,
       38880., 38940., 39000., 39060., 39120., 39180., 39240., 39300.,
       39360., 39420., 39480., 39540., 39600., 39660., 39720., 39780.,
       39840., 39900., 39960.])
radar.fixed_angle["data"] = np.array(data["fixed_angle"])
radar.sweep_number["data"] = np.array(data["sweep_number"])
radar.sweep_start_ray_index["data"] = np.array(data["sweep_start_ray_index"])
radar.sweep_end_ray_index["data"] = np.array(data["sweep_end_ray_index"])
radar.altitude["data"] = np.array(data["altitude"])
radar.azimuth["data"] = np.array(data["azimuth"])
radar.sweep_mode["data"] = np.array(data["sweep_mode"])
data["fixed_angle"][:]
masked_array(data=[3.5],
             mask=False,
       fill_value=1e+20)
# If elevation doesn't exist, but fixed angle doesn't, you can do
# fixed angle multiplied by nrays
radar.elevation["data"] = np.array(
    [data["fixed_angle"][:]] * len(data["azimuth"][:])
).squeeze()
# With elevation and azimuth in the radar object, lets recalculate
# gate latitude, longitude and altitude,
radar.init_gate_altitude()
radar.init_gate_longitude_latitude()
radar.gate_longitude["data"]
array([[-97.59416667, -97.59416776, -97.59416886, ..., -97.59489769,
        -97.59489879, -97.5948999 ],
       [-97.59416667, -97.59415662, -97.59414657, ..., -97.5874659 ,
        -97.58745576, -97.58744563],
       [-97.59416667, -97.59414621, -97.59412575, ..., -97.5805231 ,
        -97.58050246, -97.58048182],
       ...,
       [-97.59416667, -97.59419881, -97.59423095, ..., -97.61560159,
        -97.61563401, -97.61566644],
       [-97.59416667, -97.59418877, -97.59421087, ..., -97.6089062 ,
        -97.6089285 , -97.60895079],
       [-97.59416667, -97.59417836, -97.59419005, ..., -97.60196382,
        -97.60197561, -97.60198741]])
# Let's work on the field data, we will just do reflectivity for now, but any of the
# other fields can be done the same way and added as a key pair in the fields dict.
from pyart.config import get_metadata
ref_dict = get_metadata("reflecitivity_horizontal")
ref_dict["data"] = np.array(data["reflectivity_horizontal"])
ref_dict["data"]
array([[ -6.21875  ,   1.34375  ,  -8.0078125, ...,  -1.2109375,
          1.1171875,   1.59375  ],
       [ -6.2109375,   1.421875 ,  -8.5625   , ...,   2.34375  ,
         -0.7109375,   0.609375 ],
       [ -6.2109375,  -0.5078125,  -9.3828125, ...,  -0.6875   ,
         -2.328125 ,  -0.3203125],
       ...,
       [ -6.21875  ,   2.       ,  -9.21875  , ...,   0.859375 ,
         -6.6484375,  -1.328125 ],
       [ -6.2109375,   1.8515625, -10.25     , ...,   0.9375   ,
         -1.75     ,  -0.0234375],
       [ -6.21875  ,   1.6328125,  -8.2890625, ...,  -2.546875 ,
         -1.578125 ,   0.6796875]], dtype=float32)
radar.fields = {"reflectivity_horizontal": ref_dict}
# Now what does that data look like plotted with Py-ART, also confirm if it works.
import matplotlib.pyplot as plt
display = pyart.graph.RadarMapDisplay(radar)
display.plot_ppi("reflectivity_horizontal")
plt.show()
../_images/79d2254d8aa3ee1e8a51c11edd04d8ab55ca029393d463ad1346eb2aab967ddc.png