def test_burst_data_ich(data): """Test method `Data.burst_data_ich()`.""" d = data for ich, bursts in enumerate(d.mburst): if bursts.num_bursts == 0: continue # if no bursts skip this ch burst_dict = d.burst_data_ich(ich=ich) assert (burst_dict['size_raw'] == bursts.counts).all() assert (burst_dict['t_start'] == bursts.start * d.clk_p).all() assert (burst_dict['t_stop'] == bursts.stop * d.clk_p).all() assert (burst_dict['i_start'] == bursts.istart).all() assert (burst_dict['i_stop'] == bursts.istop).all() assert (burst_dict['bg_period'] == d.bp[ich]).all() nd, na, bg_d, bg_a, width = d.expand(ich, width=True) width_ms = width * 1e3 assert (width_ms == burst_dict['width_ms']).all() assert (nd == burst_dict['nd']).all() assert (na == burst_dict['na']).all() assert (bg_d == burst_dict['bg_dd']).all() assert (bg_a == burst_dict['bg_ad']).all() if d.alternated: period = d.bp[ich] bg_da = d.bg_from(Ph_sel(Aex='Dem'))[ich][period] * width bg_aa = d.bg_from(Ph_sel(Aex='Aem'))[ich][period] * width assert (bg_da == burst_dict['bg_da']).all() assert (bg_aa == burst_dict['bg_aa']).all()
def test_burst_search_and_gate(data_1ch): """Test consistency of burst search and gate.""" d = data_1ch assert d.alternated # Smoke tests bext.burst_search_and_gate(d, F=(6, 8)) bext.burst_search_and_gate(d, m=(12, 8)) bext.burst_search_and_gate(d, min_rate_cps=(60e3, 40e3)) if d.nch > 1: mr1 = 35e3 + np.arange(d.nch) * 1e3 mr2 = 30e3 + np.arange(d.nch) * 1e3 bext.burst_search_and_gate(d, min_rate_cps=(mr1, mr2)) # Consistency test d_dex = d.copy() d_dex.burst_search(ph_sel=Ph_sel(Dex='DAem')) d_aex = d.copy() d_aex.burst_search(ph_sel=Ph_sel(Aex='Aem')) d_and = bext.burst_search_and_gate(d) for bursts_dex, bursts_aex, bursts_and, ph in zip(d_dex.mburst, d_aex.mburst, d_and.mburst, d.iter_ph_times()): ph_b_mask_dex = bl.ph_in_bursts_mask(ph.size, bursts_dex) ph_b_mask_aex = bl.ph_in_bursts_mask(ph.size, bursts_aex) ph_b_mask_and = bl.ph_in_bursts_mask(ph.size, bursts_and) assert (ph_b_mask_and == ph_b_mask_dex * ph_b_mask_aex).all()
def test_burst_search(data): """Smoke test and bg_bs check.""" streams = [Ph_sel(Dex='Dem'), Ph_sel(Dex='Aem')] if data.alternated: streams.extend([Ph_sel(Dex='Aem', Aex='Aem'), Ph_sel(Dex='DAem')]) for sel in streams: data.burst_search(L=10, m=10, F=7, ph_sel=sel) assert list_equal(data.bg_bs, data.bg_from(sel)) if data.alternated: data.burst_search(m=10, F=7, ph_sel=Ph_sel(Dex='DAem'), compact=True) data.burst_search(L=10, m=10, F=7)
def test_expand(data): """Test method `expand()` for `Data()`.""" d = data for ich, bursts in enumerate(d.mburst): if bursts.num_bursts == 0: continue # if no bursts skip this ch nd, na, bg_d, bg_a, width = d.expand(ich, width=True) width2 = bursts.width * d.clk_p period = d.bp[ich] bg_d2 = d.bg_from(Ph_sel(Dex='Dem'))[ich][period] * width2 bg_a2 = d.bg_from(Ph_sel(Dex='Aem'))[ich][period] * width2 assert (width == width2).all() assert (nd == d.nd[ich]).all() and (na == d.na[ich]).all() assert (bg_d == bg_d2).all() and (bg_a == bg_a2).all()
def test_burst_recompute_index(data): """Test Bursts.recompute_index_* methods.""" d = data ph_sel = Ph_sel(Dex='Dem') d.burst_search(ph_sel=ph_sel, index_allph=True) d_sel = d.copy() d_sel.burst_search(ph_sel=ph_sel, index_allph=False) for times_sel, mask_sel, bursts_sel, times_allph, bursts_allph in zip( d.iter_ph_times(ph_sel=ph_sel), d.iter_ph_masks(ph_sel=ph_sel), d_sel.mburst, d.iter_ph_times(), d.mburst): assert (times_sel[bursts_sel.istart] == bursts_sel.start).all() assert (times_sel[bursts_sel.istop] == bursts_sel.stop).all() assert (times_allph[bursts_allph.istart] == bursts_allph.start).all() assert (times_allph[bursts_allph.istop] == bursts_allph.stop).all() # Test individual methods bursts_allph2 = bursts_sel.recompute_index_expand(mask_sel) assert bursts_allph2 == bursts_allph assert (times_allph[bursts_allph2.istart] == bursts_allph2.start).all() assert (times_allph[bursts_allph2.istop] == bursts_allph2.stop).all() bursts_sel2 = bursts_allph.recompute_index_reduce(times_sel) assert (times_sel[bursts_sel2.istart] == bursts_sel2.start).all() assert (times_sel[bursts_sel2.istop] == bursts_sel2.stop).all() assert bursts_sel2 == bursts_sel # Test round-trip bursts_allph3 = bursts_sel2.recompute_index_expand(mask_sel) assert bursts_allph3 == bursts_allph2 assert (times_allph[bursts_allph3.istart] == bursts_allph3.start).all() assert (times_allph[bursts_allph3.istop] == bursts_allph3.stop).all()
def test_burst_selection_ranges(data): """Test selection functions having a min-max range. """ d = data d.burst_search() d.calc_max_rate(m=10, ph_sel=Ph_sel(Dex='DAem')) Range = namedtuple('Range', ['min', 'max', 'getter']) sel_functions = dict( E=Range(0.5, 1, None), nd=Range(30, 40, None), na=Range(30, 40, None), time=Range(1, 61, lambda d, ich: d.mburst[ich].start * d.clk_p), width=Range(0.5, 1.5, lambda d, ich: d.mburst[ich].width * d.clk_p * 1e3), peak_phrate=Range(50e3, 150e3, lambda d, ich: d.max_rate[ich])) if d.alternated: sel_functions.update(naa=Range(30, 40, None), S=Range(0.3, 0.7, None)) for func_name, range_ in sel_functions.items(): func = getattr(select_bursts, func_name) getter = range_.getter if getter is None: getter = lambda d, ich: d[func_name][ich] ds = d.select_bursts(func, args=(range_.min, range_.max)) for ich in range(d.nch): selected = getter(ds, ich) assert ((selected >= range_.min) * (selected <= range_.max)).all()
def test_ph_in_bursts_ich(data): """Tests the ph_in_bursts_ich method. """ d = data for ich in range(d.nch): ph_in_bursts = d.ph_in_bursts_ich(ich) ph_in_bursts_dd = d.ph_in_bursts_ich(ich, ph_sel=Ph_sel(Dex='Dem')) assert ph_in_bursts_dd.size < ph_in_bursts.size
def test_iter_ph_times(data): """Test method .iter_ph_times() for all the ph_sel combinations. """ # TODO add all the ph_sel combinations like in test_bg_from() d = data assert list_array_equal(d.ph_times_m, d.iter_ph_times()) for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='Dem'))): if d.alternated: assert (ph == d.ph_times_m[ich][d.D_em[ich] * d.D_ex[ich]]).all() else: assert (ph == d.ph_times_m[ich][~d.A_em[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='Aem'))): if d.alternated: assert (ph == d.ph_times_m[ich][d.A_em[ich] * d.D_ex[ich]]).all() else: assert (ph == d.ph_times_m[ich][d.A_em[ich]]).all() if d.alternated: for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Aex='Dem'))): assert (ph == d.ph_times_m[ich][d.D_em[ich] * d.A_ex[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Aex='Aem'))): assert (ph == d.ph_times_m[ich][d.A_em[ich] * d.A_ex[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='DAem'))): assert (ph == d.ph_times_m[ich][d.D_ex[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Aex='DAem'))): assert (ph == d.ph_times_m[ich][d.A_ex[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='Dem', Aex='Dem'))): assert (ph == d.ph_times_m[ich][d.D_em[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='Aem', Aex='Aem'))): assert (ph == d.ph_times_m[ich][d.A_em[ich]]).all() for ich, ph in enumerate(d.iter_ph_times(Ph_sel(Dex='DAem', Aex='Aem'))): mask = d.D_ex[ich] + d.A_em[ich] * d.A_ex[ich] assert (ph == d.ph_times_m[ich][mask]).all() else: assert list_array_equal(d.iter_ph_times(), d.iter_ph_times(Ph_sel(Dex='DAem')))
def test_stale_fitter_after_burst_search(data): """Test that E/S_fitter attributes are deleted on burst search.""" data.burst_search(L=10, m=10, F=7, ph_sel=Ph_sel(Dex='Dem')) bplt.dplot(data, bplt.hist_fret) # create E_fitter attribute if data.alternated: bplt.dplot(data, bplt.hist_S) # create S_fitter attribute data.burst_search(L=10, m=10, F=7, ph_sel=Ph_sel(Dex='Aem')) assert not hasattr(data, 'E_fitter') if data.alternated: assert not hasattr(data, 'S_fitter') bplt.dplot(data, bplt.hist_fret) # create E_fitter attribute if data.alternated: bplt.dplot(data, bplt.hist_S) # create S_fitter attribute data.calc_fret() assert not hasattr(data, 'E_fitter') if data.alternated: assert not hasattr(data, 'S_fitter')
def test_ph_sel(): # Assign one excitation for i, k in enumerate(('Dex', 'Aex')): for v in ('Dem', 'Aem', 'DAem'): p = Ph_sel(**{k: v}) assert p[i] == v if v == 'DAem': assert str(p) == k # [Dex|Aex] representations else: assert str(p) == k + v # [Dex|Aex][Dem|Aem] representations # Assign both excitations for dv, av in product(('Dem', 'Aem', 'DAem', None), repeat=2): if dv is None and av is None: with pytest.raises(ValueError): Ph_sel(Dex=dv, Aex=av) else: p = Ph_sel(Dex=dv, Aex=av) assert p.Dex == dv assert p.Aex == av if dv == av != 'DAem': p_str = dv if dv != 'DAem' else 'all' assert str(p) == p_str # [Dem|Aem|all] representations # Test some corner cases assert Ph_sel('all') == Ph_sel(Dex='DAem', Aex='DAem') assert str(Ph_sel(Dex='DAem', Aex='Aem')) == 'DexDAem_AexAem' # Test str <-> Ph_sel mapping m = Ph_sel._get_str_mapping() assert len(set(m.values())) == len(set(m.keys())) m_inv = {v: k for k, v in m.items()} assert m_inv == Ph_sel._get_str_mapping(invert=True) # Test Ph_sel.from_str() str_reprs = Ph_sel._get_str_mapping().values() for p_str in str_reprs: assert Ph_sel.from_str(p_str) == m_inv[p_str]
def test_bg_calc(data): """Smoke test bg_calc() and test deletion of bg fields. """ data.calc_bg(bg.exp_fit, time_s=30, tail_min_us=300) assert 'bg_auto_th_us0' not in data assert 'bg_auto_F_bg' not in data assert 'bg_th_us_user' in data data.calc_bg(bg.exp_fit, time_s=30, tail_min_us='auto', F_bg=1.7) assert 'bg_auto_th_us0' in data assert 'bg_auto_F_bg' in data assert 'bg_th_us_user' not in data data.calc_bg(bg.exp_fit, time_s=30, tail_min_us='auto', F_bg=1.7, fit_allph=False) streams = [s for s in data.ph_streams if s != Ph_sel('all')] bg_t = [ np.sum(data.bg[s][ich] for s in streams) for ich in range(data.nch) ] assert list_array_equal(data.bg[Ph_sel('all')], bg_t)
def test_burst_corrections(data): """Test background and bleed-through corrections.""" d = data d.calc_ph_num(alex_all=True) d.corrections() leakage = d.get_leakage_array() for ich, bursts in enumerate(d.mburst): if bursts.num_bursts == 0: continue # if no bursts skip this ch nd, na, bg_d, bg_a, width = d.expand(ich, width=True) burst_size_raw = bursts.counts lk = leakage[ich] if d.alternated: nda, naa = d.nda[ich], d.naa[ich] period = d.bp[ich] bg_da = d.bg_from(Ph_sel(Aex='Dem'))[ich][period] * width bg_aa = d.bg_from(Ph_sel(Aex='Aem'))[ich][period] * width burst_size_raw2 = (nd + na + bg_d + bg_a + lk * nd + nda + naa + bg_da + bg_aa) assert np.allclose(burst_size_raw, burst_size_raw2) else: burst_size_raw2 = nd + na + bg_d + bg_a + lk * nd assert np.allclose(burst_size_raw, burst_size_raw2)
def test_ph_times_compact(data_1ch): """Test calculation of ph_times_compact.""" def isinteger(x): return np.equal(np.mod(x, 1), 0) ich = 0 d = data_1ch ph_d = d.get_ph_times(ph_sel=Ph_sel(Dex='DAem')) ph_a = d.get_ph_times(ph_sel=Ph_sel(Aex='DAem')) ph_dc = d.get_ph_times(ph_sel=Ph_sel(Dex='DAem'), compact=True) ph_ac = d.get_ph_times(ph_sel=Ph_sel(Aex='DAem'), compact=True) # Test that the difference of ph and ph_compact is multiple of # the complementary excitation period duration Dex_void = bl._excitation_width(d._D_ON_multich[ich], d.alex_period) Aex_void = bl._excitation_width(d._A_ON_multich[ich], d.alex_period) assert isinteger((ph_d - ph_dc) / Dex_void).all() assert isinteger((ph_a - ph_ac) / Aex_void).all() # Test that alternation histogram does not have "gaps" for ph_compact bins = np.linspace(0, d.alex_period, num=101) hist_dc, _ = np.histogram(ph_dc % d.alex_period, bins=bins) hist_ac, _ = np.histogram(ph_ac % d.alex_period, bins=bins) assert (hist_dc > 0).all() assert (hist_ac > 0).all()
def test_iter_ph_times_period(data): d = data for ich in range(data.nch): for period, ph_period in enumerate(d.iter_ph_times_period(ich=ich)): istart, iend = d.Lim[ich][period] assert (ph_period == d.ph_times_m[ich][istart:iend + 1]).all() ph_sel = Ph_sel(Dex='Dem') mask = d.get_ph_mask(ich=ich, ph_sel=ph_sel) for period, ph_period in enumerate( d.iter_ph_times_period(ich=ich, ph_sel=ph_sel)): istart, iend = d.Lim[ich][period] ph_period_test = d.ph_times_m[ich][istart:iend + 1] ph_period_test = ph_period_test[mask[istart:iend + 1]] assert (ph_period == ph_period_test).all()
def test_burst_ph_data_functions(data): """Tests the functions that iterate or operate on per-burst "ph-data". """ d = data for bursts, ph, mask in zip(d.mburst, d.iter_ph_times(), d.iter_ph_masks(Ph_sel(Dex='Dem'))): bstart = bursts.start bend = bursts.stop for i, (start, stop) in enumerate(bl.iter_bursts_start_stop(bursts)): assert ph[start] == bstart[i] assert ph[stop - 1] == bend[i] for i, burst_ph in enumerate(bl.iter_bursts_ph(ph, bursts)): assert burst_ph[0] == bstart[i] assert burst_ph[-1] == bend[i] for i, burst_ph in enumerate(bl.iter_bursts_ph(ph, bursts, mask=mask)): if burst_ph.size > 0: assert burst_ph[0] >= bstart[i] assert burst_ph[-1] <= bend[i] stats = bl.burst_ph_stats(ph, bursts, mask=mask) assert (stats[~np.isnan(stats)] >= bstart[~np.isnan(stats)]).all() assert (stats[~np.isnan(stats)] <= bend[~np.isnan(stats)]).all() bistart = bursts.istart biend = bursts.istop bursts_mask = bl.ph_in_bursts_mask(ph.size, bursts) for i, (start, stop) in enumerate(bl.iter_bursts_start_stop(bursts)): assert bursts_mask[start:stop].all() if start > 0: if i > 0 and biend[i - 1] < bistart[i] - 1: assert not bursts_mask[start - 1] if stop < ph.size: if i < bistart.size - 1 and bistart[i + 1] > biend[i] + 1: assert not bursts_mask[stop]
def test_get_ph_times_period(data): for ich in range(data.nch): data.get_ph_times_period(0, ich=ich) data.get_ph_times_period(0, ich=ich, ph_sel=Ph_sel(Dex='Dem'))
def test_calc_max_rate(data): """Smoke test for Data.calc_max_rate()""" data.calc_max_rate(m=10) if data.alternated: data.calc_max_rate(m=10, ph_sel=Ph_sel(Dex='DAem'), compact=True)
def test_burst_size_pax(): d = load_fake_pax() aex_dex_ratio = d._aex_dex_ratio nd, na = d.nd[0], d.na[0] nda, naa = d.nda[0], d.naa[0] naa_aexonly = naa - d.nar[0] * aex_dex_ratio # Test burst size during Dex b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel(Dex='DAem')) b2 = d.burst_sizes_ich(add_naa=False) b3 = nd + na assert (b1 == b2).all() assert (b1 == b3).all() # Test burst size during Dex + AexAem b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel(Dex='DAem', Aex='Aem'), naa_aexonly=True) b2 = d.burst_sizes_ich(add_naa=True) b3 = nd + na + naa_aexonly assert (b1 == b2).all() assert (b1 == b3).all() # Test burst size during AexAem b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel(Dex=None, Aex='Aem'), naa_aexonly=True) b2 = naa_aexonly assert (b1 == b2).all() # Test all-ph size with no corrections b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all')) b2 = nd + na + nda + naa assert np.allclose(b1, b2) # Test all-ph size with all corrections b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_comp=True, naa_aexonly=True) b2 = (nd + na * (1 + aex_dex_ratio) + nda + naa_aexonly * (1 + aex_dex_ratio)) assert np.allclose(b1, b2) # Test all-ph size with only na_comp b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True) b2 = (nd + na * (1 + aex_dex_ratio) + nda + naa) assert np.allclose(b1, b2) # Test all-ph size with na_comp + naa_aexonly b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_aexonly=True) b2 = (nd + na * (1 + aex_dex_ratio) + nda + naa_aexonly) assert np.allclose(b1, b2) # Test add_aex with duty-cycle correction, gamma, beta gamma = 0.7 beta = 0.85 b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_comp=True, naa_aexonly=True, gamma=gamma, beta=beta, donor_ref=True) b2 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_comp=True, naa_aexonly=True, gamma=gamma, beta=beta, donor_ref=False) b3 = (gamma * (nd + nda) + na * (1 + aex_dex_ratio) + naa_aexonly * (1 + aex_dex_ratio) / beta) assert np.allclose(b1 * gamma, b2) assert np.allclose(b2, b3) b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel(Dex='DAem', Aex='Aem'), naa_aexonly=True, gamma=gamma, beta=beta, donor_ref=False) b2 = d.burst_sizes_ich(add_naa=True, gamma=gamma, beta=beta, donor_ref=False) assert np.allclose(b1, b2) d.leakage = 0.1 nd, na = d.nd[0], d.na[0] nda, naa = d.nda[0], d.naa[0] naa_aexonly = naa - d.nar[0] * aex_dex_ratio # Test add_aex with duty-cycle correction, gamma, beta gamma = 0.7 beta = 0.85 b1 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_comp=True, naa_aexonly=True, gamma=gamma, beta=beta, donor_ref=True) b2 = d.burst_sizes_pax_ich(ph_sel=Ph_sel('all'), na_comp=True, naa_comp=True, naa_aexonly=True, gamma=gamma, beta=beta, donor_ref=False) b3 = (gamma * (nd + nda) + na * (1 + aex_dex_ratio) + naa_aexonly * (1 + aex_dex_ratio) / beta) assert np.allclose(b1 * gamma, b2) assert np.allclose(b2, b3)
def test_ph_streams(data): sel = [Ph_sel('all'), Ph_sel(Dex='Dem'), Ph_sel(Dex='Aem')] if data.alternated: sel.extend([Ph_sel(Aex='Aem'), Ph_sel(Aex='Dem')]) for s in sel: assert s in data.ph_streams
def test_bg_from(data): """Test the method .bg_from() for all the ph_sel combinations. """ d = data for sel in d.ph_streams: bg = d.bg_from(ph_sel=sel) assert list_array_equal(bg, d.bg[sel]) if not (data.alternated): assert list_array_equal(d.bg_from(Ph_sel('all')), d.bg_from(Ph_sel(Dex='DAem'))) return bg_dd = d.bg_from(ph_sel=Ph_sel(Dex='Dem')) bg_ad = d.bg_from(ph_sel=Ph_sel(Dex='Aem')) bg = d.bg_from(ph_sel=Ph_sel(Dex='DAem')) assert list_array_equal(bg, [b1 + b2 for b1, b2 in zip(bg_dd, bg_ad)]) bg_aa = d.bg_from(ph_sel=Ph_sel(Aex='Aem')) bg_da = d.bg_from(ph_sel=Ph_sel(Aex='Dem')) bg = d.bg_from(ph_sel=Ph_sel(Aex='DAem')) assert list_array_equal(bg, [b1 + b2 for b1, b2 in zip(bg_aa, bg_da)]) bg = d.bg_from(ph_sel=Ph_sel(Dex='Dem', Aex='Dem')) assert list_array_equal(bg, [b1 + b2 for b1, b2 in zip(bg_dd, bg_da)]) bg = d.bg_from(ph_sel=Ph_sel(Dex='Aem', Aex='Aem')) assert list_array_equal(bg, [b1 + b2 for b1, b2 in zip(bg_ad, bg_aa)]) bg = d.bg_from(ph_sel=Ph_sel(Dex='DAem')) assert list_array_equal(bg, [b1 + b2 for b1, b2 in zip(bg_dd, bg_ad)]) bg = d.bg_from(ph_sel=Ph_sel(Dex='DAem', Aex='Aem')) bg2 = [b1 + b2 + b3 for b1, b2, b3 in zip(bg_dd, bg_ad, bg_aa)] assert list_array_equal(bg, bg2)