diff --git a/description.txt b/description.txt index 28c3afa..481e53c 100644 --- a/description.txt +++ b/description.txt @@ -1,3 +1,3 @@ PyDisdrometer is a Python package to process disdrometer files. It currently is capable of reading several different types of disdrometers and calculating both important moment parameters, as well as radar derived parameters. It currently supports OTT Parsivel disdrometers and Joss Waldvogel Disdrometers. It is currently in alpha so functionality is limited but being expanded quickly. -Author: Joseph C. Hardin +Author: Joseph C. Hardin, Nick Guy diff --git a/pydisdrometer/DropSizeDistribution.py b/pydisdrometer/DropSizeDistribution.py index 36f8dbe..17c8e3d 100644 --- a/pydisdrometer/DropSizeDistribution.py +++ b/pydisdrometer/DropSizeDistribution.py @@ -19,7 +19,7 @@ from . import DSR from .utility import dielectric - +from .utility import configuration SPEED_OF_LIGHT=299792458 class DropSizeDistribution(object): @@ -57,7 +57,7 @@ class DropSizeDistribution(object): ''' - def __init__(self, reader, time_start = None, location=None,): + def __init__(self, reader, time_start = None, location=None): '''Initializer for the DropSizeDistribution class. The DropSizeDistribution class holds dsd's returned from the various @@ -65,36 +65,12 @@ def __init__(self, reader, time_start = None, location=None,): Parameters ---------- -# time: array_like -# An array of times corresponding to the time each dsd was sampled in minutes relative to time_start. -# Nd : 2d Array -# A list of drop size distributions -# spread: array_like -# Array giving the bin spread size for each size bin of the -# disdrometer. -# velocity: optional, array_like -# Terminal Fall Velocity for each size bin. This is based on the -# disdrometer assumptions. -# Z: optional, array_like -# The equivalent reflectivity factory from the disdrometer. Often -# taken as D**6. -# num_particles: optional, array_like -# Number of measured particles for each time instant. -# bin_edges: optional, array_like -# N+1 sized array of the boundaries of each size bin. For 30 bins -# for instance, there will be 31 different bin boundaries. -# diameter: optional, array_like -# The center size for each dsd bin. - reader: object Object returned by package readers. time_start: datetime Recording Start time. location: tuple (Latitude, Longitude) pair in decimal format. - scattering_temp: optional, string - Scattering temperature string. One of ("0C","10C","20C"). - Defaults to "10C" Returns ------- @@ -102,6 +78,9 @@ def __init__(self, reader, time_start = None, location=None,): Drop Size Distribution instance. ''' + + self.config = configuration.Configuration() + self.time = reader.time self.Nd = reader.fields['Nd'] self.spread = reader.spread @@ -210,16 +189,15 @@ def calculate_radar_parameters(self, dsr_func = DSR.bc, scatter_time_range = Non for t in range(self.scatter_start_time, self.scatter_end_time): self.fields['Kdp']['data'][t] = radar.Kdp(self.scatterer) self.fields['Ai']['data'][t] = radar.Ai(self.scatterer) - self.fields['Ad']['data'][t] = radar.Ai(self.scatterer) -radar.Ai(self.scatterer, h_pol=False) + self.fields['Adr']['data'][t] = radar.Ai(self.scatterer) -radar.Ai(self.scatterer, h_pol=False) - def _setup_empty_fields(self, ): + def _setup_empty_fields(self ): ''' Preallocate arrays of zeros for the radar moments ''' - self.fields['Zh'] = {'data': np.ma.zeros(self.numt)} - self.fields['Zdr'] = {'data': np.ma.zeros(self.numt)} - self.fields['Kdp'] = {'data': np.ma.zeros(self.numt)} - self.fields['Ai'] = {'data': np.ma.zeros(self.numt)} - self.fields['Ad'] = {'data': np.ma.zeros(self.numt)} + params_list = ['Zh', 'Zdr', 'Kdp', 'Ai', 'Adr'] + + for param in params_list: + self.fields[param] = self.config.fill_in_metadata(param, np.ma.zeros(self.numt)) def _setup_scattering(self, wavelength, dsr_func): ''' Internal Function to create scattering tables. @@ -292,15 +270,10 @@ def calculate_dsd_parameterization(self, method='bringi'): ''' - self.fields['Nt'] = {'data': np.ma.zeros(self.numt)} - self.fields['W'] = {'data': np.ma.zeros(self.numt)} - self.fields['D0'] = {'data': np.ma.zeros(self.numt)} - self.fields['Nw'] = {'data': np.ma.zeros(self.numt)} - self.fields['Dmax'] = {'data': np.ma.zeros(self.numt)} - self.fields['Dm'] = {'data': np.ma.zeros(self.numt)} - self.fields['Nw'] = {'data': np.ma.zeros(self.numt)} - self.fields['N0'] = {'data': np.ma.zeros(self.numt)} - self.fields['mu'] = {'data': np.ma.zeros(self.numt)} + params_list = ['D0', 'Dmax', 'Dm', 'Nt', 'Nw', 'N0', 'W', 'mu'] + + for param in params_list: + self.fields[param] = self.config.fill_in_metadata(param, np.ma.zeros(self.numt)) rho_w = 1e-03 # grams per mm cubed Density of Water vol_constant = np.pi / 6.0 * rho_w diff --git a/pydisdrometer/tests/testConfiguration.py b/pydisdrometer/tests/testConfiguration.py new file mode 100644 index 0000000..7854047 --- /dev/null +++ b/pydisdrometer/tests/testConfiguration.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +import numpy as np +import unittest +from ..utility import configuration + +from .. import DropSizeDistribution + +class testConfiguration(unittest.TestCase): + ''' Unit tests for Configuration Class''' + + def setUp(self): + self.config = configuration.Configuration() + + def test_config_loads_and_has_keys(self): + self.assertIsNotNone(self.config) + self.assertTrue(len(self.config.metadata.keys()) > 0 ) diff --git a/pydisdrometer/utility/configuration.py b/pydisdrometer/utility/configuration.py new file mode 100644 index 0000000..f90a179 --- /dev/null +++ b/pydisdrometer/utility/configuration.py @@ -0,0 +1,32 @@ +import json +from copy import copy +import os + + + +class Configuration(object): + ''' Class to store PyDisdrometer configuration options + + Attributes: + ----------- + + ''' + config_dir = os.path.dirname(os.path.abspath(__file__)) + metadata_config_file = os.path.join(config_dir, 'metadata.json') + + def __init__(self): + self.metadata = self.load_metadata_config() + + def load_metadata_config(self): + ''' Load the metadata configuration file and return the dictionary''' + return json.load(open(self.metadata_config_file)) + + + def fill_in_metadata(self, field, data): + metadata = self.metadata[field].copy() + metadata['data'] = copy(data) + return metadata + + + + diff --git a/pydisdrometer/utility/metadata.json b/pydisdrometer/utility/metadata.json new file mode 100644 index 0000000..7fc565b --- /dev/null +++ b/pydisdrometer/utility/metadata.json @@ -0,0 +1,88 @@ +{ + "D0": + { + "standard_name": "median_drop_diameter", + "units": "mm", + "long_name": "Median Drop Diameter" + }, + "Dmax": + { + "standard_name": "maximum_drop_diameter", + "units": "mm", + "long_name" :"Maximum Drop Diameter" + }, + "Dm": + { + "standard_name": "mean_drop_diameter", + "units": "mm", + "long_name" :"Mean Drop Diameter" + }, + "Nw": + { + "standard_name": "normalized_intercept_parameter", + "units": "?", + "long_name" :"Normalized Intercept Parameter of a Normalized Gaussian Distribution" + }, + "Nt": + { + "standard_name": "total_droplet_concentration", + "units": "m^-1", + "long_name" :"Total Droplet Concentration" + }, + "N0": + { + "standard_name": "intercept_parameter", + "units": "?", + "long_name" :"Intercept Parameter of Modeled Drop Size Distribution" + }, + "W": + { + "standard_name": "water_mass", + "units": "g/m^3", + "long_name" :"Water Mass of Drop Size Distribution" + }, + "mu": + { + "standard_name": "shape_parameter", + "units": " ", + "long_name" :"Shape Parameter of Modeled Drop Size Distribution" + }, + "rain_rate": + { + "standard_name": "rain_rate", + "units": "mm/h", + "long_name" :"Instantaneous Rainfall Rate of Water Flux" + }, + "Zh": + { + "standard_name": "horizontal_reflectivity", + "units": "dBZ", + "long_name" :"Estimated Horizontal Radar Reflectivity from Drop Size Distribution" + }, + "Zdr": + { + "standard_name": "differential_reflectivity", + "units": "dBZ", + "long_name" :"Estimated Differential Radar Reflectivity (H, V) from Drop Size Distribution" + }, + "Kdp": + { + "standard_name": "specific_differential_phase", + "units": "deg", + "long_name" :"Specific Differential Phase from Drop Size Distribution" + }, + "Ai": + { + "standard_name": "specific_attenuation", + "units": "dB/km", + "long_name": "Specific Attenuation" + }, + "Adr": + { + "standard_name": "specific_differential_attenuation", + "units": "dB/km", + "long_name": "Specific Differential Attenuation" + } +} + +