def run_MCMC_ex(which_par,niter,save_title, renorm_var,firstiter=0,seed="none",guess="random"):
    """
    Functions that runs the MCMC for a given set of parameters

    Keyword Arguments:
    which_par -- a list of indices, corresponding to the order defined above, exemple [0,2] means ombh2,tau if order is [ombh2,omch2,tau,As,ns,H0]
    niter -- number of iterations in MCMC
    renorm_var -- factor multipling the variance, to play around for better acceptance rate.
    """
    cov_new_temp = cov_new[which_par,:][:,which_par] * renorm_var
    string_temp = strings[which_par]
    titles_temp = titles[which_par]
    x_mean_temp = x_mean[which_par]
    priors_central_temp = priors_central[which_par]
    priors_invvar_temp = priors_invvar[which_par]
    print titles_temp
    sys.stdout.flush()
    dd2 = cb.update_dic(dd,x_mean_temp,string_temp)
    cl = cb.generate_spectrum(dd2)[:lmax+1,1]
    cl[:2] = 1.e-35
    if guess=="random":
        guess_param = PS2P.prop_dist_form_params(x_mean_temp,cov_new_temp)
    else :
        guess_param = guess
    tt1 = time.time()
    save_string = "outputs/chain_ex_%s_%s_%d_%d"%(save_title,str(which_par).replace(',','').replace('[','').replace(']','').replace(' ',''),np.random.randint(0,100000),niter)
    print save_string
    sys.stdout.flush()
    testss = np.array(MH.MCMC_log(guess_param, JJi.functional_form_params_n,PS2P.prop_dist_form_params, PS2P.prop_func_form_params,niter,PS2P.Gaussian_priors_func,firstiter,seed,save_string,[dlm,string_temp,dd,nl,bl,cl],[x_mean_temp*0,np.matrix(cov_new_temp)],[priors_central_temp,priors_invvar_temp]))
    print time.time() - tt1
    np.save(save_string+".npy",testss)
    return testss
def run_MCMC(which_par,niter,save_title, renorm_var):
    """
    Functions that runs the MCMC for a given set of parameters

    Keyword Arguments:
    which_par -- a list of indices, corresponding to the order defined above, exemple [0,2] means ombh2,tau if order is [ombh2,omch2,tau,As,ns,H0]
    niter -- number of iterations in MCMC
    renorm_var -- factor multipling the variance, to play around for better acceptance rate.
    """
    cov_new_temp = cov_new[which_par,:][:,which_par] * renorm_var
    string_temp = strings[which_par]
    titles_temp = titles[which_par]
    x_mean_temp = x_mean[which_par]
    priors_central_temp = priors_central[which_par]
    priors_invvar_temp = priors_invvar[which_par]
    print titles_temp
    # generate first guess parameters
    guess_param = PS2P.prop_dist_form_params(x_mean_temp,cov_new_temp)
    # generate first fluctuation map
    dd2 = cb.update_dic(dd,guess_param,string_temp)
    cl = cb.generate_spectrum(dd2)[:,1]
    cl[:2] = 1.e-35
    renorm = CG.renorm_term(cl,bl,nl)
    fluc = hp.almxfl(CG.generate_w1term(cl[:lmax+1],bl[:lmax+1],nl[:lmax+1]) + CG.generate_w0term(cl[:lmax+1]),renorm)
    # the core of the MCMC
    testss = np.array(MH.MCMC_log_Jeff_test(guess_param, JJi.target_distrib_newrescale,PS2P.prop_dist_form_params, PS2P.prop_func_form_params,niter,PS2P.Gaussian_priors_func,[[dlm,string_temp,dd,nl[:lmax+1],bl[:lmax+1]],[cl[:lmax+1],fluc]],[x_mean_temp*0,np.matrix(cov_new_temp)],[priors_central_temp,priors_invvar_temp]))
    np.save("chain_%s_%s_%d_%d.npy"%(save_title,str(which_par).replace(',','').replace('[','').replace(']','').replace(' ',''),np.random.randint(0,100000),niter),testss)
    return testss
def Step_MC(guess, *arg):
    """
    Keyword Arguments:
    x -- the vector of params

    *args are:
    arg[0] -- a target class object
    arg[1] -- Cl_old, fluc_lm_old
    """
    ##print guess, arg
    dlm,strings,params,nl,bl = arg[0]
    Cl_old, fluc_lm_GS,mf_old = arg[1]
    dd = cb.update_dic(params,guess,strings)
    #generate new spectrum from new params
    lmax = len(Cl_old)
    Cl_new = cb.generate_spectrum(dd)[:lmax,1]
    # avoid dividing by 0
    Cl_new[:2] = 1.e-35
    #print "new = ",Cl_new[50]
    #print "old = ",Cl_old[50]
    # renormalization, i.e. lhs part of eq (24) and (25)
    renorm = CG.renorm_term(Cl_new,bl,nl)
    # generate mean field map using new PS
    mf_lm_new = hp.almxfl(CG.generate_mfterm(dlm,Cl_new,bl,nl),renorm)
    # get deterministic fluctuation map (new rescaling with noise)
    fluc_lm_determ = hp.almxfl(fluc_lm_GS,np.sqrt((1./Cl_old))/np.sqrt((1./Cl_new)))
    # get GS fluctuation map "for next iteration"
    fluc_lm_GS_next = hp.almxfl(CG.generate_w1term(Cl_new,bl,nl)+CG.generate_w0term(Cl_new),renorm)
    # Chi2 part of the likelihood
    return fluc_lm_determ,mf_lm_new, fluc_lm_GS_next, Cl_new
def target_distrib(guess, *arg):
    """
    Keyword Arguments:
    x -- the vector of params

    *args are:
    arg[0] -- a target class object
    arg[1] -- Cl_old, fluc_lm_old
    """
    #print guess, arg
    dlm,strings,params,nl,bl = arg[0]
    Cl_old, fluc_lm_old = arg[1]
    dd = cb.update_dic(params,guess,strings)
    Cl_new = cb.generate_spectrum(dd)[:,1]
    Cl_new[:2] = 1.e-35
    #print "new = ",Cl_new[50]
    #print "old = ",Cl_old[50]
    renorm = CG.renorm_term(Cl_new,bl,nl)
    mf_lm_new = hp.almxfl(CG.generate_mfterm(dlm,Cl_new,bl,nl),renorm)
    fluc_lm_type2 = hp.almxfl(CG.generate_w1term(Cl_new,bl,nl)+CG.generate_w0term(Cl_new),renorm)
    #print "new = ",fluc_lm_type2[50]
    #print "old = ",fluc_lm_old[50]
    fluc_lm_determ = hp.almxfl(fluc_lm_old,np.sqrt(Cl_new/Cl_old))
    tt1 = -1/2.*np.real(np.vdot((dlm-hp.almxfl(mf_lm_new,bl)).T,hp.almxfl((dlm-hp.almxfl(mf_lm_new,bl)),1/nl)))
    #print tt1
    tt2 = -1/2. *np.real(np.vdot((mf_lm_new).T,hp.almxfl((mf_lm_new),1./Cl_new)))
    #print tt2
    tt3 = -1/2. *np.real(np.vdot((fluc_lm_determ).T,hp.almxfl((fluc_lm_determ),1/nl*bl**2)))
    #print tt3
    #tt4 = - 1./2 *(np.arange(1,np.size(Cl_new)+1)*np.log(Cl_new)).sum()
    ##print tt4
    return [tt1,tt2,tt3],Cl_new,fluc_lm_type2
def test_fluctuation_term(guess, *arg):
    """
    Keyword Arguments:
    x -- the vector of params

    *args are:
    arg[0] -- a target class object
    arg[1] -- Cl_old, fluc_lm_old
    """
    ##print guess, arg
    dlm,strings,params,nl,bl = arg[0]
    Cl_old, fluc_lm_old = arg[1]
    dd = cb.update_dic(params,guess,strings)
    #generate new spectrum from new params
    lmax = len(Cl_old)
    Cl_new = cb.generate_spectrum(dd)[:lmax,1]
    # avoid dividing by 0
    Cl_new[:2] = 1.e-35
    #print "new = ",Cl_new[50]
    #print "old = ",Cl_old[50]
    # renormalization, i.e. lhs part of eq (24) and (25)
    renorm = CG.renorm_term(Cl_new,bl,nl)

    # generate fluctuation map using new PS, this is actually the 'step 2', with acceptance 1, won't be used anymore in this function
    fluc_lm_type2 = hp.almxfl(CG.generate_w1term(Cl_new,bl,nl)+CG.generate_w0term(Cl_new),renorm)
    #print "new = ",fluc_lm_type2[50]
    #print "old = ",fluc_lm_old[50]
    # get deterministic fluctuation map (new rescaling with noise)
    fluc_lm_determ = hp.almxfl(fluc_lm_old,np.sqrt((1./Cl_old+bl**2/nl))/np.sqrt((1./Cl_new+bl**2/nl)))
    # "fluctuation part" of the likelihood
    tt3 = -1/2. *np.real(np.vdot((fluc_lm_determ).T,hp.almxfl((fluc_lm_determ),1/nl*bl**2)))
    #print tt3
    # we return Cl_new and fluc_lm_type2 for next iteration.
    return tt3,Cl_new,fluc_lm_type2,fluc_lm_determ
def functional_form_params_n(x,*arg):
    """
    Keyword Arguments:
    x -- the vector of params

    *args are:
    dlm -- input map
    x_str -- the dictionary strings corresponding to x
    params -- a camber dictionnary
    noise -- a noise power spectrum
    beam -- a beam power spectrum
    """
    dlm = arg[0]
    strings = arg[1]
    params = arg[2].copy()
    noise = arg[3]
    beam = arg[4]    
    Cl_old = arg[5]
    lmax = len(Cl_old)-1
    #params["output_root"] = '../Codes/CG_git/MH_MCMC/camb_ini/test%d'%np.random.randint(100)
    for i in range(np.size(x)):
        ##print strings[i]
        if strings[i]=='scalar_amp(1)':
            ##print params[strings[i]]
            params[strings[i]]=np.exp(x[i])*1e-10
            ##print params[strings[i]]
        else:
            params[strings[i]]=x[i]
    Cl = cb.generate_spectrum(params)
    #lmax = Cl.shape[0]-1
    tt = -1./2 * np.real(np.vdot(CG.complex2real_alm(dlm.T),CG.complex2real_alm(hp.almxfl(dlm,1/(beam[:lmax+1]**2*Cl[:lmax+1,1]+noise[:lmax+1])))))    
    #determinant is the product of the diagonal element: in log:
    tt2 =  - 1./2 *((2*np.arange(2,lmax+1)+1)*np.log(noise[2:lmax+1]+Cl[2:lmax+1,1]*beam[2:lmax+1]**2)).sum()
    return tt+tt2,Cl[:,1]
def solve_CG(params_i,dd):
    dd = cb.update_dic(dd,params_i,strings)
    cl = cb.generate_spectrum(dd)[:,1]
    # define the first guess, the b from eq 25 since the code was design with this at first (might not be best idea ever)
    b_mf = CG.generate_mfterm(dlm_filt,cl[:lmax+1],bl[:lmax+1],nl[:lmax+1])
    b_w1 = CG.generate_w1term(cl[:lmax+1],bl[:lmax+1],nl[:lmax+1])
    b_w0 = CG.generate_w0term(cl[:lmax+1])
    b = b_mf + b_w1 + b_w0
    ###### left hand side factor
    renorm= np.sqrt(cl[:lmax+1])/(1+cl[:lmax+1]*bl[:lmax+1]**2/(nl[:lmax+1]))
    out = hp.almxfl(b,renorm)
    out_mf = hp.almxfl(b_mf,renorm)
    out_w1 = hp.almxfl(b_w1,renorm)
    out_w0 = hp.almxfl(b_w0,renorm)
    return out,out_mf,out_w0,out_w1
def test_3rd_Term(list_guess):
    #initial guess
    guess_param = PS2P.prop_dist_form_params(x_mean,cov_new)
    # generate first fluctuation map
    dd2 = cb.update_dic(dd,guess_param,strings)
    cl = cb.generate_spectrum(dd2)[:,1]
    cl[:2] = 1.e-35
    renorm = CG.renorm_term(cl,bl,nl)
    fluc = hp.almxfl(CG.generate_w1term(cl[:lmax+1],bl[:lmax+1],nl[:lmax+1]) + CG.generate_w0term(cl[:lmax+1]),renorm)
    Cl_i,fluc_i = [cl,fluc]
    list_save=[]
    for i in range(len(list_guess)):
        print i
        test_param = list_guess[i]
        Like_3,Cl_ip1,fluc_ip1,fluc_i_rescaled = test_fluctuation_term(test_param,[dlm,strings,dd2,nl[:lmax+1],bl[:lmax+1]],[Cl_i, fluc_i])
        Cl_i,fluc_i = [Cl_ip1,fluc_ip1]
        list_save.append([Like_3,Cl_ip1,fluc_ip1,fluc_i_rescaled])
    return list_save
########### Here we simulate the data set ############

# White noise spectrum, (Commander level, so low)
#nl = 1.7504523623688016e-16*1e12 * np.ones(2500)
#nl = 1.7504523623688016e-16*1e12 * np.ones(2500) *2


# Gaussian beam fwhm 5 arcmin 
#bl = CG.gaussian_beam(2500,5)
#bl = CG.gaussian_beam(2500,5*np.sqrt(hp.nside2pixarea(nside,degrees=True))*60)
bl = CG.gaussian_beam(2500,13)

# Spectrum according to parameter defined above
if generate_new_data==1:
    Cl = cb.generate_spectrum(dd)
    # White noise level defined so that SNR=1 at \ell of 1700
    nl = Cl[900,1]*bl[900]**2*np.ones(2500)
    lmax_temp = Cl.shape[0]-1
    alm = hp.synalm(Cl[:,1])
    dlm = hp.almxfl(alm,bl[:lmax_temp+1])
    nlm = hp.synalm(nl[:lmax_temp+1])
    dlm = dlm+nlm
    #np.save("Dataset_planck2015_900SNR1_13arcmin.npy",dlm)
    plt.figure()
    ell = np.arange(lmax)*np.arange(1,lmax+1)
    plt.plot(ell*(Cl[:lmax,1]*bl[:lmax]**2),label = "$C_\ell b_\ell^2$")
    plt.plot(ell*(nl[:lmax]),label="$n_\ell$")
    plt.plot(ell*(Cl[:lmax,1]*bl[:lmax]**2+nl[:lmax]),"--",label = "$C_\ell b_\ell^2 + n_\ell$")
    plt.ylabel("$\ell (\ell +1) C_\ell$")
    plt.xlabel("$\ell$")
 def get_spec(self,x):
     parameters = cb.update_dic(self.params,x,self.strings)
     return cb.generate_spectrum(parameters)