def _find_primary_bounds(x, dS_mask, ddS_mask, min_distance, is_absorption): prime_regions = OrderedDict() # Find obvious lines by peak values. for pind in np.where(dS_mask)[0][::2]: lower_ind = find_nearest( np.ma.array(x.value, mask=~ddS_mask | (x.value > x.value[pind])), x.value[pind]) upper_ind = find_nearest( np.ma.array(x.value, mask=~ddS_mask | (x.value < x.value[pind])), x.value[pind]) lower_x_ddS, upper_x_ddS = x.value[lower_ind], \ x.value[upper_ind] x_dS = x[pind] # if is_absorption: # cond = np.sign(ddS[lower_ind]) > np.sign(ddS[upper_ind]) # else: # cond = np.sign(ddS[lower_ind]) < np.sign(ddS[upper_ind]) # if cond: # Ensure that this found peak value is not within the minimum # distance of any other found peak values. if np.all([ np.abs(x - x_dS) > min_distance for x, _, _, _ in prime_regions.values() ]): prime_regions[(lower_ind, upper_ind)] = (x_dS, (lower_x_ddS, upper_x_ddS), is_absorption, False) return prime_regions
def _find_ternary_bounds(x, ddS_mask, dddS_mask, min_distance, is_absorption): ternary_regions = OrderedDict() # Find "buried" lines. Do this by taking the third difference of the # spectrum. Find the indices where the dddS_mask is true, retrieve only a # single index from the tuple by going in steps of 2. Each tind represents # the index of the centroid of the found buried line. for tind in np.where(dddS_mask)[0][::2]: # ddS contains bounds information. Find the lower bound index of the # dispersion. lower_ind = find_nearest( np.ma.array(x.value, mask=~ddS_mask | (x.value > x.value[tind])), x.value[tind]) # ddS contains bounds information. Find the upper bound index of the # dispersion. upper_ind = find_nearest( np.ma.array(x.value, mask=~ddS_mask | (x.value < x.value[tind])), x.value[tind]) # Retrieve the dispersion value for these indices and set the # dispersion value for the centroid. lower_x_ddS, upper_x_ddS = x.value[lower_ind], \ x.value[upper_ind] if lower_ind == 0 or upper_ind == x.size - 1: continue x_dddS = x[tind] # if is_absorption: # # This is truly a buried line if, for absorption, if the sign of # # the lower index in the bounds mask is greater than the upper. # cond = (dddS[lower_ind] > dddS[upper_ind]) # else: # # This is truly a buried line if, for emission, if the sign of # # the lower index in the bounds mask is greater than the upper. # cond = (dddS[lower_ind] < dddS[upper_ind]) # if True: # Ensure that this found peak value is not within the minimum # distance of any other found peak values. if np.all([ np.abs(x - x_dddS) > min_distance for x, _, _, _ in ternary_regions.values() ]): ternary_regions[(lower_ind, upper_ind)] = (x_dddS, (lower_x_ddS, upper_x_ddS), is_absorption, True) return ternary_regions
def region_bounds(x, y, threshold=0.001, min_distance=1): # Slice the y axis in half -- if more data elements exist in the "top" # half, assume the spectrum is absorption. Otherwise, assume emission. is_absorption = profile_type(x, y) == 'absorption' if not isinstance(min_distance, u.Quantity): min_distance *= x.unit dY, ddY, dddY = _make_data_diffs(y) dS, ddS, dddS = _make_sign_diffs(dY, ddY, dddY) dS_mask, ddS_mask, dddS_mask = _generate_masks(y, threshold, dS, ddS, dddS, is_absorption) ternary_regions = _find_ternary_bounds(x, ddS_mask, dddS_mask, min_distance, is_absorption) prime_regions = _find_primary_bounds(x, dS_mask, ddS_mask, min_distance, is_absorption) # Delete any information in ternary that shares the same bounds in primary for k in prime_regions: if k in ternary_regions: del ternary_regions[k] # For the ternary centroids closest to a prime centroid, use the bounds # information of the primary centroid for (t_low_ind, t_up_ind), (t_cent, bnds, is_absorb, buried) in ternary_regions.copy().items(): p_cents = [pr[0] for pr in prime_regions.values()] p_bnds = [(lo, hi) for lo, hi in prime_regions] # Find closest index ind = find_nearest(np.array([c.value for c in p_cents]), t_cent.value) p_cent = p_cents[ind] p_bnd = p_bnds[ind] # p_ind = find_nearest(x.value, p_cent.value) new_t_up_ind = t_up_ind new_t_low_ind = t_low_ind # If the prime centroid is greater than the ternary centroid, # update the ternary upper bound. if p_cent > t_cent: new_t_up_ind = p_bnd[1] # p_ind else: new_t_low_ind = p_bnd[0] # p_ind del ternary_regions[(t_low_ind, t_up_ind)] ternary_regions[(new_t_low_ind, new_t_up_ind)] = (t_cent, (x.value[new_t_low_ind], x.value[new_t_up_ind]), is_absorb, buried) ternary_regions.update(prime_regions) return ternary_regions