From fc611c6de9446b41460c432cdd6a6e53ff98674d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Schr=C3=B6n?= <martin.schroen@ufz.de> Date: Mon, 27 Nov 2023 16:41:00 +0100 Subject: [PATCH] Feature: muons processing and plotting --- VERSION | 2 +- corny/version.py | 2 +- default.cfg | 14 ++++++++ instantPASDy.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 972ef76..100435b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.9 +0.8.2 diff --git a/corny/version.py b/corny/version.py index 07b67b5..40c8236 100644 --- a/corny/version.py +++ b/corny/version.py @@ -1,6 +1,6 @@ # Corny module: version.py # Version management -VERSION = "0.8.1" +VERSION = "0.8.2" from .io import app_file_path diff --git a/default.cfg b/default.cfg index c1518bd..d3812e0 100644 --- a/default.cfg +++ b/default.cfg @@ -122,6 +122,10 @@ latitude_column = longitude_column = altitude_column = +## Muons +# Column for muon counts +muon_column = + [clean] # Cut the data, find outliers, fill gaps, and smooth out noise. @@ -280,6 +284,10 @@ temperature_range = -60, 60 # Units: m³/m³ sm_range = +## Muon count range +# Units: cph +muon_range = + ## Split tracks # Identify single tracks between locations A and B (yes/no) @@ -373,6 +381,12 @@ NM_station = JUNG # - 1day # 1 day temporal resolution NM_resolution = 1min +## Muon counts +# Muon correction parameters based on Stevanato et al. (2022) +muon_beta = 625 +muon_alpha = 0.0021 +muon_T_ref = 0 + [conversion] # New column name for the soil moisture product diff --git a/instantPASDy.py b/instantPASDy.py index 0c65782..f795e90 100644 --- a/instantPASDy.py +++ b/instantPASDy.py @@ -575,6 +575,8 @@ def main(configfile=None, cfg_prefix=None): (Ta,Tb) = xsplit(config['clean']['temperature_range'], range=2, type=float) if 'timeres_range' in config['clean']: (tra,trb)= xsplit(config['clean']['timeres_range'], range=2, type=float) + + # Define new column N+clean data[N+clean] = data[N] @@ -710,6 +712,31 @@ def main(configfile=None, cfg_prefix=None): #data[['GpsUTC', 'LatDec', 'LongDec', 'Alt']].to_csv('testgps.csv', index=False) + #################################################### + ###### Muons ####################################### + #################################################### + + Muons = False + if cc(config,'input','muon_column'): + Muons = True + mu = gc(config,'input','muon_column') + (Ma,Mb) = gc(config,'clean','muon_range', range=2, dtype=list, types=float) + data[mu+"_cph"] = Unit_convert(data[mu], data[tres], 'cph') + data[mu+clean] = find_outlier(data, mu+"_cph", lower=Ma, upper=Mb) + + beta_M = gc(config,'correction','muon_beta', dtype=float) + alpha_M = gc(config,'correction','muon_alpha', dtype=float) + Tref_M = gc(config,'correction','muon_T_ref', dtype=float) + + data[mu+clean+"_p"] = data[mu+clean] * np.exp((data[p] - 1013) / beta_M) + data[mu+clean+"_ph"] = data[mu+clean+"_p"] * (1 + alpha_M * (data[T] - Tref_M)) + + mufinal = mu+clean+"_ph" + + J.report("muons", + "Muons have been dropped beyond below {:.0f} and above {:.0f} cph. " \ + +"Corrections were applied based on Stevanato et al. (2022) using beta={:.0f}, alpha={:.0f}, and T_ref={:.0f}.", + Ma, Mb, beta_M, alpha_M, Tref_M) #################################################### ###### Soil ####################################### @@ -1638,6 +1665,13 @@ def main(configfile=None, cfg_prefix=None): J.report("neutronsth", "Temporal smoothing was applied over {:.0f} time steps.", smooth_window) + + if Muons: + data[mufinal+mov] = data[mufinal].rolling(smooth_window, center=True).mean() + mufinal += mov + J.report("muons", + "Temporal smoothing was applied over {:.0f} time steps.", + smooth_window) if cc(config,'clean','smooth_radius'): @@ -2791,6 +2825,60 @@ def main(configfile=None, cfg_prefix=None): buffer = F.buff R.add_image(buffer) + if Muons: + Pr.update("Muons ") + R.add_page() + R.add_title("Muons") + R.add_par(J.post("muons")) + + if not data[mu].isnull().all(): + with Figure(size=(10,11), layout=(3,1), + **kw_fig_buff, **kw_fig_time, + x_ticks_last=True) as F: + + ax = F.axes[0] + # ax.scatter(data_orig.index, data_orig[N], + # label="$N$ raw", + # marker='o', s=5, lw=0, color='#DDDDDD') + ax.scatter(data.index, data[mu+"_cph"], + label="Muons raw", + marker='o', s=10, lw=0, color='#CCCCCC') + data_outliers = data[data[mu+clean] != data[mu+"_cph"]] + ax.scatter(data_outliers.index, data_outliers[mu+"_cph"], + label="Muons raw (dropped)", + marker='+', s=40, lw=2, color='red') + + ax = F.axes[1] + ax.scatter(data.index, data[mu+clean], + label="Muons cleaned", + marker='o', s=10, lw=0, color='#CCCCCC') + ax.scatter(data.index, data[mu+clean+"_ph"], + label="$Muons cleaned, atm. corrections", + marker='o', s=10, lw=0, color='#999999') + + ax = F.axes[2] + ax.plot(data.index, (data[mufinal] - data[mufinal].mean())/data[mufinal].std(ddof=0), + label="Muons, normalized", + lw=1, color='C0') + ax.plot(data.index, (data["NM"] - data["NM"].mean())/data["NM"].std(ddof=0), + label="Neutron Monitor, normalized", + lw=1, color='C3') + ax.set_ylabel("z score (--)") + + for ax in F.axes[0:2]: + ax.set_ylabel("Muons (cph)") + for ax in F.axes: + ax.set_xlim(date1, date2) + ax.grid(color="k", alpha=0.1) + ax.legend(loc="upper left", bbox_to_anchor=(0, 1.12), + ncol=3, fancybox=False, framealpha=1, edgecolor="k", + shadow=True) + if ax != F.axes[-1]: + ax.set_xticklabels([]) + + buffer = F.buff + R.add_image(buffer) + Pr.update("Atmosphere") R.add_page() R.add_title("Atmosphere") -- GitLab