예제 #1
0
def setup_two(make_data_path):

    from sherpa.astro.io import read_pha, read_arf, read_rmf
    from sherpa.astro import xspec

    abs1 = xspec.XSphabs('abs1')
    p1 = PowLaw1D('p1')

    model = abs1 * p1 * 1e-4

    pi2278 = make_data_path("pi2278.fits")
    pi2286 = make_data_path("pi2286.fits")
    data_pi2278 = read_pha(pi2278)
    data_pi2286 = read_pha(pi2286)

    data_pi2278.set_rmf(read_rmf(make_data_path('rmf2278.fits')))
    data_pi2278.set_arf(read_arf(make_data_path('arf2278.fits')))

    data_pi2286.set_rmf(read_rmf(make_data_path('rmf2286.fits')))
    data_pi2286.set_arf(read_arf(make_data_path('arf2286.fits')))

    rsp_pi2278 = Response1D(data_pi2278)
    rsp_pi2286 = Response1D(data_pi2286)
    return {
        'data_pi2278': data_pi2278,
        'data_pi2286': data_pi2286,
        'model_pi2278': rsp_pi2278(model),
        'model_pi2286': rsp_pi2286(model)
    }
예제 #2
0
    def setUp(self):
        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)
        from sherpa.astro.io import read_pha
        from sherpa.astro import xspec

        # Ensure we have a known set of XSPEC settings.
        # At present this is just the abundance and cross-section,
        # since the cosmology settings do not affect any of the
        # models used here.
        #
        self._xspec_settings = {
            'abund': xspec.get_xsabund(),
            'xsect': xspec.get_xsxsect()
        }

        xspec.set_xsabund('angr')
        xspec.set_xsxsect('bcmc')

        pha_fname = self.make_path("9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = xspec.XSphabs('abs1')
        p1 = PowLaw1D('p1')
        self.model = abs1 + p1

        self.model_mult = abs1 * p1
        pi2278 = self.make_path("pi2278.fits")
        pi2286 = self.make_path("pi2286.fits")
        self.data_pi2278 = read_pha(pi2278)
        self.data_pi2286 = read_pha(pi2286)
예제 #3
0
    def setUp(self):
        try:
            from sherpa.astro.io import read_pha
            from sherpa.astro.xspec import XSwabs, XSpowerlaw
        except:
            return
        # self.startdir = os.getcwd()
        self.old_level = logger.getEffectiveLevel()
        logger.setLevel(logging.CRITICAL)

        pha = self.make_path("refake_0934_1_21_1e4.fak")
        # rmf = self.make_path("ccdid7_default.rmf")
        # arf = self.make_path("quiet_0934.arf")

        self.simarf = self.make_path("aref_sample.fits")
        self.pcaarf = self.make_path("aref_Cedge.fits")

        data = read_pha(pha)
        data.ignore(None, 0.3)
        data.ignore(7.0, None)

        rsp = Response1D(data)
        self.abs1 = XSwabs('abs1')
        self.p1 = XSpowerlaw('p1')
        model = rsp(self.abs1 * self.p1)

        self.fit = Fit(data, model, CStat(), NelderMead(), Covariance())
def loadup_3c273(use_errors, subt, noticed, make_data_path):
    """Load up the 3C273 data.

    Requires @requires_fits and @requires_data on the test.
    """

    # We could create a PHA object but it's easiest to use
    # an on-disk version to setup everything.
    #
    path = make_data_path("3c273.pi")
    pha = io.read_pha(path, use_errors=use_errors)

    if subt:
        pha.subtract()
    else:
        pha.unsubtract()

    if noticed:
        # After this, we have both
        #   pha.get_filter(format="%.3f")
        #   pha.get_background().get_filter(format="%.3f")
        # returning
        #   "0.518:1.986,4.869:8.220"
        #
        # In channels this is
        #   "36:136,334:563"
        #
        pha.notice(0.5, 2)
        pha.notice(5, 7)

    return pha
예제 #5
0
def test_dataphahistogram_prepare_wavelength(make_data_path):
    """Check we can use wavelength setting"""

    from sherpa.astro.io import read_pha

    # could fake a dataset but it's easier to use one
    infile = make_data_path('3c273.pi')
    pha = read_pha(infile)
    pha.name = 'my-name.pi'

    # Also check out the type='counts' option
    pha.set_analysis('wave', type='counts')
    pha.notice(3, 5)

    plot = aplot.DataPHAPlot()
    plot.prepare(pha)

    assert plot.xlabel == 'Wavelength (Angstrom)'
    assert plot.ylabel == 'Counts/Angstrom'
    assert plot.title == 'my-name.pi'

    # data is inverted
    assert plot.xlo[0] > plot.xlo[-1]

    # can we access the "pseudo" x attribute?
    assert plot.x[0] > plot.x[-1]

    assert np.all(plot.y > 0)

    # regression test
    yexp = np.asarray([39.44132393, 68.92072985, 64.39425057,
                       48.69954162, 41.17454851, 88.87982014,
                       74.70504415, 79.22094498, 94.57773635])
    assert plot.y == pytest.approx(yexp)
예제 #6
0
    def setUp(self):
        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)
        from sherpa.astro.xspec import XSphabs
        from sherpa.astro.io import read_pha

        pha_fname = self.make_path("9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = XSphabs('abs1')
        p1 = PowLaw1D('p1')
        self.model = abs1 + p1
예제 #7
0
def setup(make_data_path):
    from sherpa.astro.io import read_pha
    from sherpa.astro.xspec import XSwabs, XSpowerlaw

    old_level = logger.getEffectiveLevel()
    logger.setLevel(logging.CRITICAL)

    pha = make_data_path("refake_0934_1_21_1e4.fak")

    simarf = make_data_path("aref_sample.fits")
    pcaarf = make_data_path("aref_Cedge.fits")

    data = read_pha(pha)
    data.ignore(None, 0.3)
    data.ignore(7.0, None)

    rsp = Response1D(data)
    abs1 = XSwabs('abs1')
    p1 = XSpowerlaw('p1')
    model = rsp(abs1 * p1)

    abs1.nh = 0.092886
    p1.phoindex = 0.994544
    p1.norm = 9.26369

    fit = Fit(data, model, CStat(), NelderMead(), Covariance())

    yield {'simarf': simarf,
           'pcaarf': pcaarf,
           'niter': 10,
           'fit': fit}

    # Reset the logger
    logger.setLevel(old_level)
예제 #8
0
def test_sourceplot_prepare_wavelength(make_data_path):
    """Check we can use wavelength setting"""

    from sherpa.astro.io import read_pha

    # could fake a dataset but it's easier to use one
    infile = make_data_path('3c273.pi')
    pha = read_pha(infile)
    pha.name = 'my-name.pi'

    pha.set_analysis('wave')
    pha.notice(3, 5)

    mdl = Const1D()

    # not bothered too much about the model (e.g. setting a response)
    #
    plot = aplot.SourcePlot()
    plot.prepare(pha, mdl)

    assert plot.xlabel == 'Wavelength (Angstrom)'
    assert plot.ylabel == 'f(lambda)  Photons/sec/cm$^2$/Angstrom '
    assert plot.title == 'Source Model of my-name.pi'

    # data is inverted
    assert plot.xlo[0] > plot.xlo[-1]
    assert plot.xlo[0] > plot.xhi[0]
    assert np.all(plot.y > 0)
    assert plot.y.size == 1090
예제 #9
0
파일: test_sim.py 프로젝트: valkenar/sherpa
    def setUp(self):
        try:
            from sherpa.astro.io import read_pha
            from sherpa.astro.xspec import XSwabs, XSpowerlaw
        except:
            return
        #self.startdir = os.getcwd()
        self.old_level = logger.getEffectiveLevel()
        logger.setLevel(logging.CRITICAL)

        datadir = SherpaTestCase.datadir
        if datadir is None:
            return

        pha = os.path.join(datadir, "refake_0934_1_21_1e4.fak")
        rmf = os.path.join(datadir, "ccdid7_default.rmf")
        arf = os.path.join(datadir, "quiet_0934.arf")
        
        self.simarf = os.path.join(datadir, "aref_sample.fits")
        self.pcaarf = os.path.join(datadir, "aref_Cedge.fits")

        data = read_pha(pha)
        data.ignore(None,0.3)
        data.ignore(7.0,None)

        rsp = Response1D(data)
        self.abs1 = XSwabs('abs1')
        self.p1 = XSpowerlaw('p1')
        model = rsp(self.abs1*self.p1)
        
        self.fit = Fit(data, model, CStat(), NelderMead(), Covariance())
예제 #10
0
def test_bug38_filtering_grouping(make_data_path):
    """Low-level tests related to bugs #38, #917: filter+group"""

    from sherpa.astro.io import read_pha
    pha = read_pha(make_data_path('3c273.pi'))

    pha.notice(1, 6)
    pha.ignore(3, 4)

    assert pha.get_filter(group=True, format='%.4f') == '1.0147:2.7886,4.1391:6.2342'
    assert pha.get_filter(group=False, format='%.4f') == '1.0001:2.8543,4.0369:6.5627'

    pha.group_width(40)

    assert pha.get_filter(group=True, format='%.4f') == '0.8760:2.6280,3.7960:6.7160'
    assert pha.get_filter(group=False, format='%.4f') == '0.5913:2.9127,3.5113:7.0007'

    assert pha.mask.size == 26
    assert pha.mask.sum() == 10
    assert pha.mask[1:5].all()
    assert pha.mask[6:12].all()

    # get the ungrouped mask
    mask = pha.get_mask()
    assert mask.sum() == 10 * 40
    assert mask[40:200].all()
    assert mask[240:480].all()

    # check filtered bins
    elo_all, ehi_all = pha._get_ebins(group=False)
    elo, ehi = pha._get_ebins(group=True)

    assert elo[1] == elo_all[40]
    assert ehi[11] == ehi_all[479]
예제 #11
0
    def setUp(self):
        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)
        from sherpa.astro.xspec import XSphabs
        from sherpa.astro.io import read_pha

        pha_fname = self.make_path("9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = XSphabs("abs1")
        p1 = PowLaw1D("p1")
        self.model = abs1 + p1
예제 #12
0
def setup_bkg(make_data_path):

    from sherpa.astro.io import read_pha, read_arf, read_rmf
    from sherpa.astro import xspec

    infile = make_data_path("9774_bg.pi")
    bkg = read_pha(infile)
    bkg.exposure = 1

    arf = read_arf(make_data_path('9774.arf'))
    rmf = read_rmf(make_data_path('9774.rmf'))
    bkg.set_arf(arf)
    bkg.set_rmf(rmf)

    bkg.set_analysis('energy')
    bkg.notice(0.5, 7.0)

    # We stay with a linear scale for the absorption model
    # here as the values don't seem to go below 0.1.
    #
    abs1 = xspec.XSwabs('abs1')
    p1 = PowLaw1D('p1')
    model = abs1 * p1

    p1.ampl = 1e-4

    rsp = Response1D(bkg)
    return {'bkg': bkg, 'model': rsp(model)}
예제 #13
0
def test_pha_real(subtract, group, make_data_path, override_plot_backend):
    """This is grouped and has a background"""
    from sherpa.astro.io import read_pha
    d = read_pha(make_data_path('3c273.pi'))
    d.name = '3c273.pi'

    if not group:
        d.ungroup()

    d.notice(0.5, 7)
    if subtract:
        d.subtract()

    r = d._repr_html_()

    check(r, 'PHA', '3c273.pi', 'COUNTS', nmeta=11)

    assert '<div class="dataval">2000-01-10T06:47:15</div>' in r
    assert '<div class="dataname">Background</div>' in r
    assert '<div class="dataname">Grouping</div>' in r

    if subtract:
        assert '<div class="dataval">Subtracted</div>' in r
    else:
        assert '<div class="dataval">Not subtracted</div>' in r

    if group:
        assert '<div class="dataval">Applied (46 groups)</div>' in r
        assert '<div class="dataval">0.4672-9.8696 Energy (keV) with 42 groups</div>' in r
    else:
        assert '<div class="dataval">Not applied</div>' in r
        assert '<div class="dataval">0.4964-7.0080 Energy (keV) with 446 channels</div>' in r
def test_read_pha_fails_rmf(make_data_path):
    """Just check in we can't read in a RMF as a PHA file."""

    if backend_is("pyfits"):
        emsg = " does not appear to be a PHA spectrum"
        etype = IOErr
    elif backend_is("crates"):
        emsg = "dmKeyRead() could not find key. 'HDUCLAS1'"
        etype = ValueError
    else:
        assert False, f"Internal error: unknown backend {io.backend}"

    infile = make_data_path(RMFFILE)
    with pytest.raises(etype) as excinfo:
        io.read_pha(infile)

    assert emsg in str(excinfo.value)
예제 #15
0
def test_read_pha_fails_arf(make_data_path):
    """Just check in we can't read in an ARF as a PHA file."""

    if backend_is("pyfits"):
        emsg = " does not appear to be a PHA spectrum"
        etype = IOErr
    elif backend_is("crates"):
        emsg = "File must be a PHA file."
        etype = TypeError
    else:
        assert False, f"Internal error: unknown backend {io.backend}"

    infile = make_data_path(ARFFILE)
    with pytest.raises(etype) as excinfo:
        io.read_pha(infile)

    assert emsg in str(excinfo.value)
예제 #16
0
def test_read_pha_fails_rmf(make_data_path):
    """Just check in we can't read in a RMF as a PHA file."""

    if backend == 'pyfits':
        emsg = " does not appear to be a PHA spectrum"
        etype = IOErr
    elif backend == 'crates':
        emsg = "dmKeyRead() could not find key. 'HDUCLAS1'"
        etype = ValueError
    else:
        assert False, "Internal error: unknown backend {}".format(backend)

    infile = make_data_path(RMFFILE)
    with pytest.raises(etype) as excinfo:
        io.read_pha(infile)

    assert emsg in str(excinfo.value)
예제 #17
0
def test_read_pha_fails_arf(make_data_path):
    """Just check in we can't read in an ARF as a PHA file."""

    if backend == 'pyfits':
        emsg = " does not appear to be a PHA spectrum"
        etype = IOErr
    elif backend == 'crates':
        emsg = 'File must be a PHA file.'
        etype = TypeError
    else:
        assert False, "Internal error: unknown backend {}".format(backend)

    infile = make_data_path(ARFFILE)
    with pytest.raises(etype) as excinfo:
        io.read_pha(infile)

    assert emsg in str(excinfo.value)
예제 #18
0
def test_read_pha_fails_rmf(make_data_path):
    """Just check in we can't read in a RMF as a PHA file."""

    if backend == 'pyfits':
        emsg = " does not appear to be a PHA spectrum"
        etype = IOErr
    elif backend == 'crates':
        emsg = 'File must be a PHA file.'
        etype = TypeError
    else:
        assert False, "Internal error: unknown backend {}".format(backend)

    infile = make_data_path(RMFFILE)
    with pytest.raises(etype) as excinfo:
        io.read_pha(infile)

    assert emsg in str(excinfo.value)
예제 #19
0
    def setUp(self):
        try:
            from sherpa.astro.xspec import XSphabs, XSpowerlaw
            from sherpa.astro.io import read_pha
        except:
            return

        pha_fname = self.make_path("stats/9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("stats/9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = XSphabs('abs1')
        p1 = PowLaw1D('p1')
        self.model = abs1 + p1
예제 #20
0
    def setUp(self):
        try:
            from sherpa.astro.xspec import XSphabs, XSpowerlaw
            from sherpa.astro.io import read_pha
        except:
            return

        pha_fname = self.make_path("stats/9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("stats/9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = XSphabs('abs1')
        p1 = PowLaw1D('p1')
        self.model = abs1 + p1
예제 #21
0
def test_bug38_filtering(make_data_path):
    """Low-level tests related to bugs #38, #917: filter"""

    from sherpa.astro.io import read_pha
    pha = read_pha(make_data_path('3c273.pi'))

    assert pha.mask is True
    pha.notice(0.3, 2)
    assert pha.mask.size == 46
    assert pha.mask.sum() == 25
    assert pha.mask[1:26].all()
예제 #22
0
파일: test_stats.py 프로젝트: mirca/sherpa
    def setUp(self):
        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)
        from sherpa.astro.io import read_pha
        from sherpa.astro.xspec import XSphabs

        pha_fname = self.make_path("9774.pi")
        self.data = read_pha(pha_fname)
        self.data.notice(0.5, 7.0)

        bkg_fname = self.make_path("9774_bg.pi")
        self.bkg = read_pha(bkg_fname)

        abs1 = XSphabs('abs1')
        p1 = PowLaw1D('p1')
        self.model = abs1 + p1

        self.model_mult = abs1 * p1
        pi2278 = self.make_path("pi2278.fits")
        pi2286 = self.make_path("pi2286.fits")
        self.data_pi2278 = read_pha(pi2278)
        self.data_pi2286 = read_pha(pi2286)
예제 #23
0
def test_xmmrgs_notice(make_data_path):
    '''Test that notice and ignore works on XMMRGS dataset, which is
    ordered in increasing wavelength, not energy'''
    from sherpa.astro.io import read_pha, read_rmf
    dat = read_pha(make_data_path('xmmrgs/P0112880201R1S004SRSPEC1003.FTZ'))
    rmf = read_rmf(make_data_path('xmmrgs/P0112880201R1S004RSPMAT1003.FTZ'))
    dat.set_rmf(rmf)
    dat.units = 'wave'
    dat.notice(18.8, 19.2)
    assert len(dat.get_dep(filter=True)) == 41
    assert dat.get_filter(format='%.2f') == '18.80:19.21'

    dat.ignore(10, 19.)
    assert len(dat.get_dep(filter=True)) == 20
    assert dat.get_filter(format='%.2f') == '19.01:19.21'
예제 #24
0
def test_read_pha(make_data_path):
    """Can we read in a Swift PHA file."""

    infile = make_data_path(PHAFILE)
    pha = io.read_pha(infile)
    assert isinstance(pha, DataPHA)

    # assert_allclose defaults to a tolerance of 1e-7
    # which is close to the precision these values are stored
    # in the file.
    assert_allclose(pha.exposure, 4812.26699895)
    assert_allclose(pha.backscal, 1.148e-3)
    assert_allclose(pha.areascal, 1.0)

    # Although channel is an integer, it's treated as a
    # float. Note that the channels start at 0 in the file,
    # but they are promoted to 1 by the crates backend.
    # XSPEC 12.9.1b, on reading this file, reports channel numbers
    # between 1 and 1024 inclusive.
    #
    nchan = 1024
    assert_allclose(pha.channel, np.arange(1, nchan + 1))

    # Rather than check each element, use some simple summary
    # statistics.
    assert len(pha.counts) == nchan
    assert_allclose(pha.counts.min(), 0.0)
    assert_allclose(pha.counts.max(), 3.0)
    assert_allclose(pha.counts.sum(), 58.0)
    assert np.argmax(pha.counts) == 110

    for field in [
            'staterror', 'syserror', 'bin_lo', 'bin_hi', 'grouping', 'quality'
    ]:
        assert getattr(pha, field) is None

    assert pha.grouped is False
    assert pha.subtracted is False
    assert pha.units == 'channel'
    assert pha.rate
    assert pha.plot_fac == 0
    assert pha.response_ids == []
    assert pha.background_ids == []
    assert pha.get_background() is None
예제 #25
0
def test_write_pha_fits_basic_roundtrip(tmp_path):
    """A very-basic PHA output

    No ancillary information and no header.
    """

    chans = np.arange(1, 5, dtype=np.int16)
    counts = np.asarray([1, 0, 3, 2], dtype=np.int16)
    pha = DataPHA("testy", chans, counts)

    outfile = tmp_path / "out.pi"
    io.write_pha(str(outfile), pha, ascii=False, clobber=False)
    pha = None

    inpha = io.read_pha(str(outfile))
    assert isinstance(inpha, DataPHA)
    assert inpha.channel == pytest.approx(chans)
    assert inpha.counts == pytest.approx(counts)
    for field in ["staterror", "syserror", "bin_lo", "bin_hi",
                  "grouping", "quality", "exposure"]:
        assert getattr(inpha, field) is None

    assert inpha.backscal == pytest.approx(1.0)
    assert inpha.areascal == pytest.approx(1.0)

    assert not inpha.grouped
    assert not inpha.subtracted
    assert inpha.units == "channel"
    assert inpha.rate
    assert inpha.plot_fac == 0
    assert inpha.response_ids == []
    assert inpha.background_ids == []

    if backend_is("crates"):
        check_write_pha_fits_basic_roundtrip_crates(outfile)

    elif backend_is("pyfits"):
        check_write_pha_fits_basic_roundtrip_pyfits(outfile)

    else:
        # Technically this could be dummy_backend but it would have
        # failed earlier.
        #
        raise RuntimeError(f"Unknown io backend: {io.backend}")
예제 #26
0
def test_read_pha(make_data_path):
    """Can we read in a Swift PHA file."""

    infile = make_data_path(PHAFILE)
    pha = io.read_pha(infile)
    assert isinstance(pha, DataPHA)

    # assert_allclose defaults to a tolerance of 1e-7
    # which is close to the precision these values are stored
    # in the file.
    assert_allclose(pha.exposure, 4812.26699895)
    assert_allclose(pha.backscal, 1.148e-3)
    assert_allclose(pha.areascal, 1.0)

    # Although channel is an integer, it's treated as a
    # float. Note that the channels start at 0 in the file,
    # but they are promoted to 1 by the crates backend.
    # XSPEC 12.9.1b, on reading this file, reports channel numbers
    # between 1 and 1024 inclusive.
    #
    nchan = 1024
    assert_allclose(pha.channel, np.arange(1, nchan + 1))

    # Rather than check each element, use some simple summary
    # statistics.
    assert len(pha.counts) == nchan
    assert_allclose(pha.counts.min(), 0.0)
    assert_allclose(pha.counts.max(), 3.0)
    assert_allclose(pha.counts.sum(), 58.0)
    assert np.argmax(pha.counts) == 110

    for field in ['staterror', 'syserror', 'bin_lo', 'bin_hi',
                  'grouping', 'quality']:
        assert getattr(pha, field) is None

    assert pha.grouped is False
    assert pha.subtracted is False
    assert pha.units == 'channel'
    assert pha.rate
    assert pha.plot_fac == 0
    assert pha.response_ids == []
    assert pha.background_ids == []
    assert pha.get_background() is None
예제 #27
0
def setup(make_data_path):

    from sherpa.astro.io import read_pha
    from sherpa.astro import xspec

    infile = make_data_path("9774.pi")
    data = read_pha(infile)
    data.notice(0.3, 7.0)

    # Change the exposure time to make the fitted amplitude
    # > 1
    #
    data.exposure = 1

    # Use the wabs model because it is unlikely to change
    # (as scientifically it is no-longer useful). The problem
    # with using something like the phabs model is that
    # changes to that model in XSPEC could change the results
    # here.
    #
    # We fit the log of the nH since this makes the numbers
    # a bit closer to O(1), and so checking should be easier.
    #
    abs1 = xspec.XSwabs('abs1')
    p1 = PowLaw1D('p1')
    factor = Const1D('factor')
    factor.integrate = False
    model = abs1 * p1 + 0 * factor

    factor.c0 = 0
    abs1.nh = 10**factor.c0

    # Ensure the nh limits are honoured by factor (upper limit only).
    # If you don't do this then the fit can fail because a value
    # outside the abs1.nh but within factor.c0 can be picked.
    #
    factor.c0.max = numpy.log10(abs1.nh.max)

    rsp = Response1D(data)
    return {'data': data, 'model': rsp(model)}
예제 #28
0
def test_1209_background(make_data_path):
    """Do we pick up the header keywords from the background?

    This is related to issue #1209
    """

    # We could set up channels and counts, but let's not.
    #
    d = DataPHA("dummy", None, None)
    assert d.header["TELESCOP"] == "none"
    assert d.header["INSTRUME"] == "none"
    assert d.header["FILTER"] == "none"

    infile = make_data_path(PHAFILE)
    bkg = io.read_pha(infile)
    d.set_background(bkg)

    # The PHA file contains a FILTER keyword but the responses do not.
    #
    assert d.header["TELESCOP"] == "SWIFT"
    assert d.header["INSTRUME"] == "XRT"
    assert d.header["FILTER"] == "NONE"
예제 #29
0
def test_astro_data_plot_with_stat_simple(make_data_path, stat):

    from sherpa.astro import io

    infile = make_data_path('3c273.pi')
    pha = io.read_pha(infile)

    # tweak the data set so that we aren't using the default
    # options (it shouldn't matter for this test but just
    # in case).
    #
    # Note that background subtraction would normally be an issue
    # for some of the stats (e.g. WStat), but this shouldn't
    # trigger a problem here.
    #
    pha.set_analysis('energy')
    pha.subtract()
    pha.ignore(None, 0.5)
    pha.ignore(7.0, None)

    dplot = DataPHAPlot()
    dplot.prepare(pha, stat=stat)
예제 #30
0
def test_bug38_filtering_grouping(make_data_path):
    """Low-level tests related to bugs #38, #917: filter+group"""

    from sherpa.astro.io import read_pha
    pha = read_pha(make_data_path('3c273.pi'))

    pha.notice(1, 6)
    pha.ignore(3, 4)

    expected = '0.9928:2.8616,4.0296:6.5700'
    assert pha.get_filter(group=True, format='%.4f') == expected
    assert pha.get_filter(group=False, format='%.4f') == expected

    pha.group_width(40)

    expected = '0.5840:2.9200,3.5040:7.0080'
    assert pha.get_filter(group=True, format='%.4f') == expected
    assert pha.get_filter(group=False, format='%.4f') == expected

    assert pha.mask.size == 26
    assert pha.mask.sum() == 10
    assert pha.mask[1:5].all()
    assert pha.mask[6:12].all()

    # get the ungrouped mask
    mask = pha.get_mask()
    assert mask.sum() == 10 * 40
    assert mask[40:200].all()
    assert mask[240:480].all()

    # check filtered bins
    elo_all, ehi_all = pha._get_ebins(group=False)
    elo, ehi = pha._get_ebins(group=True)

    assert elo[1] == elo_all[40]
    assert ehi[11] == ehi_all[479]
예제 #31
0
    def setUp(self):
        from sherpa.astro.io import read_pha
        from sherpa.astro.xspec import XSwabs, XSpowerlaw
        # self.startdir = os.getcwd()
        self.old_level = logger.getEffectiveLevel()
        logger.setLevel(logging.CRITICAL)

        pha = self.make_path("refake_0934_1_21_1e4.fak")
        # rmf = self.make_path("ccdid7_default.rmf")
        # arf = self.make_path("quiet_0934.arf")

        self.simarf = self.make_path("aref_sample.fits")
        self.pcaarf = self.make_path("aref_Cedge.fits")

        data = read_pha(pha)
        data.ignore(None, 0.3)
        data.ignore(7.0, None)

        rsp = Response1D(data)
        self.abs1 = XSwabs('abs1')
        self.p1 = XSpowerlaw('p1')
        model = rsp(self.abs1 * self.p1)

        self.fit = Fit(data, model, CStat(), NelderMead(), Covariance())
예제 #32
0
def savefig(name):
    plt.savefig(name)
    print("# Created: {}".format(name))


basedir = get_datadir()
if basedir is None:
    raise IOError("No test data directory")

# Temporarily jump to the directory to get the paths right
cwd = os.getcwd()

os.chdir(basedir)
print(f'--> jumping to {basedir}')
pha = read_pha('3c273.pi')
os.chdir(cwd)

report('pha')
report('pha.get_background()')
report('pha.get_arf()')
report('pha.get_rmf()')

chans = np.arange(1, 1025, dtype=int)
counts = np.ones(1024, dtype=int)
test = DataPHA('example', chans, counts)
report('test')

plot = DataPHAPlot()
plot.histo_prefs['linestyle'] = '-'
plot.prepare(pha)
예제 #33
0
def test_pha_write_xmm_grating(make_data_path, tmp_path):
    """Check we can handle an XMM grating.

    This has an AREASCAL column and WCS attached to the CHANNEL
    column. We don't guarantee the WCS info will be retained or
    propagated.

    """

    def check_header(obj, roundtrip=False):
        # check header for a selected set of keywords
        hdr = obj.header

        # selected OGIP keywords
        assert "HDUNAME" not in hdr

        assert hdr["HDUCLASS"] == "OGIP"
        assert hdr["HDUCLAS1"] == "SPECTRUM"
        assert hdr["HDUCLAS2"] == "NET"
        assert hdr["HDUCLAS3"] == "COUNT"
        if roundtrip:
            assert hdr["HDUCLAS4"] == "TYPE:I"
        else:
            assert "HDUCLAS4" not in hdr
        assert hdr["HDUVERS"] == "1.2.0"
        assert "HDUVERS1" not in hdr

        # a few header keywords to check they are handled,
        # including data types (string, float, integer,
        # logical).
        #
        assert hdr["OBJECT"] == "TW Hya"
        assert hdr["TELESCOP"] == "XMM"
        assert hdr["INSTRUME"] == "RGS1"
        assert hdr["FILTER"] == "UNKNOWN"

        assert not hdr["POISSERR"]
        assert hdr["CHANTYPE"] == "PI"
        assert hdr["DETCHANS"] == 3600

        assert "EXPOSIRE" not in hdr

        assert hdr["SYS_ERR"] == pytest.approx(0.0)
        assert hdr["GROUPING"] == 0
        assert "QUALITY" not in hdr
        assert hdr["CORRSCAL"] == 1
        assert "AREASCAL" not in hdr
        assert "BACKSCAL" not in hdr

        assert hdr["CORRFILE"] == "none"
        for key in ["RESPFILE", "ANCRFILE", "BACKFILE"]:
            assert key not in hdr

        # WCS attached to the CHANNEL column
        if backend_is("crates"):
            assert "TCRYP1" not in hdr
            assert "TCRVL1" not in hdr
            assert "TLMIN1" not in hdr
            assert "TLMAX1" not in hdr

        elif backend_is("pyfits"):
            assert hdr["TCTYP1"] == ""
            assert hdr["TCUNI1"] == "Angstrom"
            assert hdr["TCRPX1"] == 1
            assert hdr["TCRVL1"] == pytest.approx(4.00500011)
            assert hdr["TCDLT1"] == pytest.approx(0.01)

            assert hdr["TLMIN1"] == 1
            assert hdr["TLMAX1"] == 3600

        else:
            assert False  # programming error

    def check_data(obj, roundtrip=False):
        """Basic checks of the data"""

        assert obj.staterror.min() == pytest.approx(1.0)
        assert obj.staterror.sum() == pytest.approx(4496.9490242)
        assert obj.staterror[1498] == pytest.approx(7.937253952)
        assert np.argmax(obj.staterror) == 1498

        assert obj.syserror is None
        assert obj.bin_lo is None
        assert obj.bin_hi is None

        assert obj.exposure == pytest.approx(28965.6406250)
        assert obj.backscal == pytest.approx(1.0)
        assert len(obj.areascal) == 3600
        assert obj.areascal.min() == pytest.approx(0.0)
        assert obj.areascal.max() == pytest.approx(1.0)
        assert obj.areascal.sum() == pytest.approx(2950.6953666)

        for f in ["grouped", "subtracted", "rate"]:
            assert isinstance(getattr(obj, f), bool)

        assert not obj.grouped
        assert not obj.subtracted
        assert obj.rate

        assert obj.plot_fac == 0

        assert obj.channel.dtype == np.dtype("float64")
        assert obj.counts.dtype == np.dtype("float64")

        assert obj.channel == pytest.approx(np.arange(1, 3601))
        assert len(obj.counts) == 3600

        expected = [0, 0, -1, -3, 0, -1, -1, 0, -2, -1]
        assert obj.counts[112:122] == pytest.approx(expected)

        assert obj.grouping is None
        assert len(obj.quality) == 3600
        assert obj.quality.min() == 0
        assert obj.quality.max() == 1
        assert obj.quality.sum() == 741

    infile = make_data_path("xmmrgs/P0112880201R1S004SRSPEC1003.FTZ")
    indata = io.read_pha(infile, use_errors=True)
    assert isinstance(indata, DataPHA)
    assert indata.name.endswith("/P0112880201R1S004SRSPEC1003.FTZ")
    check_header(indata)
    check_data(indata)

    assert indata.response_ids == []
    assert indata.background_ids == []

    assert indata.get_arf() is None
    assert indata.get_rmf() is None
    assert indata.get_background() is None

    # check we can write it out - be explicit with all options
    #
    outfile = tmp_path / "test.pha"
    outfile = str(outfile)  # our IO routines don't recognize paths

    # This is a bit ugly as I want to capture/hide the Astro deprecation
    # warning, but it's only valid when we are using AstroPy.
    #
    if backend_is("pyfits"):
        from astropy.utils.exceptions import AstropyDeprecationWarning
        with pytest.warns(AstropyDeprecationWarning) as ws:
            io.write_pha(outfile, indata, ascii=False, clobber=False)

        # Skip the known "deprecation" error, but flag up any other
        # errors. This is probably excessive (e.g. the message may change
        # textually) but for now see how this goes. I did not want to
        # add this to the generic list of known warnings as I do not like
        # making these affect all tests.
        #
        expected = "The following keywords are now recognized as special column-related attributes and should be set via the Column objects: TCDLTn, TCRPXn, TCRVLn, TCTYPn, TCUNIn. In future, these values will be dropped from manually specified headers automatically and replaced with values generated based on the Column objects."
        if len(ws) > 0:
            assert len(ws) == 1, len(ws)
            assert str(ws[0].message) == expected

    else:
        io.write_pha(outfile, indata, ascii=False, clobber=False)

    outdata = io.read_pha(outfile, use_errors=True)
    assert isinstance(outdata, DataPHA)
    assert outdata.name.endswith("/test.pha")
    check_header(outdata, roundtrip=True)
    check_data(outdata, roundtrip=True)

    # The responses and background should NOT be read in
    # (we are in a different directory to infile so we can't
    # find these files).
    #
    assert outdata.response_ids == []
    assert outdata.background_ids == []

    assert outdata.get_arf() is None
    assert outdata.get_rmf() is None
    assert outdata.get_background() is None
예제 #34
0
def test_pha_write_basic(make_data_path, tmp_path):
    """Check we can write out a PHA file as a FITS file.

    This uses an existing PHA file rather than creating one manually.

    """

    def check_header(obj):
        # check header for a selected set of keywords
        hdr = obj.header

        # selected OGIP keywords
        check_hduname(hdr, "SPECTRUM")

        assert hdr["HDUCLASS"] == "OGIP"
        assert hdr["HDUCLAS1"] == "SPECTRUM"
        assert hdr["HDUCLAS2"] == "TOTAL"
        assert hdr["HDUCLAS3"] == "TYPE:I"
        assert hdr["HDUCLAS4"] == "COUNT"
        assert hdr["HDUVERS"] == "1.1.0"
        assert hdr["HDUVERS1"] == "1.1.0"

        # a few header keywords to check they are handled,
        # including data types (string, float, integer,
        # logical).
        #
        assert hdr["OBJECT"] == "3C 273"
        assert hdr["INSTRUME"] == "ACIS"
        assert hdr["GRATING"] == "HETG"
        assert hdr["DETNAM"] == "ACIS-56789"
        assert hdr["RA_NOM"] == pytest.approx(187.28186566)
        assert hdr["DEC_NOM"] == pytest.approx(2.05610034)
        assert hdr["SIM_X"] == pytest.approx(-0.68282252)
        assert hdr["DATE-OBS"] == "2000-01-10T06:47:15"
        assert isinstance(hdr["CLOCKAPP"], (bool, np.bool_))
        assert hdr["CLOCKAPP"]
        assert hdr["TIMEZERO"] == 0
        assert hdr["DETCHANS"] == 1024

        assert hdr["SYS_ERR"] == pytest.approx(0.0)
        assert hdr["GROUPING"] == 0
        assert hdr["QUALITY"] == 0

    def check_data(obj, roundtrip=False):
        """Basic checks of the data"""

        assert obj.staterror is None
        assert obj.syserror is None
        assert obj.bin_lo is None
        assert obj.bin_hi is None

        assert obj.exposure == pytest.approx(38564.608926889)
        assert np.log10(obj.backscal) == pytest.approx(-5.597491618115439)
        assert obj.areascal == pytest.approx(1.0)
        for f in ["grouped", "subtracted", "rate"]:
            assert isinstance(getattr(obj, f), bool)

        assert obj.grouped
        assert not obj.subtracted
        assert obj.rate

        assert obj.plot_fac == 0

        assert obj.channel.dtype == np.dtype("float64")
        assert obj.counts.dtype == np.dtype("float64")

        assert obj.channel == pytest.approx(np.arange(1, 1025))
        assert len(obj.counts) == 1024
        assert obj.counts[0:11] == pytest.approx(np.zeros(11))
        cvals = [1, 3, 2, 3, 7, 1, 6, 4, 4, 0]
        assert obj.counts[12:22] == pytest.approx(cvals)

        assert len(obj.grouping) == 1024
        if roundtrip:
            assert obj.quality is None
        else:
            assert len(obj.quality) == 1024
            assert obj.quality == pytest.approx(np.zeros(1024))

        if backend_is("crates"):
            assert obj.grouping.dtype == np.dtype("int16")
            if not roundtrip:
                assert obj.quality.dtype == np.dtype("int16")

        elif backend_is("pyfits"):
            assert obj.grouping.dtype == np.dtype(">i2")
            if not roundtrip:
                assert obj.quality.dtype == np.dtype(">i2")

        else:
            pytest.fail("Unrecognized IO backend")

        one, = np.where(obj.grouping == 1)
        expected = [0,  17,  21,  32,  39,  44,  48,  51,  54,  56,  59,  61,  65,
                    68,  71,  75,  78,  82,  88,  96, 101, 110, 116, 124, 130, 133,
                    139, 143, 150, 156, 164, 177, 186, 196, 211, 232, 244, 260, 276,
                    291, 323, 344, 368, 404, 450, 676]
        assert one == pytest.approx(expected)
        assert obj.grouping.sum() == -932
        assert set(obj.grouping) == {-1, 1}

    infile = make_data_path("3c273.pi")
    indata = io.read_pha(infile)
    assert isinstance(indata, DataPHA)
    assert indata.name.endswith("/3c273.pi")
    check_header(indata)
    check_data(indata)

    # The responses and background should be read in
    #
    assert indata.response_ids == pytest.approx([1])
    assert indata.background_ids == pytest.approx([1])

    assert indata.get_arf().name.endswith("/3c273.arf")
    assert indata.get_rmf().name.endswith("/3c273.rmf")
    assert indata.get_background().name.endswith("/3c273_bg.pi")

    # check we can write it out - be explicit with all options
    #
    outfile = tmp_path / "test.pha"
    outfile = str(outfile)  # our IO routines don't recognize paths
    io.write_pha(outfile, indata, ascii=False, clobber=False)

    outdata = io.read_pha(outfile)
    assert isinstance(outdata, DataPHA)
    assert outdata.name.endswith("/test.pha")
    check_header(outdata)
    check_data(outdata, roundtrip=True)

    # The responses and background should NOT be read in
    # (we are in a different directory to infile so we can't
    # find these files).
    #
    assert outdata.response_ids == []
    assert outdata.background_ids == []

    assert outdata.get_arf() is None
    assert outdata.get_rmf() is None
    assert outdata.get_background() is None
예제 #35
0
def test_write_pha_fits_with_extras_roundtrip(tmp_path, caplog):
    """PHA-I with grouping/quality/errors/header

    This covers issue #488 - that is, should the output use the correct
    data type for columns? At present the code does not.

    """

    chans = np.arange(1, 5, dtype=np.int32)
    counts = np.asarray([1, 0, 3, 2], dtype=np.int32)
    grouping = np.asarray([1, -1, 1, 1], dtype=np.int16)
    quality = np.asarray([0, 0, 0, 2], dtype=np.int16)
    etime = 1023.4
    bscal = 0.05
    ascal = np.asarray([1, 1, 0.9, 0.9])

    hdr = {"TELESCOP": "CHANDRA", "INSTRUME": "ACIS", "FILTER": "NONE",
           "CHANTYPE": "PI",
           "DETCHANS": 10,  # This intentionally does not match the data
           "OBJECT": "Made up source",
           "CORRFILE": "None",
           # This will cause a warning when reading in the file
           "ANCRFILE": "made-up-ancrfile.fits",
           # "structural keywords" which match DETCHANS
           "TLMIN1": 1, "TLMAX1": 10}

    pha = DataPHA("testy",
                  chans.astype(np.float64),
                  counts.astype(np.float32),
                  grouping=grouping.astype(np.float32),
                  quality=quality.astype(np.float64),
                  exposure=etime,
                  backscal=bscal,
                  areascal=ascal,
                  header=hdr)

    outfile = tmp_path / "out.pi"
    io.write_pha(str(outfile), pha, ascii=False, clobber=False)
    pha = None

    assert len(caplog.record_tuples) == 0

    with SherpaVerbosity("INFO"):
        inpha = io.read_pha(str(outfile))

    assert len(caplog.record_tuples) == 1
    lname, lvl, msg = caplog.record_tuples[0]
    assert lname == "sherpa.astro.io"
    assert lvl == logging.WARNING

    # message depends on the backend
    if backend_is("crates"):
        assert msg.startswith("File ")
        assert msg.endswith("/made-up-ancrfile.fits does not exist.")
    elif backend_is("pyfits"):
        assert msg.startswith("file '")
        assert msg.endswith("/made-up-ancrfile.fits' not found")

    assert isinstance(inpha, DataPHA)
    assert inpha.channel == pytest.approx(chans)
    assert inpha.counts == pytest.approx(counts)
    assert inpha.grouping == pytest.approx(grouping)
    assert inpha.quality == pytest.approx(quality)
    assert inpha.exposure == pytest.approx(etime)
    assert inpha.backscal == pytest.approx(bscal)
    assert inpha.areascal == pytest.approx(ascal)
    for field in ["staterror", "syserror", "bin_lo", "bin_hi"]:
        assert getattr(inpha, field) is None

    assert inpha.grouped
    assert not inpha.subtracted
    assert inpha.units == "channel"
    assert inpha.rate
    assert inpha.plot_fac == 0
    assert inpha.response_ids == []
    assert inpha.background_ids == []

    if backend_is("crates"):
        check_write_pha_fits_with_extras_roundtrip_crates(outfile, etime, bscal)

    elif backend_is("pyfits"):
        check_write_pha_fits_with_extras_roundtrip_pyfits(outfile, etime, bscal)

    else:
        raise RuntimeError(f"Unknown io backend: {io.backend}")
예제 #36
0
def test_read_pha_errors(make_data_path):
    """Can we read in a ROSAT PHA file."""

    infile = make_data_path(PHAFILE)
    pha = io.read_pha(infile, use_errors=True)
    validate_pha(pha, errors=True)
예제 #37
0
def test_chandra_phaII_roundtrip(make_data_path, tmp_path):
    """Can we read in/write out/read in a PHA-II dataset.

    There is no abiility to write out a PHA-II file,
    only PHA-I.
    """

    def check_header(pha, roundtrip=False):
        hdr = pha.header
        assert hdr["TG_M"] == 2
        assert hdr["TG_PART"] == 1

        check_hduname(hdr, "SPECTRUM")

        assert hdr["HDUCLASS"] == "OGIP"
        assert hdr["HDUCLAS1"] == "SPECTRUM"
        assert hdr["HDUCLAS2"] == "TOTAL"
        assert hdr["HDUCLAS3"] == "COUNT"
        assert hdr["HDUCLAS4"] == "TYPE:II"
        assert hdr["HDUVERS"] == "1.0.0"
        assert hdr["HDUVERS1"] == "1.0.0"
        assert "HDUVERS2" not in hdr

        assert hdr["ORIGIN"] == "ASC"
        assert hdr["CREATOR"] == "tgextract - Version CIAO 4.8"

        assert hdr["OBJECT"] == "3C 120"
        assert hdr["MISSION"] == "AXAF"
        assert hdr["TELESCOP"] == "CHANDRA"
        assert hdr["INSTRUME"] == "ACIS"
        assert hdr["GRATING"] == "HETG"
        assert hdr["DETNAM"] == "ACIS-56789"

        assert hdr["DETCHANS"] == 8192
        assert hdr["CHANTYPE"] == "PI"
        assert "TOTCTS" not in hdr

        assert not hdr["POISSERR"]
        if roundtrip:
            assert hdr["SYS_ERR"] == 0
        else:
            assert not "SYS_ERR" in hdr

        assert hdr["QUALITY"] == 0
        assert hdr["GROUPING"] == 0

        assert hdr["CORRFILE"] == "none"
        assert hdr["CORRSCAL"] == pytest.approx(1.0)

        for key in ["ANCRFILE", "BACKFILE", "RESPFILE"]:
            assert key not in hdr

    def check_data(pha, bkg=False, roundtrip=False):
        assert len(pha.channel) == 8192
        assert len(pha.counts) == 8192
        assert pha.staterror is None
        assert pha.syserror is None
        assert len(pha.channel) == 8192
        assert len(pha.channel) == 8192
        assert pha.grouping is None
        assert pha.quality is None
        assert pha.exposure == pytest.approx(77716.294300039)
        if bkg:
            assert pha.backscal == pytest.approx(4.0188284)
            assert pha.areascal is None
        else:
            assert pha.backscal == pytest.approx(1.0)
            assert pha.areascal == pytest.approx(1.0)

        assert pha.rate
        assert pha.response_ids == []
        expected = [] if bkg or roundtrip else [1, 2]
        assert pha.background_ids == expected

    infile = make_data_path("3c120_pha2.gz")
    phas = io.read_pha(infile)
    assert len(phas) == 12

    # pick the fifth element and a few quick checks
    pha = phas[4]
    assert isinstance(pha, DataPHA)
    assert pha.name.endswith("/3c120_pha2.gz")
    check_header(pha)
    check_data(pha)

    bkg1 = pha.get_background(1)
    bkg2 = pha.get_background(2)
    check_header(bkg1)
    check_header(bkg1)
    check_data(bkg1, bkg=True)
    check_data(bkg2, bkg=True)

    outfile = tmp_path / "test.pha"
    io.write_pha(str(outfile), pha, ascii=False, clobber=False)

    outpha = io.read_pha(str(outfile))
    assert isinstance(outpha, DataPHA)
    assert outpha.name.endswith("/test.pha")
    check_header(outpha, roundtrip=True)
    check_data(outpha, roundtrip=True)
def test_read_pha_errors(make_data_path):
    """Can we read in a ROSAT PHA file."""

    infile = make_data_path(PHAFILE)
    pha = io.read_pha(infile, use_errors=True)
    validate_pha(pha, errors=True)
예제 #39
0
    print("{}".format(name))
    print(repr(eval(name)))
    print("----------------------------------------")


def savefig(name):
    outfile = os.path.join(savedir, name)
    plt.savefig(outfile)
    print("# Created: {}".format(name))


os.chdir('../../../../sherpa-test-data/sherpatest/')

from sherpa.astro.io import read_pha

pha = read_pha('9774.pi')

dump("pha")
dump("pha.get_background()")
dump("pha.get_arf()")
dump("pha.get_rmf()")

dump("pha.header['INSTRUME']")
dump("pha.header['DETNAM']")
dump("pha.channel.size")

pha.set_analysis('energy')
pha.notice(0.3, 7)
tabs = ~pha.mask
pha.group_counts(20, tabStops=tabs)
예제 #40
0
y = arf.exposure * ydet / (rmf.e_max - rmf.e_min)
y = y.repeat(2)
plt.plot(x, y, '-')

plt.yscale('log')
plt.ylim(1e4, 3e6)
plt.xlim(0, 10)
plt.xlabel('Energy (keV)')
plt.ylabel('Count / keV')
savefig('rspmodelnopha_energy.png')


from sherpa.astro.io import read_pha
from sherpa.astro.instrument import RSPModelPHA

pha2 = read_pha('3c273.pi')
arf2 = pha2.get_arf()
rmf2 = pha2.get_rmf()

mdl2 = PowLaw1D('mdl2')
inst2 = RSPModelPHA(arf2, rmf2, pha2, mdl2)
report("inst2")

dump("inst2([]).size")

pha2.set_analysis('energy')
report('pha2.get_filter()')
report('pha2.get_filter_expr()')

pha2.notice(0.5, 7.0)
report('pha2.get_filter()')