Example #1
0
def test_spectrum_like_with_background_model():
    energies = np.logspace(1, 3, 51)

    low_edge = energies[:-1]
    high_edge = energies[1:]

    sim_K = 1E-1
    sim_kT = 20.

    # get a blackbody source function
    source_function = Blackbody(K=sim_K, kT=sim_kT)

    # power law background function
    background_function = Powerlaw(K=5, index=-1.5, piv=100.)

    spectrum_generator = SpectrumLike.from_function(
        'fake',
        source_function=source_function,
        background_function=background_function,
        energy_min=low_edge,
        energy_max=high_edge)

    background_plugin = SpectrumLike.from_background('background',
                                                     spectrum_generator)

    bb = Blackbody()

    pl = Powerlaw()
    pl.piv = 100

    bkg_ps = PointSource('bkg', 0, 0, spectral_shape=pl)

    bkg_model = Model(bkg_ps)

    jl_bkg = JointLikelihood(bkg_model, DataList(background_plugin))

    _ = jl_bkg.fit()

    plugin_bkg_model = SpectrumLike('full',
                                    spectrum_generator.observed_spectrum,
                                    background=background_plugin)

    pts = PointSource('mysource', 0, 0, spectral_shape=bb)

    model = Model(pts)

    # MLE fitting

    jl = JointLikelihood(model, DataList(plugin_bkg_model))

    result = jl.fit()

    K_variates = jl.results.get_variates('mysource.spectrum.main.Blackbody.K')

    kT_variates = jl.results.get_variates(
        'mysource.spectrum.main.Blackbody.kT')

    assert np.all(
        np.isclose([K_variates.average, kT_variates.average], [sim_K, sim_kT],
                   rtol=0.5))
Example #2
0
def test_spectrum_like_with_background_model():
    energies = np.logspace(1, 3, 51)

    low_edge = energies[:-1]
    high_edge = energies[1:]

    sim_K = 1E-1
    sim_kT = 20.

    # get a blackbody source function
    source_function = Blackbody(K=sim_K, kT=sim_kT)

    # power law background function
    background_function = Powerlaw(K=5, index=-1.5, piv=100.)

    spectrum_generator = SpectrumLike.from_function('fake',
                                                    source_function=source_function,
                                                    background_function=background_function,
                                                    energy_min=low_edge,
                                                    energy_max=high_edge)


    background_plugin = SpectrumLike.from_background('background',spectrum_generator)


    bb = Blackbody()


    pl = Powerlaw()
    pl.piv = 100

    bkg_ps = PointSource('bkg',0,0,spectral_shape=pl)

    bkg_model = Model(bkg_ps)

    jl_bkg = JointLikelihood(bkg_model,DataList(background_plugin))

    _ = jl_bkg.fit()




    plugin_bkg_model = SpectrumLike('full',spectrum_generator.observed_spectrum,background=background_plugin)

    pts = PointSource('mysource', 0, 0, spectral_shape=bb)

    model = Model(pts)

    # MLE fitting

    jl = JointLikelihood(model, DataList(plugin_bkg_model))

    result = jl.fit()

    K_variates = jl.results.get_variates('mysource.spectrum.main.Blackbody.K')

    kT_variates = jl.results.get_variates('mysource.spectrum.main.Blackbody.kT')

    assert np.all(np.isclose([K_variates.mean(), kT_variates.mean()], [sim_K, sim_kT], rtol=0.5))
Example #3
0
def test_one_free_parameter_input_output():

    fluxUnit = 1. / (u.TeV * u.cm**2 * u.s)

    temp_file = "__test_mle.fits"
    
    spectrum=Powerlaw()
    source = PointSource( "tst", ra=100 , dec=20, spectral_shape=spectrum)
    model = Model(source)

    spectrum.piv = 7*u.TeV      
    spectrum.index = -2.3
    spectrum.K = 1e-15*fluxUnit  

    spectrum.piv.fix = True

    #two free parameters (one with units)
    spectrum.index.fix = False
    spectrum.K.fix = False
    cov_matrix = np.diag([0.001]*2)
    ar = MLEResults(model, cov_matrix, {})  
    
    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)
   
    #one free parameter with units
    spectrum.index.fix = True
    spectrum.K.fix = False
    cov_matrix = np.diag([0.001]*1)
    ar = MLEResults(model, cov_matrix, {})  
    
    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)
  
   
    #one free parameter without units
    spectrum.index.fix = False
    spectrum.K.fix = True
    cov_matrix = np.diag([0.001]*1)
    ar = MLEResults(model, cov_matrix, {})  
    
    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)
Example #4
0
def test_one_free_parameter_input_output():

    fluxUnit = 1. / (u.TeV * u.cm**2 * u.s)

    temp_file = "__test_mle.fits"

    spectrum = Powerlaw()
    source = PointSource("tst", ra=100, dec=20, spectral_shape=spectrum)
    model = Model(source)

    spectrum.piv = 7 * u.TeV
    spectrum.index = -2.3
    spectrum.K = 1e-15 * fluxUnit

    spectrum.piv.fix = True

    #two free parameters (one with units)
    spectrum.index.fix = False
    spectrum.K.fix = False
    cov_matrix = np.diag([0.001] * 2)
    ar = MLEResults(model, cov_matrix, {})

    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)

    #one free parameter with units
    spectrum.index.fix = True
    spectrum.K.fix = False
    cov_matrix = np.diag([0.001] * 1)
    ar = MLEResults(model, cov_matrix, {})

    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)

    #one free parameter without units
    spectrum.index.fix = False
    spectrum.K.fix = True
    cov_matrix = np.diag([0.001] * 1)
    ar = MLEResults(model, cov_matrix, {})

    ar.write_to(temp_file, overwrite=True)
    ar_reloaded = load_analysis_results(temp_file)
    os.remove(temp_file)
    _results_are_same(ar, ar_reloaded)
def test_spectrum_like_with_background_model():
    energies = np.logspace(1, 3, 51)

    low_edge = energies[:-1]
    high_edge = energies[1:]

    sim_K = 1e-1
    sim_kT = 20.0

    # get a blackbody source function
    source_function = Blackbody(K=sim_K, kT=sim_kT)

    # power law background function
    background_function = Powerlaw(K=5, index=-1.5, piv=100.0)

    spectrum_generator = SpectrumLike.from_function(
        "fake",
        source_function=source_function,
        background_function=background_function,
        energy_min=low_edge,
        energy_max=high_edge,
    )

    background_plugin = SpectrumLike.from_background("background",
                                                     spectrum_generator)

    bb = Blackbody()

    pl = Powerlaw()
    pl.piv = 100

    bkg_ps = PointSource("bkg", 0, 0, spectral_shape=pl)

    bkg_model = Model(bkg_ps)

    jl_bkg = JointLikelihood(bkg_model, DataList(background_plugin))

    _ = jl_bkg.fit()

    plugin_bkg_model = SpectrumLike("full",
                                    spectrum_generator.observed_spectrum,
                                    background=background_plugin)

    pts = PointSource("mysource", 0, 0, spectral_shape=bb)

    model = Model(pts)

    # MLE fitting

    jl = JointLikelihood(model, DataList(plugin_bkg_model))

    result = jl.fit()

    K_variates = jl.results.get_variates("mysource.spectrum.main.Blackbody.K")

    kT_variates = jl.results.get_variates(
        "mysource.spectrum.main.Blackbody.kT")

    assert np.all(
        np.isclose([K_variates.average, kT_variates.average], [sim_K, sim_kT],
                   rtol=0.5))

    ## test with ogiplike
    with within_directory(__example_dir):
        ogip = OGIPLike("test_ogip",
                        observation="test.pha{1}",
                        background=background_plugin)
Example #6
0
def test_OGIP_response_against_xspec():

    # Test for various photon indexes
    for index in [-0.5, 0.0, 0.5, 1.5, 2.0, 3.0, 4.0]:

        print("Processing index %s" % index)

        # First reset xspec
        xspec.AllData.clear()

        # Create a model in XSpec

        mo = xspec.Model("po")

        # Change the default value for the photon index
        # (remember that in XSpec the definition of the powerlaw is norm * E^(-PhoIndex),
        # so PhoIndex is positive normally. This is the opposite of astromodels.
        mo.powerlaw.PhoIndex = index
        mo.powerlaw.norm = 12.2

        # Now repeat the same in 3ML

        # Generate the astromodels function and set it to the same values as the XSpec power law
        # (the pivot in XSpec is set to 1). Remember also that the definition in xspec has the
        # sign of the photon index opposite
        powerlaw = Powerlaw()
        powerlaw.piv = 1.0
        powerlaw.index = -mo.powerlaw.PhoIndex.values[0]
        powerlaw.K = mo.powerlaw.norm.values[0]

        # Exploit the fact that the power law integral is analytic
        powerlaw_integral = Powerlaw()
        # Remove transformation
        powerlaw_integral.K._transformation = None
        powerlaw_integral.K.bounds = (None, None)
        powerlaw_integral.index = powerlaw.index.value + 1
        powerlaw_integral.K = old_div(powerlaw.K.value, (powerlaw.index.value + 1))

        powerlaw_integral.display()

        integral_function = lambda e1, e2: powerlaw_integral(e2) - powerlaw_integral(e1)

        # Now check that the two convoluted model give the same number of counts in each channel

        # Fake a spectrum so we can actually compute the convoluted model

        # Get path of response file
        rsp_file = str(get_path_of_data_file("ogip_test_gbm_n6.rsp"))

        fs1 = xspec.FakeitSettings(
            rsp_file, exposure=1.0, fileName="_fake_spectrum.pha"
        )

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML
        rsp = OGIPResponse(rsp_file)

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)

        # Now do the same with a matrix with a ARF

        # First reset xspec
        xspec.AllData.clear()

        # Then load rsp and arf in XSpec

        rsp_file = str(get_path_of_data_file("ogip_test_xmm_pn.rmf"))

        arf_file = str(get_path_of_data_file("ogip_test_xmm_pn.arf"))

        fs1 = xspec.FakeitSettings(
            rsp_file, arf_file, exposure=1.0, fileName="_fake_spectrum.pha"
        )

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML
        rsp = OGIPResponse(rsp_file, arf_file=arf_file)

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)
Example #7
0
def test_response_against_xspec():

    # Make a response and write to a FITS OGIP file
    matrix, mc_energies, ebounds = get_matrix_elements()

    rsp = InstrumentResponse(matrix, ebounds, mc_energies)

    temp_file = "__test.rsp"

    rsp.to_fits(temp_file, "TEST", "TEST", overwrite=True)

    # Test for various photon indexes

    for index in np.linspace(-2.0, 2.0, 10):

        if index == 1.0:

            # This would make the integral of the power law different, so let's just
            # skip it

            continue

        # First reset xspec
        xspec.AllData.clear()

        # Create a model in XSpec

        mo = xspec.Model("po")

        # Change the default value for the photon index
        # (remember that in XSpec the definition of the powerlaw is norm * E^(-PhoIndex),
        # so PhoIndex is positive normally. This is the opposite of astromodels.
        mo.powerlaw.PhoIndex = index
        mo.powerlaw.norm = 12.2

        # Now repeat the same in 3ML

        # Generate the astromodels function and set it to the same values as the XSpec power law
        # (the pivot in XSpec is set to 1). Remember also that the definition in xspec has the
        # sign of the photon index opposite
        powerlaw = Powerlaw()
        powerlaw.piv = 1.0
        powerlaw.index = -mo.powerlaw.PhoIndex.values[0]
        powerlaw.K = mo.powerlaw.norm.values[0]

        # Exploit the fact that the power law integral is analytic
        powerlaw_integral = Powerlaw()
        powerlaw_integral.K._transformation = None
        powerlaw_integral.K.bounds = (None, None)
        powerlaw_integral.index = powerlaw.index.value + 1
        powerlaw_integral.K = old_div(powerlaw.K.value, (powerlaw.index.value + 1))

        integral_function = lambda e1, e2: powerlaw_integral(e2) - powerlaw_integral(e1)

        # Now check that the two convoluted model give the same number of counts in each channel

        # Fake a spectrum so we can actually compute the convoluted model

        # Get path of response file

        fs1 = xspec.FakeitSettings(
            temp_file, exposure=1.0, fileName="_fake_spectrum.pha"
        )

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)

    os.remove(temp_file)
Example #8
0
def test_OGIP_response_against_xspec():

    # Test for various photon indexes
    for index in [-0.5, 0.0, 0.5, 1.5, 2.0, 3.0, 4.0]:

        print("Processing index %s" % index)

        # First reset xspec
        xspec.AllData.clear()

        # Create a model in XSpec

        mo = xspec.Model("po")

        # Change the default value for the photon index
        # (remember that in XSpec the definition of the powerlaw is norm * E^(-PhoIndex),
        # so PhoIndex is positive normally. This is the opposite of astromodels.
        mo.powerlaw.PhoIndex = index
        mo.powerlaw.norm = 12.2

        # Now repeat the same in 3ML

        # Generate the astromodels function and set it to the same values as the XSpec power law
        # (the pivot in XSpec is set to 1). Remember also that the definition in xspec has the
        # sign of the photon index opposite
        powerlaw = Powerlaw()
        powerlaw.piv = 1.0
        powerlaw.index = -mo.powerlaw.PhoIndex.values[0]
        powerlaw.K = mo.powerlaw.norm.values[0]

        # Exploit the fact that the power law integral is analytic
        powerlaw_integral = Powerlaw()
        # Remove transformation
        powerlaw_integral.K._transformation = None
        powerlaw_integral.K.bounds = (None, None)
        powerlaw_integral.index = powerlaw.index.value + 1
        powerlaw_integral.K = powerlaw.K.value / (powerlaw.index.value + 1)

        powerlaw_integral.display()

        integral_function = lambda e1, e2: powerlaw_integral(e2) - powerlaw_integral(e1)

        # Now check that the two convoluted model give the same number of counts in each channel

        # Fake a spectrum so we can actually compute the convoluted model

        # Get path of response file
        rsp_file = get_path_of_data_file("ogip_test_gbm_n6.rsp")

        fs1 = xspec.FakeitSettings(rsp_file, exposure=1.0, fileName="_fake_spectrum.pha")

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML
        rsp = OGIPResponse(rsp_file)

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)

        # Now do the same with a matrix with a ARF

        # First reset xspec
        xspec.AllData.clear()

        # Then load rsp and arf in XSpec

        rsp_file = get_path_of_data_file("ogip_test_xmm_pn.rmf")

        arf_file = get_path_of_data_file("ogip_test_xmm_pn.arf")

        fs1 = xspec.FakeitSettings(rsp_file, arf_file, exposure=1.0, fileName="_fake_spectrum.pha")

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML
        rsp = OGIPResponse(rsp_file, arf_file=arf_file)

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)
Example #9
0
def test_response_against_xspec():

    # Make a response and write to a FITS OGIP file
    matrix, mc_energies, ebounds = get_matrix_elements()

    rsp = InstrumentResponse(matrix, ebounds, mc_energies)

    temp_file = "__test.rsp"

    rsp.to_fits(temp_file, "TEST", "TEST", overwrite=True)

    # Test for various photon indexes

    for index in np.linspace(-2.0, 2.0, 10):

        if index == 1.0:

            # This would make the integral of the power law different, so let's just
            # skip it

            continue

        # First reset xspec
        xspec.AllData.clear()

        # Create a model in XSpec

        mo = xspec.Model("po")

        # Change the default value for the photon index
        # (remember that in XSpec the definition of the powerlaw is norm * E^(-PhoIndex),
        # so PhoIndex is positive normally. This is the opposite of astromodels.
        mo.powerlaw.PhoIndex = index
        mo.powerlaw.norm = 12.2

        # Now repeat the same in 3ML

        # Generate the astromodels function and set it to the same values as the XSpec power law
        # (the pivot in XSpec is set to 1). Remember also that the definition in xspec has the
        # sign of the photon index opposite
        powerlaw = Powerlaw()
        powerlaw.piv = 1.0
        powerlaw.index = -mo.powerlaw.PhoIndex.values[0]
        powerlaw.K = mo.powerlaw.norm.values[0]

        # Exploit the fact that the power law integral is analytic
        powerlaw_integral = Powerlaw()
        powerlaw_integral.K._transformation = None
        powerlaw_integral.K.bounds = (None, None)
        powerlaw_integral.index = powerlaw.index.value + 1
        powerlaw_integral.K = powerlaw.K.value / (powerlaw.index.value + 1)

        integral_function = lambda e1, e2: powerlaw_integral(e2) - powerlaw_integral(e1)

        # Now check that the two convoluted model give the same number of counts in each channel

        # Fake a spectrum so we can actually compute the convoluted model

        # Get path of response file

        fs1 = xspec.FakeitSettings(temp_file, exposure=1.0, fileName="_fake_spectrum.pha")

        xspec.AllData.fakeit(noWrite=True, applyStats=False, settings=fs1)

        # Get the expected counts
        xspec_counts = mo.folded(1)

        # Now get the convolution from 3ML

        rsp.set_function(integral_function)

        threeML_counts = rsp.convolve()

        # Compare them
        assert np.allclose(xspec_counts, threeML_counts)

    os.remove(temp_file)
Example #10
0
def test_healpixRoi(geminga_maptree, geminga_response):

    #test to make sure writing a model with HealpixMapROI works fine
    ra, dec = 101.7, 16.
    data_radius = 9.
    model_radius = 24.

    m = np.zeros(hp.nside2npix(NSIDE))
    vec = Sky2Vec(ra, dec)
    m[hp.query_disc(NSIDE,
                    vec, (data_radius * u.degree).to(u.radian).value,
                    inclusive=False)] = 1

    #hp.fitsfunc.write_map("roitemp.fits" , m, nest=False, coord="C", partial=False, overwrite=True )

    map_roi = HealpixMapROI(data_radius=data_radius,
                            ra=ra,
                            dec=dec,
                            model_radius=model_radius,
                            roimap=m)
    #fits_roi = HealpixMapROI(data_radius=data_radius, ra=ra, dec=dec, model_radius=model_radius, roifile="roitemp.fits")
    hawc = HAL("HAWC", geminga_maptree, geminga_response, map_roi)
    hawc.set_active_measurements(1, 9)
    '''
  Define model: Two sources, 1 point, 1 extended

  Same declination, but offset in RA

  Different spectral idnex, but both power laws
  '''
    pt_shift = 3.0
    ext_shift = 2.0

    # First soource
    spectrum1 = Powerlaw()
    source1 = PointSource("point",
                          ra=ra + pt_shift,
                          dec=dec,
                          spectral_shape=spectrum1)

    spectrum1.K = 1e-12 / (u.TeV * u.cm**2 * u.s)
    spectrum1.piv = 1 * u.TeV
    spectrum1.index = -2.3

    spectrum1.piv.fix = True
    spectrum1.K.fix = True
    spectrum1.index.fix = True

    # Second source
    shape = Gaussian_on_sphere(lon0=ra - ext_shift, lat0=dec, sigma=0.3)
    spectrum2 = Powerlaw()
    source2 = ExtendedSource("extended",
                             spatial_shape=shape,
                             spectral_shape=spectrum2)

    spectrum2.K = 1e-12 / (u.TeV * u.cm**2 * u.s)
    spectrum2.piv = 1 * u.TeV
    spectrum2.index = -2.0

    spectrum2.piv.fix = True
    spectrum2.K.fix = True
    spectrum2.index.fix = True

    shape.lon0.fix = True
    shape.lat0.fix = True
    shape.sigma.fix = True

    model = Model(source1, source2)

    hawc.set_model(model)

    # Write the model map
    model_map_tree = hawc.write_model_map("test.hd5", test_return_map=True)

    # Read the model back
    hawc_model = map_tree_factory('test.hd5', map_roi)

    # Check written model and read model are the same
    check_map_trees(hawc_model, model_map_tree)

    os.remove("test.hd5")
Example #11
0
def test_model_residual_maps(geminga_maptree, geminga_response, geminga_roi):

    #data_radius = 5.0
    #model_radius = 7.0
    output = dirname(geminga_maptree)

    ra_src, dec_src = 101.7, 16.0
    maptree, response, roi = geminga_maptree, geminga_response, geminga_roi

    hawc = HAL("HAWC", maptree, response, roi)

    # Use from bin 1 to bin 9
    hawc.set_active_measurements(1, 9)

    # Display information about the data loaded and the ROI
    hawc.display()
    '''
    Define model: Two sources, 1 point, 1 extended

    Same declination, but offset in RA

    Different spectral index, but both power laws

    '''
    pt_shift = 3.0
    ext_shift = 2.0

    # First source
    spectrum1 = Powerlaw()
    source1 = PointSource("point",
                          ra=ra_src + pt_shift,
                          dec=dec_src,
                          spectral_shape=spectrum1)

    spectrum1.K = 1e-12 / (u.TeV * u.cm**2 * u.s)
    spectrum1.piv = 1 * u.TeV
    spectrum1.index = -2.3

    spectrum1.piv.fix = True
    spectrum1.K.fix = True
    spectrum1.index.fix = True

    # Second source
    shape = Gaussian_on_sphere(lon0=ra_src - ext_shift,
                               lat0=dec_src,
                               sigma=0.3)
    spectrum2 = Powerlaw()
    source2 = ExtendedSource("extended",
                             spatial_shape=shape,
                             spectral_shape=spectrum2)

    spectrum2.K = 1e-12 / (u.TeV * u.cm**2 * u.s)
    spectrum2.piv = 1 * u.TeV
    spectrum2.index = -2.0

    shape.lon0.fix = True
    shape.lat0.fix = True
    shape.sigma.fix = True

    spectrum2.piv.fix = True
    spectrum2.K.fix = True
    spectrum2.index.fix = True

    # Define model with both sources
    model = Model(source1, source2)

    # Define the data we are using
    data = DataList(hawc)

    # Define the JointLikelihood object (glue the data to the model)
    jl = JointLikelihood(model, data, verbose=False)

    # This has the effect of loading the model cache
    fig = hawc.display_spectrum()

    # the test file names
    model_file_name = "{0}/test_model.hdf5".format(output)
    residual_file_name = "{0}/test_residual.hdf5".format(output)

    # Write the map trees for testing
    model_map_tree = hawc.write_model_map(model_file_name,
                                          poisson_fluctuate=True,
                                          test_return_map=True)
    residual_map_tree = hawc.write_residual_map(residual_file_name,
                                                test_return_map=True)

    # Read the maps back in
    hawc_model = map_tree_factory(model_file_name, roi)
    hawc_residual = map_tree_factory(residual_file_name, roi)

    check_map_trees(hawc_model, model_map_tree)
    check_map_trees(hawc_residual, residual_map_tree)