Esempio n. 1
0
def model(params, cluster, data):
    #--- Extract parameters
    CR_X_E   = params[0]*1e-2
    CR_eta   = params[1]
    CR_slope = params[2]
    
    #--- Set parameters
    cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', CR_eta), CR_X_E, CR_slope)
    
    #--- Profile
    r_synch, p_synch = cluster.get_synchrotron_profile(data['profile']['radius'], freq0=data['info']['prof_freq'])
    
    #--- Spectrum
    sfreq_bis = np.append(np.array([1]), data['spectrum']['freq'].to_value('MHz'))*u.MHz
    s_synch = cluster.get_synchrotron_spectrum(sfreq_bis, 
                                               Rmin=data['info']['spec_Rmin'], Rmax=data['info']['spec_Rmax'], 
                                               type_integral='cylindrical')[1]
    s_synch = s_synch[1:]
    
    #--- Spectral index
    p_synch1 = cluster.get_synchrotron_profile(data['index']['radius'], freq0=data['info']['idx_freq1'])[1]
    p_synch2 = cluster.get_synchrotron_profile(data['index']['radius'], freq0=data['info']['idx_freq2'])[1]
    upper = np.log10((p_synch1/p_synch2).to_value(''))
    lower = np.log10((data['info']['idx_freq1']/data['info']['idx_freq2']).to_value(''))
    i_synch  = -upper/lower
    
    return p_synch, s_synch, i_synch
def model_hadronic(params, cluster, data):
    '''
    Compute the hadronic model

    Parameters
    ----------
    - params (list of float): model parameters to be tested
    - cluster (minot object): cluster object
    - data (dict): radio data

    Output
    ------
    - p_synch (quantity array): radio profile
    - s_synch (quantity array): radio spectrum
    - i_synch (quantity array): radio spectral index profile

    '''

    #--- Extract parameters
    CR_X_E = params[0] * 1e-2
    CR_eta = params[1]
    CR_slope = params[2]
    Norm = params[3]

    #--- Set parameters
    cluster = perseus_model_library.set_pure_hadronic_model(
        cluster, ('density', CR_eta), CR_X_E, CR_slope)

    #--- Profile
    r_synch, p_synch = cluster.get_synchrotron_profile(
        data['profile']['radius'], freq0=data['info']['prof_freq'])

    #--- Spectrum
    sfreq_bis = np.append(np.array([1]),
                          data['spectrum']['freq'].to_value('MHz')) * u.MHz
    s_synch = cluster.get_synchrotron_spectrum(sfreq_bis,
                                               Rmin=data['info']['spec_Rmin'],
                                               Rmax=data['info']['spec_Rmax'],
                                               type_integral='cylindrical')[1]
    s_synch = s_synch[1:]

    #--- Spectral index
    if fit_index:
        p_synch1 = cluster.get_synchrotron_profile(
            data['index']['radius'], freq0=data['info']['idx_freq1'])[1]
        p_synch2 = cluster.get_synchrotron_profile(
            data['index']['radius'], freq0=data['info']['idx_freq2'])[1]
        upper = np.log10((p_synch1 / p_synch2).to_value(''))
        lower = np.log10((data['info']['idx_freq1'] /
                          data['info']['idx_freq2']).to_value(''))
        i_synch = -upper / lower
    else:
        i_synch = np.nan

    return Norm * p_synch, s_synch, i_synch
    coll2 = ['orange', 'green', 'magenta']
    output_dir = []
    output_dir0 = '/sps/cta/llr/radam/PerseusGammaCalib'
    for im in mag_case:
        output_dir.append(output_dir0 + '_' + model_case + '_' + im + '_' +
                          basedata)

    #========== Define the cluster model
    cluster = []
    for i in range(len(mag_case)):
        if model_case == 'Hadronic':
            cluster0 = perseus_model_library.default_model(
                directory=output_dir[i])
            cluster0 = perseus_model_library.set_magnetic_field_model(
                cluster0, case=mag_case[i])
            cluster0 = perseus_model_library.set_pure_hadronic_model(
                cluster0, ('density', 1.0), 1e-2, 2.5)
            cluster0.Npt_per_decade_integ = 10
        elif model_case == 'Leptonic':
            cluster0 = perseus_model_library.default_model(
                directory=output_dir[i])
            cluster0 = perseus_model_library.set_magnetic_field_model(
                cluster0, case=mag_case[i])
            cluster0 = perseus_model_library.set_pure_leptonic_model(
                cluster0, ('density', 1.0), 1e-5, 2.0)
            if app_steady: cluster0.cre1_loss_model = 'Steady'
            cluster0.Npt_per_decade_integ = 10
        else:
            raise ValueError('Only Hadronic or Leptonic are possible')
        cluster.append(cluster0)

    #========== Data
Esempio n. 4
0
# Main function
#========================================

if __name__ == "__main__":

    #========== Parameters
    Nmc         = 10         # Number of Monte Carlo trials
    fit_index   = False       # Fit the spectral index profile
    mcmc_nsteps = 100        # number of MCMC points
    mcmc_burnin = 10         # number of MCMC burnin points
    mcmc_reset  = False      # Reset the MCMC
    
    #========== Define the cluster model
    cluster = perseus_model_library.default_model()
    cluster = perseus_model_library.set_magnetic_field_model(cluster, case='Taylor2006')
    cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', 2.0), 3e-3, 2.5)
    cluster.Npt_per_decade_integ = 10
    
    #========== Data
    radio_data = perseus_data_library.get_radio_data(cluster.cosmo, cluster.redshift)

    #========== MCMC fit
    #----- Define the MCMC
    par0 = np.array([0.3, 2.0, 2.5])
    
    param_name = [r'$X_{CRp}$(%)', r'$\eta_{CRp}$', r'$\alpha_{CRp}$']
    ndim, nwalkers, nsteps, burnin = len(par0), 10, mcmc_nsteps, mcmc_burnin
    pos = [par0 + par0*1e-1*np.random.randn(ndim) for i in range(nwalkers)]
    
    #----- Define the MCMC
    sampler = emcee.EnsembleSampler(nwalkers, ndim, lnlike, args=[cluster, radio_data], pool=Pool(cpu_count()))
def post_analysis(cluster, radio_data, param_name, par_min, par_max, burnin,
                  conf=68.0, Nmc=100, model_case='Hadronic'):
    '''
    Extract statistics and plots after runing the MCMC

    Parameters
    ----------
    - cluster (minot object): cluster object
    - radio_data (dict): radio data
    - param_name (list): list of the names of the parameters
    - par_min/max (list): list of min and max value for the parameters
    - burnin (int): the burn-in phase of the chain
    - conf (float): the confidence limit interval
    - Nmc (int): the number of Monte Carlo sample to draw

    Output
    ------
    - Plots and statistics
    '''

    #========== Get the chains    
    #----- Restore chains
    with open(cluster.output_dir+'/'+model_case+'_sampler.pkl', 'rb') as f:
        sampler = pickle.load(f)

    #----- Plot acceptance
    # Acceptance
    sample_acc = (np.roll(sampler.lnprobability,1,axis=1) != sampler.lnprobability)
    sample_acc = sample_acc[:,1:]

    acc_mean   = np.sum(sample_acc)/float(len(sample_acc.flatten()))
    acc_sample = np.sum(sample_acc, axis=0)/float(len(sample_acc[:,0]))
    acc_chain  = np.sum(sample_acc, axis=1)/float(len(sample_acc[0,:]))
    
    plt.figure(10)
    plt.plot(sampler.acceptance_fraction, 'k')
    plt.plot(acc_chain, 'r', linestyle='--')
    plt.ylim(0,1)
    plt.xlim(0,len(sampler.acceptance_fraction)-1)
    plt.xlabel('Chain number')
    plt.ylabel('Mean sample acceptance')
    plt.savefig(cluster.output_dir+'/'+model_case+'_chains_acceptance_chain.pdf')
    plt.close()
    
    plt.figure(11)
    plt.plot(acc_sample, 'k')
    plt.ylim(0,1)
    plt.xlim(0,len(acc_sample)-1)
    plt.xlabel('Sample number')
    plt.ylabel('Mean chain acceptance')
    plt.savefig(cluster.output_dir+'/'+model_case+'_chains_acceptance_sample.pdf')
    plt.close()
    print('  --> Acceptence plot done')
    
    #----- Burn in
    param_chains = sampler.chain[:, burnin:, :]
    lnL_chains = sampler.lnprobability[:, burnin:]
    ndim = param_chains.shape[2]
    print('  --> Burn-in done')

    #----- Chain covariance
    chain_list = []
    for i in range(ndim):
        chain_list.append(param_chains[:,:,i].flatten())
    par_cov = np.cov(np.array(chain_list))
    print('---- Param chain covariance^1/2:')
    print(par_cov**0.5)
    print('')
    print('  --> Chain covariance done')
        
    #----- Get the best fit parameters
    wbest = (lnL_chains == np.amax(lnL_chains))
    param_best = []
    for i in range(ndim):
        param_best.append(((param_chains[:,:,i])[wbest])[0])
    print('  --> Best-fit parameters done')

    #----- MC parameters
    param_flat = param_chains.reshape(param_chains.shape[0]*param_chains.shape[1],param_chains.shape[2])
    Nsample = len(param_flat[:,0])-1
    param_MC = np.zeros((Nmc, ndim))
    for i in range(Nmc):
        param_MC[i,:] = param_flat[np.random.randint(0, high=Nsample), :] # randomly taken from chains
    print('  --> MC parameters done')
        
    #========== Statistics results
    #----- Chain statistics
    chainfname = cluster.output_dir+'/'+model_case+'_chainstat.txt'
    par_best, par_percentile = mcmc_common.chains_statistics(param_chains, lnL_chains,
                                                             parname=param_name, conf=conf, show=True,
                                                             outfile=chainfname)
    print('  --> Chain statistics done')
        
    #----- Parameter space
    try:
        mcmc_common.chains_plots(param_chains, param_name, cluster.output_dir+'/'+model_case+'_chains',
                                 par_best=par_best, par_percentile=par_percentile, conf=conf,
                                 par_min=par_min, par_max=par_max)
    except:
        print('Error in chains_plots --> skip it')
    print('  --> Chain plots done')

    #========== Data versus model
    # Best-fit
    if model_case == 'Hadronic':
        prof_best, spec_best, idx_best = model_hadronic(par_best, cluster, radio_data)
    if model_case == 'Leptonic':
        prof_best, spec_best, idx_best = model_leptonic(par_best, cluster, radio_data)
                
    # MC sampling
    prof_mc = []
    spec_mc = []
    idx_mc  = []
    
    for imc in range(Nmc):
        if model_case == 'Hadronic':
            prof_mci, spec_mci, idx_mci = model_hadronic(param_MC[imc,:], cluster, radio_data)
        if model_case == 'Leptonic':
            prof_mci, spec_mci, idx_mci = model_leptonic(param_MC[imc,:], cluster, radio_data)            
        prof_mc.append(prof_mci)
        spec_mc.append(spec_mci)
        idx_mc.append(idx_mci)
        
    # Limits
    prof_u = np.percentile(np.array(prof_mc), 100-(100-conf)/2.0, axis=0)*prof_mc[0].unit
    prof_d = np.percentile(np.array(prof_mc), (100-conf)/2.0, axis=0)*prof_mc[0].unit
    
    spec_u = np.percentile(np.array(spec_mc), 100-(100-conf)/2.0, axis=0)*spec_mc[0].unit
    spec_d = np.percentile(np.array(spec_mc), (100-conf)/2.0, axis=0)*spec_mc[0].unit
    
    idx_u = np.percentile(np.array(idx_mc), 100-(100-conf)/2.0, axis=0)
    idx_d = np.percentile(np.array(idx_mc), (100-conf)/2.0, axis=0)
    
    #----- Spectrum
    fig = plt.figure(0, figsize=(8, 6))
    # MC
    for imc in range(Nmc):
        plt.plot(radio_data['spectrum']['freq'].to_value('MHz'), spec_mc[imc].to_value('Jy'),
                 color='blue', alpha=0.05)
        
    # Limits
    plt.plot(radio_data['spectrum']['freq'].to_value('MHz'), spec_u.to_value('Jy'),
             color='blue', linewidth=2, linestyle='--', label=str(conf)+'% C.L.')
    plt.plot(radio_data['spectrum']['freq'].to_value('MHz'), spec_d.to_value('Jy'),
             color='blue', linewidth=2, linestyle='--')
    plt.fill_between(radio_data['spectrum']['freq'].to_value('MHz'), spec_d.to_value('Jy'),
                     spec_u.to_value('Jy'), color='blue', alpha=0.2)
    
    # Best fit and data
    plt.plot(radio_data['spectrum']['freq'].to_value('MHz'), spec_best.to_value('Jy'),
             color='blue', linewidth=3, label='Best-fit')
    plt.errorbar(radio_data['spectrum']['freq'].to_value('MHz'), radio_data['spectrum']['flux'].to_value('Jy'),
                 radio_data['spectrum']['error'].to_value('Jy'),
                 marker='o', color='k', linestyle='', label='Data')
    
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('frequency (MHz)')
    plt.ylabel('flux (Jy)')
    plt.legend()
    plt.savefig(cluster.output_dir+'/'+model_case+'_Radio_spectrum.pdf')
    plt.close()
    
    #----- Profile
    fig = plt.figure(0, figsize=(8, 6))
    # MC
    for imc in range(Nmc):
        plt.plot(radio_data['profile']['radius'].to_value('kpc'), prof_mc[imc].to_value('Jy arcmin-2'),
                 color='blue', alpha=0.05)
        
    # Limits    
    plt.plot(radio_data['profile']['radius'].to_value('kpc'), prof_u.to_value('Jy arcmin-2'),
             color='blue', linewidth=2, linestyle='--', label=str(conf)+'% C.L.')
    plt.plot(radio_data['profile']['radius'].to_value('kpc'), prof_d.to_value('Jy arcmin-2'),
             color='blue', linewidth=2, linestyle='--')
    plt.fill_between(radio_data['profile']['radius'].to_value('kpc'), prof_d.to_value('Jy arcmin-2'),
                     prof_u.to_value('Jy arcmin-2'), color='blue', alpha=0.2)
    
    # Best and data
    plt.plot(radio_data['profile']['radius'].to_value('kpc'), prof_best.to_value('Jy arcmin-2'),
             color='blue', linewidth=3, label='Best-fit')
    plt.errorbar(radio_data['profile']['radius'].to_value('kpc'),
                 radio_data['profile']['flux'].to_value('Jy arcmin-2'), 
                 yerr=radio_data['profile']['error'].to_value('Jy arcmin-2'),
                 marker='o', linestyle='', color='k', label='Data')
    
    plt.plot([radio_data['info']['prof_Rmin'].to_value('kpc'),radio_data['info']['prof_Rmin'].to_value('kpc')],
             [0,1e6], linestyle='--', color='grey')
    plt.plot([radio_data['info']['prof_Rmax'].to_value('kpc'),radio_data['info']['prof_Rmax'].to_value('kpc')],
             [0,1e6], linestyle='--', color='grey')
    plt.fill_between([0,radio_data['info']['prof_Rmin'].to_value('kpc')], [0,0], [1e6,1e6],
                     color='grey', alpha=0.2, label='Excluded region')
    plt.fill_between([radio_data['info']['prof_Rmax'].to_value('kpc'),
                      radio_data['info']['prof_Rmax'].to_value('kpc')*1e6], [0,0], [1e6,1e6],
                     color='grey', alpha=0.2)
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('radius (kpc)')
    plt.ylabel('surface brightness (Jy/arcmin$^2$)')
    if basedata == 'Gitti2002':
        plt.xlim(10,250)
        plt.ylim(1e-3,1e1)
    if basedata == 'Pedlar1990':
        plt.xlim(13,100)
        plt.ylim(5e-3,5e-1)
    plt.savefig(cluster.output_dir+'/'+model_case+'_Radio_profile.pdf')
    plt.close()
    
    #----- Spectral index
    if fit_index:
        fig = plt.figure(0, figsize=(8, 6))
        # MC
        for imc in range(Nmc):
            plt.plot(radio_data['index']['radius'].to_value('kpc'), idx_mc[imc], color='blue', alpha=0.05)
            
        # Limits
        plt.plot(radio_data['index']['radius'].to_value('kpc'), idx_u, color='blue',
                 linewidth=2, linestyle='--', label=str(conf)+'% C.L.')
        plt.plot(radio_data['index']['radius'].to_value('kpc'), idx_d, color='blue',
                 linewidth=2, linestyle='--')
        plt.fill_between(radio_data['index']['radius'].to_value('kpc'), idx_d, idx_u,
                         color='blue', alpha=0.2)
        
        # Best and data    
        plt.plot(radio_data['index']['radius'].to_value('kpc'), idx_best, color='blue',
                 linewidth=3, label='Best-fit')
        plt.errorbar(radio_data['index']['radius'].to_value('kpc'), radio_data['index']['idx'],
                     yerr=radio_data['index']['error'],
                     marker='o', linestyle='', color='k', label='Data')
        
        plt.plot([radio_data['info']['idx_Rmin'].to_value('kpc'),radio_data['info']['idx_Rmin'].to_value('kpc')],
                 [0,1e6], linestyle='--', color='grey')
        plt.plot([radio_data['info']['idx_Rmax'].to_value('kpc'),radio_data['info']['idx_Rmax'].to_value('kpc')],
                 [0,1e6], linestyle='--', color='grey')
        plt.fill_between([0,radio_data['info']['idx_Rmin'].to_value('kpc')], [0,0], [1e6,1e6], color='grey',
                         alpha=0.1, label='Excluded region')
        plt.fill_between([radio_data['info']['idx_Rmax'].to_value('kpc'), np.inf], [0,0], [1e6,1e6],
                         color='grey', alpha=0.1)
        plt.xscale('log')
        plt.yscale('linear')
        plt.xlabel('radius (kpc)')
        plt.ylabel('spectral index')
        plt.xlim(10,250)
        plt.ylim(0.5,2.5)
        plt.savefig(cluster.output_dir+'/'+model_case+'_Radio_index.pdf')
        plt.close()

    print('  --> Radio plots done')
    
    #========== Implication for gamma rays
    energy = np.logspace(-2,6,100)*u.GeV
    radius = np.logspace(0,4,100)*u.kpc
    
    #---------- Best-fit
    if model_case == 'Hadronic':
        cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', param_best[1]),
                                                                param_best[0]*1e-2, param_best[2])
    if model_case == 'Leptonic':
        cluster = perseus_model_library.set_pure_leptonic_model(cluster, ('density', param_best[1]),
                                                                param_best[0]*1e-5, param_best[2])
        if app_steady: cluster.cre1_loss_model = 'Steady'

    # Hadronic
    E, dN_dEdSdt = cluster.get_gamma_spectrum(energy, 
                                              Rmin=None, Rmax=cluster.R500,
                                              type_integral='cylindrical',
                                              Rmin_los=None, NR500_los=5.0)
    
    r, dN_dSdtdO = cluster.get_gamma_profile(radius, 
                                             Emin=150*u.GeV, Emax=50*u.TeV, 
                                             Energy_density=False, Rmin_los=None, NR500_los=5.0)

    fluxH = cluster.get_gamma_flux(Emin=150*u.GeV, Emax=None, Energy_density=False,
                                   Rmax=cluster.R500, type_integral='cylindrical').to_value('s-1 cm-2')
    
    # Inverse Compton
    E, dNIC_dEdSdt = cluster.get_ic_spectrum(energy, 
                                             Rmin=None, Rmax=cluster.R500,
                                             type_integral='cylindrical',
                                             Rmin_los=None, NR500_los=5.0)
    
    r, dNIC_dSdtdO = cluster.get_ic_profile(radius, 
                                            Emin=150*u.GeV, Emax=50*u.TeV, 
                                            Energy_density=False, Rmin_los=None, NR500_los=5.0)

    fluxIC = cluster.get_ic_flux(Emin=150*u.GeV, Emax=None, Energy_density=False,
                                 Rmax=cluster.R500, type_integral='cylindrical').to_value('s-1 cm-2')

    #---------- Monte Carlo sampling: hadronic
    prof_g_mc = []
    spec_g_mc = []
    flux_g_mc = []
    
    for imc in range(Nmc):
        if model_case == 'Hadronic':
            cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', param_MC[imc,1]), 
                                                                    param_MC[imc,0]*1e-2, param_MC[imc,2])
        if model_case == 'Leptonic':
            cluster = perseus_model_library.set_pure_leptonic_model(cluster, ('density', param_MC[imc,1]),
                                                                    param_MC[imc,0]*1e-5, param_MC[imc,2])
            if app_steady: cluster.cre1_loss_model = 'Steady'

        spec_g_mci = cluster.get_gamma_spectrum(energy, Rmin=None, Rmax=cluster.R500,
                                                type_integral='cylindrical',
                                                Rmin_los=None, NR500_los=5.0)[1]
    
        prof_g_mci = cluster.get_gamma_profile(radius, Emin=150*u.GeV, Emax=50*u.TeV, 
                                               Energy_density=False, Rmin_los=None, NR500_los=5.0)[1]

        flux_g_mci = cluster.get_gamma_flux(Emin=150*u.GeV, Emax=None, Energy_density=False,
                                            Rmax=cluster.R500, type_integral='cylindrical').to_value('s-1 cm-2')
    
        prof_g_mc.append(prof_g_mci)
        spec_g_mc.append(spec_g_mci)
        flux_g_mc.append(flux_g_mci)
    
    #---------- Limits: hadronic
    dN_dEdSdt_u = np.percentile(np.array(spec_g_mc), 100-(100-conf)/2.0, axis=0)*spec_g_mc[0].unit
    dN_dEdSdt_d = np.percentile(np.array(spec_g_mc), (100-conf)/2.0, axis=0)*spec_g_mc[0].unit
    
    dN_dSdtdO_u = np.percentile(np.array(prof_g_mc), 100-(100-conf)/2.0, axis=0)*prof_g_mc[0].unit
    dN_dSdtdO_d = np.percentile(np.array(prof_g_mc), (100-conf)/2.0, axis=0)*prof_g_mc[0].unit

    fluxH_u = np.percentile(np.array(flux_g_mc), 100-(100-conf)/2.0)
    fluxH_d = np.percentile(np.array(flux_g_mc), (100-conf)/2.0)
    
    #---------- Monte Carlo sampling: IC
    prof_ic_mc = []
    spec_ic_mc = []
    flux_ic_mc = []
    
    for imc in range(Nmc):
        if model_case == 'Hadronic':
            cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', param_MC[imc,1]), 
                                                                    param_MC[imc,0]*1e-2, param_MC[imc,2])
        if model_case == 'Leptonic':
            cluster = perseus_model_library.set_pure_leptonic_model(cluster, ('density', param_MC[imc,1]),
                                                                    param_MC[imc,0]*1e-5, param_MC[imc,2])
        if app_steady: cluster.cre1_loss_model = 'Steady'

        spec_ic_mci = cluster.get_ic_spectrum(energy, Rmin=None, Rmax=cluster.R500,
                                              type_integral='cylindrical',
                                              Rmin_los=None, NR500_los=5.0)[1]
    
        prof_ic_mci = cluster.get_ic_profile(radius, Emin=150*u.GeV, Emax=50*u.TeV, 
                                             Energy_density=False, Rmin_los=None, NR500_los=5.0)[1]

        flux_ic_mci = cluster.get_ic_flux(Emin=150*u.GeV, Emax=None, Energy_density=False,
                                          Rmax=cluster.R500, type_integral='cylindrical').to_value('s-1 cm-2')

        prof_ic_mc.append(prof_ic_mci)
        spec_ic_mc.append(spec_ic_mci)
        flux_ic_mc.append(flux_ic_mci)
    
    #---------- Limits: IC
    dNIC_dEdSdt_u = np.percentile(np.array(spec_ic_mc), 100-(100-conf)/2.0, axis=0)*spec_ic_mc[0].unit
    dNIC_dEdSdt_d = np.percentile(np.array(spec_ic_mc), (100-conf)/2.0, axis=0)*spec_ic_mc[0].unit
    
    dNIC_dSdtdO_u = np.percentile(np.array(prof_ic_mc), 100-(100-conf)/2.0, axis=0)*prof_ic_mc[0].unit
    dNIC_dSdtdO_d = np.percentile(np.array(prof_ic_mc), (100-conf)/2.0, axis=0)*prof_ic_mc[0].unit

    fluxIC_u = np.percentile(np.array(flux_ic_mc), 100-(100-conf)/2.0)
    fluxIC_d = np.percentile(np.array(flux_ic_mc), (100-conf)/2.0)
    
    #========== Figure
    #----- Spectrum
    fig = plt.figure(0, figsize=(8, 6))
    # MC
    for imc in range(Nmc):
        if imc == 0:
            plt.plot(E.to_value('GeV'), (E**2*spec_g_mc[imc]).to_value('MeV cm-2 s-1'), color='blue',
                     alpha=0.05, label='Monte Carlo')
        else:
            plt.plot(E.to_value('GeV'), (E**2*spec_g_mc[imc]).to_value('MeV cm-2 s-1'),
                     color='blue', alpha=0.05)
    for imc in range(Nmc):
        plt.plot(E.to_value('GeV'), (E**2*spec_ic_mc[imc]).to_value('MeV cm-2 s-1'),
                 color='magenta', alpha=0.05)
        
    # Limits
    plt.plot(E.to_value('GeV'), (E**2*dN_dEdSdt_u).to_value('MeV cm-2 s-1'), color='blue',
             linewidth=2, linestyle='--', label=str(conf)+'% C.L.')
    plt.plot(E.to_value('GeV'), (E**2*dN_dEdSdt_d).to_value('MeV cm-2 s-1'), color='blue',
             linewidth=2, linestyle='--')
    plt.fill_between(E.to_value('GeV'), (E**2*dN_dEdSdt_u).to_value('MeV cm-2 s-1'),
                     (E**2*dN_dEdSdt_d).to_value('MeV cm-2 s-1'), color='blue', alpha=0.2)
    
    plt.plot(E.to_value('GeV'), (E**2*dNIC_dEdSdt_u).to_value('MeV cm-2 s-1'),
             color='magenta', linewidth=2, linestyle='--')
    plt.plot(E.to_value('GeV'), (E**2*dNIC_dEdSdt_d).to_value('MeV cm-2 s-1'),
             color='magenta', linewidth=2, linestyle='--')
    plt.fill_between(E.to_value('GeV'), (E**2*dNIC_dEdSdt_u).to_value('MeV cm-2 s-1'),
                     (E**2*dNIC_dEdSdt_d).to_value('MeV cm-2 s-1'), color='magenta', alpha=0.2)
    
    # Best fit
    plt.plot(E.to_value('GeV'), (E**2*dN_dEdSdt).to_value('MeV cm-2 s-1'),
             color='blue', linewidth=3, label='Best-fit model (Hadronic)')
    plt.plot(E.to_value('GeV'), (E**2*dNIC_dEdSdt).to_value('MeV cm-2 s-1'),
             color='magenta', linewidth=3, linestyle='-',label='Best-fit model (IC)')
    
    plt.fill_between([30, 100e3], [0,0], [1e6,1e6], color='green', alpha=0.1, label='CTA energy range')
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('Energy (GeV)')
    plt.ylabel(r'$\frac{E^2 dN}{dEdSdt}$ (MeV cm$^{-2}$ s$^{-1}$)')
    plt.xlim(1e-2, 2e5)
    plt.ylim(1e-10, 5e-6)
    plt.legend(fontsize=14)
    plt.savefig(cluster.output_dir+'/'+model_case+'_Gamma_spectrum.pdf')
    plt.close()

    #----- Profile
    fig = plt.figure(0, figsize=(8, 6))
    # MC
    for imc in range(Nmc):
        if imc == 0:
            plt.plot(r.to_value('kpc'), (prof_g_mc[imc]).to_value('cm-2 s-1 deg-2'),
                     color='blue', alpha=0.05, label='Monte Carlo')
        else:
            plt.plot(r.to_value('kpc'), (prof_g_mc[imc]).to_value('cm-2 s-1 deg-2'),
                     color='blue', alpha=0.05)
    for imc in range(Nmc):
        plt.plot(r.to_value('kpc'), (prof_ic_mc[imc]).to_value('cm-2 s-1 deg-2'),
                 color='magenta', alpha=0.05)

    # Limits
    plt.plot(r.to_value('kpc'), (dN_dSdtdO_u).to_value('cm-2 s-1 deg-2'),
             color='blue', linewidth=2, linestyle='--', label=str(conf)+'% C.L.')
    plt.plot(r.to_value('kpc'), (dN_dSdtdO_d).to_value('cm-2 s-1 deg-2'),
             color='blue', linewidth=2, linestyle='--')
    plt.fill_between(r.to_value('kpc'), (dN_dSdtdO_u).to_value('cm-2 s-1 deg-2'),
                     (dN_dSdtdO_d).to_value('cm-2 s-1 deg-2'), color='blue', alpha=0.2)
    
    plt.plot(r.to_value('kpc'), (dNIC_dSdtdO_u).to_value('cm-2 s-1 deg-2'),
             color='magenta', linewidth=2, linestyle='--')
    plt.plot(r.to_value('kpc'), (dNIC_dSdtdO_d).to_value('cm-2 s-1 deg-2'),
             color='magenta', linewidth=2, linestyle='--')
    plt.fill_between(r.to_value('kpc'), (dNIC_dSdtdO_u).to_value('cm-2 s-1 deg-2'),
                     (dNIC_dSdtdO_d).to_value('cm-2 s-1 deg-2'), color='magenta', alpha=0.2)

    # Best-fit
    plt.plot(r.to_value('kpc'), (dN_dSdtdO).to_value('cm-2 s-1 deg-2'),
             color='blue', linewidth=3, label='Best-fit model (Hadronic)')
    plt.plot(r.to_value('kpc'), (dNIC_dSdtdO).to_value('cm-2 s-1 deg-2'),
             color='magenta', linewidth=3, linestyle='-', label='Best-fit model (IC)')
    
    plt.vlines((0.05*u.deg*cluster.cosmo.kpc_proper_per_arcmin(cluster.redshift)).to_value('kpc'),
               0,1, linestyle=':', color='k', label='CTA PSF (1 TeV)')
    plt.vlines(cluster.R500.to_value('kpc'), 0,1, linestyle='--', color='k', label='$R_{500}$')
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('Radius (kpc)')
    plt.ylabel(r'$\frac{dN}{dSdtd\Omega}$ (cm$^{-2}$ s$^{-1}$ deg$^{-2}$)')
    plt.xlim(10,5e3)
    plt.ylim(1e-16,1e-9)
    plt.legend(fontsize=14)
    plt.savefig(cluster.output_dir+'/'+model_case+'_Gamma_profile.pdf')
    plt.close()

    #----- Flux
    file = open(cluster.output_dir+'/'+model_case+'_Gamma_flux.txt','w')
    file.write('Energy E_gamma > 150 GeV \n')
    file.write('Hadronic        - Best  '+str(fluxH)+' cm-2 s-1 \n')
    file.write('                  Upper '+str(fluxH_u)+' cm-2 s-1 \n')
    file.write('                  Lower '+str(fluxH_d)+' cm-2 s-1 \n')
    file.write('Inverse Compton - Best  '+str(fluxIC)+' cm-2 s-1 \n')
    file.write('                  Upper '+str(fluxIC_u)+' cm-2 s-1 \n')
    file.write('                  Lower '+str(fluxIC_d)+' cm-2 s-1 \n')
    file.close()

    plotting.seaborn_1d(np.array(flux_g_mc)*1e12,
                        output_fig=cluster.output_dir+'/'+model_case+'_Gamma_flux_H.pdf',
                        ci=0.68, truth=None, best=fluxH*1e12,
                        label='$F_{\gamma,\ hadronic}$ ($10^{-12}$ s$^{-1}$ cm$^{-2}$)',
                        gridsize=100, alpha=(0.2, 0.4), 
                        figsize=(10,10), fontsize=12,
                        cols=[('blue','grey', 'orange')])
    plt.close("all")

    plotting.seaborn_1d(np.array(flux_ic_mc)*1e12,
                        output_fig=cluster.output_dir+'/'+model_case+'_Gamma_flux_IC.pdf',
                        ci=0.68, truth=None, best=fluxIC*1e12,
                        label='$F_{\gamma,\ IC}$ ($10^{-12}$ s$^{-1}$ cm$^{-2}$)',
                        gridsize=100, alpha=(0.2, 0.4), 
                        figsize=(10,10), fontsize=12,
                        cols=[('blue','grey', 'orange')])
    plt.close("all")
    print('  --> Gamma plots done')
    print('   Number of steps:              ', mcmc_nsteps)
    print('   Fitting for spectral index?:  ', fit_index)
    print('   Applying SS loss (leptonic)?: ', app_steady)
    print('----------------------------------------')
    print('')

    #========== Make directory
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)
    print('-----> Working in '+output_dir)
    
    #========== Define the cluster model
    if model_case == 'Hadronic':
        cluster = perseus_model_library.default_model(directory=output_dir)
        cluster = perseus_model_library.set_magnetic_field_model(cluster, case=mag_case)
        cluster = perseus_model_library.set_pure_hadronic_model(cluster, ('density', 1.0), 1e-2, 2.5)
        cluster.Npt_per_decade_integ = 10
    elif model_case == 'Leptonic':
        cluster = perseus_model_library.default_model(directory=output_dir)
        cluster = perseus_model_library.set_magnetic_field_model(cluster, case=mag_case)
        cluster = perseus_model_library.set_pure_leptonic_model(cluster, ('density', 1.0), 1e-5, 2.0)
        if app_steady: cluster.cre1_loss_model = 'Steady'
        cluster.Npt_per_decade_integ = 30
    else:
        raise ValueError('Only Hadronic or Leptonic are possible')
    
    #========== Data
    print('')
    print('-----> Getting the radio data')
    radio_data = perseus_data_library.get_radio_data(cluster.cosmo, cluster.redshift, prof_file=basedata)