diff options
-rwxr-xr-x | calc_pei.py | 79 |
1 files changed, 62 insertions, 17 deletions
diff --git a/calc_pei.py b/calc_pei.py index bf49478..ce387e1 100755 --- a/calc_pei.py +++ b/calc_pei.py @@ -1,12 +1,18 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Aaron LI # Created: 2016-04-29 -# Updated: 2016-05-04 +# Updated: 2016-05-18 +# +# Change log: +# 2016-05-18: +# * Fix/Update PEI Y positions determination +# * Update `calc_pei()` results +# 2016-05-04: +# * Prepare the PEI uncertainty estimation support # # FIXME/TODO: -# * come up a approach to estimate the PEI error +# * improve the PEI uncertainty estimation approach (fix the bias) # """ @@ -38,13 +44,13 @@ import matplotlib.patches as patches from info import get_r500 -__version__ = "0.4.0" -__date__ = "2016-05-04" +__version__ = "0.4.2" +__date__ = "2016-05-18" plt.style.use("ggplot") -def calc_pei(data, r500, interp_np=101): +def calc_pei(data, r500, interp_np=101, pei_pos=None): """ Calculate the power excess index (PEI), which is defined the area ratio of the lower-left part with respect to the total rectangle. @@ -53,29 +59,64 @@ def calc_pei(data, r500, interp_np=101): * data: (frequency, power) power spectrum data * r500: R500 value in unit of the inverse of the above "frequency" * interp_np: number of data points interpolated to calculate PEI + * pei_pos: position specification (i.e., xmin, xmax, ymin, ymax) of + the PEI rectangle. + If this argument is provided, then the PEI rectangle is + just determined (i.e., r500 etc is ignored). + This is a dictionary with the mentioned keys. + e.g., the returned results of previous `calc_pei()`. """ freqs, psd1d = data - # frequency values corresponding to 0.35R500 and 0.035R500 - pei_fmin = 1.0 / (0.350 * r500) - pei_fmax = 1.0 / (0.035 * r500) # switch to the logarithmic scale mask = (freqs > 0.0) x = np.log10(freqs[mask]) y = np.log10(psd1d[mask]) - pei_xmin = np.log10(pei_fmin) - pei_xmax = np.log10(pei_fmax) + # determine the X positions of PEI rectangle + if pei_pos is not None: + pei_xmin = pei_pos["pei_xmin"] + pei_xmax = pei_pos["pei_xmax"] + else: + # frequency values corresponding to 0.35R500 and 0.035R500 + pei_fmin = 1.0 / (0.350 * r500) + pei_fmax = 1.0 / (0.035 * r500) + pei_xmin = np.log10(pei_fmin) + pei_xmax = np.log10(pei_fmax) + # data points within the PEI range + mask_pei = np.logical_and(x >= pei_xmin, x <= pei_xmax) + y_pei = y[mask_pei] # interpolate the power spectrum f_interp = scipy.interpolate.interp1d(x, y, kind="linear", assume_sorted=True) x_interp = np.linspace(pei_xmin, pei_xmax, num=interp_np) y_interp = f_interp(x_interp) - pei_ymin = np.min(y_interp) - pei_ymax = np.max(y_interp) + # determine the Y positions of PEI rectangle + if pei_pos is not None: + pei_ymin = pei_pos["pei_ymin"] + pei_ymax = pei_pos["pei_ymax"] + else: + pei_ymin = min(np.min(y_interp), np.min(y_pei)) + pei_ymax = max(np.max(y_interp), np.max(y_pei)) + # + # XXX/FIXME: + # fixes the values that are smaller than the predefined `pei_ymin` + # (due to large uncertainties of the PSD) + # NOTE/FIXME: + # Since the PEI rectangle is just *fixed* during the Monte Carlo error + # estimation, and the values below the specified `pei_ymin` are just + # ignored (i.e., force to be `pei_ymin`), therefore, the estimated error + # of PEI is upwardly *biased*, i.e., the upper PEI uncertainty maybe + # OK, but the lower PEI uncertainty is *underestimated*. + # + y_interp[y_interp < pei_ymin] = pei_ymin # calculate the PEI area_total = (pei_xmax - pei_xmin) * (pei_ymax - pei_ymin) area_below = scipy.integrate.trapz((y_interp-pei_ymin), x_interp) pei_value = area_below / area_total results = { + "pei_xmin": pei_xmin, + "pei_xmax": pei_xmax, + "pei_ymin": pei_ymin, + "pei_ymax": pei_ymax, "area_total": area_total, "area_below": area_below, "pei_value": pei_value, @@ -137,10 +178,10 @@ def plot_pei(data, data_interp_log10, info={}, ax=None, fig=None): psd1d_err = data[:, 2] x_interp = 10 ** data_interp_log10[:, 0] y_interp = 10 ** data_interp_log10[:, 1] - pei_xmin = np.min(x_interp) - pei_xmax = np.max(x_interp) - pei_ymin = np.min(y_interp) - pei_ymax = np.max(y_interp) + pei_xmin = 10 ** info["pei_xmin"] + pei_xmax = 10 ** info["pei_xmax"] + pei_ymin = 10 ** info["pei_ymin"] + pei_ymax = 10 ** info["pei_ymax"] # mask = (freqs > 0.0) xmin = np.min(freqs[mask]) / 1.2 @@ -254,6 +295,10 @@ def main(): ("obsid", obsid), ("r500_pix", r500_pix), ("r500_err_pix", r500_err_pix), + ("pei_xmin", pei["pei_xmin"]), + ("pei_xmax", pei["pei_xmax"]), + ("pei_ymin", pei["pei_ymin"]), + ("pei_ymax", pei["pei_ymax"]), ("area_total", pei["area_total"]), ("area_below", pei["area_below"]), ("pei", pei["pei_value"]), |