Skip to content

Commit e761f86

Browse files
authored
Merge pull request #122 from rcjackson/yaml_config
ADD: Further expansion of the YAML-based configuration to include all hard-coded parameters
2 parents 8c1a24c + c534c07 commit e761f86

22 files changed

Lines changed: 902 additions & 721 deletions

README.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
CMAC 2.0
2-
========
1+
CMAC
2+
====
33

44
CMAC: Corrected Precipitation Radar Moments in Antenna Coordinates
55

6-
CMAC 2.0 (Corrected Moments in Antenna Coordinates version 2) is a set of
6+
CMAC (Corrected Moments in Antenna Coordinates) is a set of
77
algorithms and code that does corrections to Radar data, but also adds fields
88
to the original data. Using fuzzy logic CMAC also calculates gate IDs such as
99
rain, snow and second-trip. Some other examples of the corrections done are
@@ -19,16 +19,16 @@ Interactive notebooks on the cloud
1919

2020

2121
The `Atmospheric Community Toolkit <https://arm-doe.github.io/ACT>`_ is installed in this binder
22-
and can be used to download data for CMAC2.0 from ARM Data Discovery. For an example on how
22+
and can be used to download data for CMAC from ARM Data Discovery. For an example on how
2323
to download ARM datastreams from Data Discovery, click `here <https://arm-doe.github.io/ACT/API/generated/act.discovery.download_data.html#act.discovery.download_data>`_.
2424

2525

26-
All ARM files are in the format that is needed by CMAC2.0 for processing.
26+
All ARM files are in the format that is needed by CMAC for processing.
2727

2828
Install
2929
-------
3030

31-
CMAC 2.0 and the required environment can be installed by using the
31+
CMAC and the required environment can be installed by using the
3232
instructions below::
3333

3434
git clone https://github.com/EVS-ATMOS/cmac2.0.git
@@ -56,10 +56,10 @@ need to be replaced with corresponding version number found here:
5656

5757
https://anaconda.org/menpo/ffmpeg
5858

59-
Using CMAC 2.0
60-
--------------
59+
Using CMAC
60+
----------
6161

62-
Once downloaded, CMAC 2.0 can be used in the terminal. The required arguments
62+
Once downloaded, CMAC can be used in the terminal. The required arguments
6363
are radar_file, sonde_file, clutter_file and config_dict. There are optional
6464
arguments such as out_radar, image_directory and sweep for the quicklooks.
6565

cmac/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from .cmac_processing import return_csu_kdp, retrieve_qvp, beam_block
2727
from .config import get_cmac_values, get_field_names
2828
from .config import get_metadata, get_plot_values
29+
from .config import get_zs_relationships, get_default_metadata
2930
from .data_catalouging import get_sounding_times, get_sounding_file_name
3031
from .radar_clutter import tall_clutter
3132

cmac/cmac_ppi_quicklooks.py

Lines changed: 141 additions & 93 deletions
Large diffs are not rendered by default.

cmac/cmac_processing.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" Module that does various CMAC 2.0 calculations. This code was written by
1+
""" Module that does various CMAC calculations. This code was written by
22
Scott Collis and Robert Jackson. """
33

44
import copy
@@ -20,8 +20,8 @@
2020
'corrected_specific_diff_phase': 'Kdp',
2121
'corrected_reflectivity': 'Z'}
2222

23-
def rain_rate(radar, A, B, moment="specific_attenuation"):
24-
"""
23+
def rain_rate(radar, A, B, moment="specific_attenuation", valid_max=400):
24+
"""
2525
Rain rate applied to a pyart Radar object.
2626
2727
Takes a given set of an A coefficient and a B exponent to a
@@ -33,7 +33,7 @@ def rain_rate(radar, A, B, moment="specific_attenuation"):
3333
raise ValueError(f"Invalid moment: {moment}")
3434
else:
3535
abbrev = rain_rate_abbrevs[moment]
36-
36+
3737
mom = radar.fields[moment]["data"]
3838
if moment == "corrected_reflectivity":
3939
mom = 10**(mom / 10.)
@@ -44,13 +44,14 @@ def rain_rate(radar, A, B, moment="specific_attenuation"):
4444
radar.fields[f'rain_rate_{abbrev}']['standard_name'] = 'rainfall_rate'
4545
radar.fields[f'rain_rate_{abbrev}']['long_name'] = f'Rainfall rate estimated from {abbrev}'
4646
radar.fields[f'rain_rate_{abbrev}']['valid_min'] = 0
47-
radar.fields[f'rain_rate_{abbrev}']['valid_max'] = 400
47+
radar.fields[f'rain_rate_{abbrev}']['valid_max'] = valid_max
4848
radar.fields[f'rain_rate_{abbrev}']['A_coefficient'] = A
4949
radar.fields[f'rain_rate_{abbrev}']['B_exponent'] = B
5050
return radar
5151

5252

53-
def snow_rate(radar, swe_ratio, A, B, citation='Wolf and Snider 2012', abbrev='ws2012'):
53+
def snow_rate(radar, swe_ratio, A, B, citation='Wolf and Snider 2012',
54+
abbrev='ws2012', valid_max=500):
5455
"""
5556
Snow rate applied to a pyart.Radar object
5657
@@ -75,7 +76,7 @@ def snow_rate(radar, swe_ratio, A, B, citation='Wolf and Snider 2012', abbrev='w
7576
radar.fields['snow_rate_%s' % abbrev]['standard_name'] = 'snowfall_rate'
7677
radar.fields['snow_rate_%s' % abbrev]['long_name'] = 'Snowfall rate from Z using %s' % citation
7778
radar.fields['snow_rate_%s' % abbrev]['valid_min'] = 0
78-
radar.fields['snow_rate_%s' % abbrev]['valid_max'] = 500
79+
radar.fields['snow_rate_%s' % abbrev]['valid_max'] = valid_max
7980
radar.fields['snow_rate_%s' % abbrev]['swe_ratio'] = swe_ratio
8081
radar.fields['snow_rate_%s' % abbrev]['A'] = A
8182
radar.fields['snow_rate_%s' % abbrev]['B'] = B
@@ -114,7 +115,7 @@ def snr_and_sounding(radar, soundings_dir, override_file=None, verbose=True):
114115
return z_dict, temp_dict, snr
115116

116117

117-
def get_texture(radar, vel_field, nyq=None):
118+
def get_texture(radar, vel_field, nyq=None, window=4, median_size=(4, 4)):
118119
""" Calculates velocity texture field. """
119120
if nyq is None:
120121
nyq = radar.instrument_parameters['nyquist_velocity']['data'][0]
@@ -127,9 +128,9 @@ def get_texture(radar, vel_field, nyq=None):
127128
vel = vel.filled(np.nan)
128129
else:
129130
vel = radar.fields[vel_field]['data']
130-
131-
std_dev = pyart.util.angular_texture_2d(vel, 4, nyq)
132-
filtered_data = ndimage.filters.median_filter(std_dev, size=(4, 4))
131+
132+
std_dev = pyart.util.angular_texture_2d(vel, window, nyq)
133+
filtered_data = ndimage.filters.median_filter(std_dev, size=tuple(median_size))
133134
texture_field = pyart.config.get_metadata('velocity')
134135
texture_field['data'] = np.ma.masked_where(
135136
np.isnan(filtered_data), filtered_data)
@@ -141,7 +142,8 @@ def get_texture(radar, vel_field, nyq=None):
141142
def cum_score_fuzzy_logic(radar, mbfs=None,
142143
ret_scores=False,
143144
hard_const=None,
144-
verbose=False):
145+
verbose=False,
146+
median_size=(3, 4)):
145147
if mbfs is None:
146148
second_trip = {'velocity_texture': [[0, 0, 1.8, 2], 1.0],
147149
'cross_correlation_ratio': [[.5, .7, 1, 1], 0.0],
@@ -196,7 +198,7 @@ def cum_score_fuzzy_logic(radar, mbfs=None,
196198
this_score = this_score.reshape(
197199
flds[list(flds.keys())[0]]['data'].shape)
198200
scores.update({key: ndimage.filters.median_filter(
199-
this_score, size=[3, 4])})
201+
this_score, size=list(median_size))})
200202

201203
if hard_const is not None:
202204
# hard_const = [[class, field, (v1, v2)], ...]
@@ -242,7 +244,7 @@ def cum_score_fuzzy_logic(radar, mbfs=None,
242244
def do_my_fuzz(radar, rhv_field, ncp_field,
243245
tex_start=2.0, tex_end=2.1,
244246
custom_mbfs=None, custom_hard_constraints=None,
245-
verbose=True): # NEEDS DOCSTRING
247+
verbose=True, median_size=(3, 4)): # NEEDS DOCSTRING
246248
if verbose:
247249
print('##')
248250
print('## CMAC calculation using fuzzy logic:')
@@ -298,14 +300,16 @@ def do_my_fuzz(radar, rhv_field, ncp_field,
298300
hard_const = custom_hard_constraints
299301

300302
gid_fld, cats = cum_score_fuzzy_logic(radar, mbfs=mbfs, verbose=verbose,
301-
hard_const=hard_const)
303+
hard_const=hard_const,
304+
median_size=median_size)
302305
rain_val = list(cats).index('rain')
303306
snow_val = list(cats).index('snow')
304307
melt_val = list(cats).index('melting')
305308
return _fix_rain_above_bb(gid_fld, rain_val, melt_val, snow_val), cats
306309

307310

308-
def get_melt(radar, melt_cat=None):
311+
def get_melt(radar, melt_cat=None, fzl_ceiling=5000.0,
312+
fzl_replacement=3500.0, fzl_floor=1000.0):
309313
if melt_cat is None:
310314
cat_dict = {}
311315
for pair_str in radar.fields['gate_id']['notes'].split(','):
@@ -325,9 +329,9 @@ def get_melt(radar, melt_cat=None):
325329
fzl = fzl_sounding
326330

327331
print(fzl)
328-
if fzl > 5000:
329-
fzl = 3500.0
330-
if fzl < 1000:
332+
if fzl > fzl_ceiling:
333+
fzl = fzl_replacement
334+
if fzl < fzl_floor:
331335
fzl = radar.gate_altitude['data'].min()
332336
return fzl
333337

@@ -336,7 +340,7 @@ def fix_phase_fields(orig_kdp, orig_phidp, rrange, happy_kdp,
336340

337341
orig_kdp['data'][happy_kdp.gate_excluded] = 0.0
338342
orig_kdp['data'][orig_kdp['data'] > max_kdp] = max_kdp
339-
interg = integrate.cumtrapz(orig_kdp['data'], rrange, axis=1)
343+
interg = integrate.cumulative_trapezoid(orig_kdp['data'], rrange, axis=1)
340344
orig_phidp['data'][:, 0:-1] = interg/len(rrange)
341345
return orig_phidp, orig_kdp
342346

0 commit comments

Comments
 (0)