jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def nbar_halo(self,zs,logmlow,logmhigh):
        zs = np.atleast_1d(zs)
        zs[zs<0.001] = 0.001
        self._setup_k_z_m_grid_functions(zs)        
        lnmlow=np.log(10.**logmlow)
        lnmhigh=np.log(10.**logmhigh)
        lnmsin=self.lnms[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh)]
        nfnin=self.nfn[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh),:]
        nhalobinned=np.zeros(self.z.shape[0])
        for j in range(0,self.z.shape[0]):
            nhalobinned[j]=integrate.simpson(np.exp(lnmsin)*nfnin[:,j],lnmsin)
        return nhalobinned
//  [python]
def bias_halo(self,zs,logmlow,logmhigh):
        zs = np.atleast_1d(zs)
        zs[zs<0.001] = 0.001
        self._setup_k_z_m_grid_functions(zs)            
        lnmlow=np.log(10.**logmlow)
        lnmhigh=np.log(10.**logmhigh)
        lnmsin=self.lnms[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh)]
        nfnin=self.nfn[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh),:]
        halobiasin=self.halobias[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh),:]
        bhalo = np.zeros([self.z.shape[0]])
        for j in range(0,self.z.shape[0]):
            bhalo[j]=integrate.simps((np.exp(lnmsin))*nfnin[:,j]*halobiasin[:,j],lnmsin)/integrate.simps((np.exp(lnmsin))*nfnin[:,j],lnmsin) #as eq 49 
        return bhalo
//  [python]
def bias_halo(self,zs,logmlow,logmhigh):
        zs = np.atleast_1d(zs)
        zs[zs<0.001] = 0.001
        self._setup_k_z_m_grid_functions(zs)            
        lnmlow=np.log(10.**logmlow)
        lnmhigh=np.log(10.**logmhigh)
        lnmsin=self.lnms[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh)]
        nfnin=self.nfn[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh),:]
        halobiasin=self.halobias[(self.lnms>=lnmlow)&(self.lnms<=lnmhigh),:]
        bhalo = np.zeros([self.z.shape[0]])
        for j in range(0,self.z.shape[0]):
            bhalo[j]=integrate.simpson((np.exp(lnmsin))*nfnin[:,j]*halobiasin[:,j],lnmsin)/integrate.simpson((np.exp(lnmsin))*nfnin[:,j],lnmsin) #as eq 49 
        return bhalo
//  [python]
def radially_integrated_psd(q, C):
    """Assumes no roll-off/cut-off in PSD."""
    if q[0] > q[1]:
        q = q[::-1]
        C = C[::-1]
    return 2 * np.pi * scin.simps(np.multiply(q, C), q)
//  [python]
def radially_integrated_psd(q, C):
    """Assumes no roll-off/cut-off in PSD."""
    if q[0] > q[1]:
        q = q[::-1]
        C = C[::-1]
    return 2 * np.pi * scipy.integrate.simpson(np.multiply(q, C), q)
//  [python]
def calc_Iq_from_Pr(q, r, Pr):
    Iq = np.array([simps(Pr * j0(qk*r), r) for qk in q])
    #Iq = np.array([np.trapz(Pr * j0(qk*r), r) for qk in q])
    #Iq /= Iq[0]
    return Iq
//  [python]
def calc_Iq_from_Pr(q, r, Pr):
    Iq = np.array([simpson(Pr * j0(qk*r), r) for qk in q])
    #Iq = np.array([np.trapz(Pr * j0(qk*r), r) for qk in q])
    #Iq /= Iq[0]
    return Iq
//  [python]
def test_pdf_5(conv_norm_lognorm):
    x1 = -np.flipud(np.logspace(-5, np.log10(10.2), 300))
    x2 = np.logspace(-5, 5, 300)
    x = np.concatenate([x1, x2])
    integral = scipy.integrate.simps(
        conv_norm_lognorm.pdf(x, 1.7, 1., -0.2, 2.), x)
    assert np.isclose(integral, 1.0)
//  [python]
def test_pdf_5(conv_norm_lognorm):
    x1 = -np.flipud(np.logspace(-5, np.log10(10.2), 300))
    x2 = np.logspace(-5, 5, 300)
    x = np.concatenate([x1, x2])
    integral = scipy.integrate.simpson(
        conv_norm_lognorm.pdf(x, 1.7, 1., -0.2, 2.), x)
    assert np.isclose(integral, 1.0)
//  [python]
def test_pdf_6(conv_lognorm_gamma):
    x = -1 + np.logspace(-4, 5, 200)
    integral = scipy.integrate.simps(
        conv_lognorm_gamma.pdf(x, 1.5, 1.7, 1.3, -1, 1.2), x)
    assert np.isclose(integral, 1.0, rtol=1e-4, atol=1e-4)
//  [python]
def test_pdf_6(conv_lognorm_gamma):
    x = -1 + np.logspace(-4, 5, 200)
    integral = scipy.integrate.simpson(
        conv_lognorm_gamma.pdf(x, 1.5, 1.7, 1.3, -1, 1.2), x)
    assert np.isclose(integral, 1.0, rtol=1e-4, atol=1e-4)
//  [python]
def calculate_delay(
        time,
        lat,
        lon,
        frequency,
        elevation,
    ):
    '''TODO: Docstring
    '''
    

    if Point is None or gcoord is None:
        raise ImportError('pyglow must be installed to calculate delay')

    if not isinstance(time, Time):
        dn = time
    else:
        dn = time.tt.datetime

    num=500
    alts=np.linspace(0,4000,num=num)
    distance=np.linspace(0,4000,num=num)
    ne=np.zeros(num)
    xyz_prev=0.0
    for ai,a in enumerate(alts):
        llh=coord.az_el_r2geodetic(lat, lon, 0, 180.0, elevation, a*1e3)

        pt = Point(dn, llh[0], llh[1], llh[2]/1e3)
        pt.run_iri()
        if pt.ne > 0.0:
            ne[ai]=pt.ne*1e6
        else:
            ne[ai]=0.0
        xyz=gcoord.lla2ecef(np.array([lat,lon,a]))[0]
        if ai==0:
            distance[ai]=0.0
        else:
            distance[ai]=np.sqrt(np.dot(xyz-xyz_prev,xyz-xyz_prev))+distance[ai-1]
        xyz_prev=xyz
        
    f_p=8.98*np.sqrt(ne)
    v_g = constants.c*np.sqrt(1-(f_p/frequency)**2.0)

    dt2=integrate.simps(1.0 - 1.0/(np.sqrt(1-(f_p/frequency)**2.0)),distance*1e3)/constants.c

    return dt2, ne, distance
//  [python]
def calculate_delay(
        time,
        lat,
        lon,
        frequency,
        elevation,
    ):
    '''TODO: Docstring
    '''
    

    if Point is None or gcoord is None:
        raise ImportError('pyglow must be installed to calculate delay')

    if not isinstance(time, Time):
        dn = time
    else:
        dn = time.tt.datetime

    num=500
    alts=np.linspace(0,4000,num=num)
    distance=np.linspace(0,4000,num=num)
    ne=np.zeros(num)
    xyz_prev=0.0
    for ai,a in enumerate(alts):
        llh=coord.az_el_r2geodetic(lat, lon, 0, 180.0, elevation, a*1e3)

        pt = Point(dn, llh[0], llh[1], llh[2]/1e3)
        pt.run_iri()
        if pt.ne > 0.0:
            ne[ai]=pt.ne*1e6
        else:
            ne[ai]=0.0
        xyz=gcoord.lla2ecef(np.array([lat,lon,a]))[0]
        if ai==0:
            distance[ai]=0.0
        else:
            distance[ai]=np.sqrt(np.dot(xyz-xyz_prev,xyz-xyz_prev))+distance[ai-1]
        xyz_prev=xyz
        
    f_p=8.98*np.sqrt(ne)
    v_g = constants.c*np.sqrt(1-(f_p/frequency)**2.0)

    dt2=integrate.simpson(1.0 - 1.0/(np.sqrt(1-(f_p/frequency)**2.0)),distance*1e3)/constants.c

    return dt2, ne, distance
//  [python]
fig1 = plt.figure(1, figsize=(2 * 10, 10))
fig1.set_facecolor('w')
sp1 = fig1.add_subplot(1, 2, 1)
sp2 = fig1.add_subplot(1, 2, 2)


for i_ct, ct in enumerate(cos_theta_test):
    areats = scipy.integrate.simps(extract_ene_hist['true'][:, i_ct], extract_ene_hist['emit_ene_g_hist'])
    areae = scipy.integrate.simps(extract_ene_hist['elast'][:, i_ct], extract_ene_hist['emit_ene_g_hist'])
    thiscol = ms.colorprog(i_ct, len(cos_theta_test))
    label = 'costheta=%.2f' % ct
    sp1.plot(extract_ene_hist['emit_ene_g_hist'], extract_ene_hist['true'][:, i_ct] / areats, color=thiscol, label=label, alpha=alpha, linewidth=linewid, marker='o')
    sp2.plot(extract_ene_hist['emit_ene_g_hist'], extract_ene_hist['elast'][:, i_ct] / areae, color=thiscol, label=label, alpha=alpha, linewidth=linewid, marker='o')
//  [python]
fig1 = plt.figure(1, figsize=(2 * 10, 10))
fig1.set_facecolor('w')
sp1 = fig1.add_subplot(1, 2, 1)
sp2 = fig1.add_subplot(1, 2, 2)


for i_ct, ct in enumerate(cos_theta_test):
    areats = scipy.integrate.simpson(extract_ene_hist['true'][:, i_ct], extract_ene_hist['emit_ene_g_hist'])
    areae = scipy.integrate.simpson(extract_ene_hist['elast'][:, i_ct], extract_ene_hist['emit_ene_g_hist'])
    thiscol = ms.colorprog(i_ct, len(cos_theta_test))
    label = 'costheta=%.2f' % ct
    sp1.plot(extract_ene_hist['emit_ene_g_hist'], extract_ene_hist['true'][:, i_ct] / areats, color=thiscol, label=label, alpha=alpha, linewidth=linewid, marker='o')
    sp2.plot(extract_ene_hist['emit_ene_g_hist'], extract_ene_hist['elast'][:, i_ct] / areae, color=thiscol, label=label, alpha=alpha, linewidth=linewid, marker='o')
//  [python]
def _Ptwohalo(self,z,lnms,k,pk,uk1,uk2,nfn,rhomatter,halobias,spec,frequency = None,frequency2=None):
        #frequency and frequency2 are the CIB frequencies
        if  spec[:1] == 'm':
            spec1 = 'm'
        else:
            spec1 = spec[:3]
        if spec[-1] == 'm':
            spec2 = 'm'
        else:
            spec2=spec[-3:]
            
        #calculate consistency condition
        #TODO: check consistency function for observables other than mass and electrons.
        
        if 'gas' in spec or 'm' in spec:
            consistency=np.ones([z.shape[0]])
            if not self.use_counterterms:
                for j in range(0,z.shape[0]):
                    consistency[j] = integrate.simps(np.exp(2.*lnms)*nfn[:,j]*halobias[:,j]/(self.omegam*self.rhocrit),lnms)

        def Akmz(spec,uk,frequency=None):
            if spec == 'm' or spec == 'gas':
                return self.A_gas(lnms,uk,rhomatter)/consistency[np.newaxis,:,np.newaxis]
            if spec == 'CIB':
                return self.Anu_CIB(frequency,uk)
            if spec == 'tSZ':
                return self.A_tSZ(uk)
            if spec == 'gal':
                return self.A_gal(lnms,uk)
            
        twohalointegrand1 = np.exp(self.lnms[:,np.newaxis,np.newaxis])*self.nfn[:,:,np.newaxis]*self.halobias[:,:,np.newaxis]*Akmz(spec1,uk1,frequency)
                
        
        if self.use_counterterms:
                    
                    twohalointegrand1 += self.nmin[:,np.newaxis] * self.mmin_nfn * self.biasmin[:,np.newaxis] * Akmz(spec1,uk1,frequency)[self.mindex_mmin_nfn]

        
        if spec2 == spec1 and frequency == frequency2:
            twohalointegrand2 = twohalointegrand1
        else:
            twohalointegrand2 = np.exp(self.lnms[:,np.newaxis,np.newaxis])*self.nfn[:,:,np.newaxis]*self.halobias[:,:,np.newaxis]*Akmz(spec2,uk2,frequency2)
       
            if self.use_counterterms:

                    twohalointegrand2 += self.nmin[:,np.newaxis] * self.mmin_nfn * self.biasmin[:,np.newaxis] * Akmz(spec2,uk2,frequency)[self.mindex_mmin_nfn]
 
       
        
       
        Ptwohalo = np.zeros([z.shape[0],k.shape[0]])
        
        
            
        
        
        #TODO: maybe turn into slicing instead of loop?
        for j in range(0,z.shape[0]):
            for q in range(0,k.shape[0]):
                Ptwohalo[j,q] = pk[j,q]*integrate.simps(twohalointegrand1[:,j,q],lnms)*integrate.simps(twohalointegrand2[:,j,q],lnms)



        return Ptwohalo
//  [python]
def _Ptwohalo(self,z,lnms,k,pk,uk1,uk2,nfn,rhomatter,halobias,spec,frequency = None,frequency2=None):
        #frequency and frequency2 are the CIB frequencies
        if  spec[:1] == 'm':
            spec1 = 'm'
        else:
            spec1 = spec[:3]
        if spec[-1] == 'm':
            spec2 = 'm'
        else:
            spec2=spec[-3:]
            
        #calculate consistency condition
        #TODO: check consistency function for observables other than mass and electrons.
        
        if 'gas' in spec or 'm' in spec:
            consistency=np.ones([z.shape[0]])
            if not self.use_counterterms:
                for j in range(0,z.shape[0]):
                    consistency[j] = integrate.simpson(np.exp(2.*lnms)*nfn[:,j]*halobias[:,j]/(self.omegam*self.rhocrit),lnms)

        def Akmz(spec,uk,frequency=None):
            if spec == 'm' or spec == 'gas':
                return self.A_gas(lnms,uk,rhomatter)/consistency[np.newaxis,:,np.newaxis]
            if spec == 'CIB':
                return self.Anu_CIB(frequency,uk)
            if spec == 'tSZ':
                return self.A_tSZ(uk)
            if spec == 'gal':
                return self.A_gal(lnms,uk)
            
        twohalointegrand1 = np.exp(self.lnms[:,np.newaxis,np.newaxis])*self.nfn[:,:,np.newaxis]*self.halobias[:,:,np.newaxis]*Akmz(spec1,uk1,frequency)
                
        
        if self.use_counterterms:
                    
                    twohalointegrand1 += self.nmin[:,np.newaxis] * self.mmin_nfn * self.biasmin[:,np.newaxis] * Akmz(spec1,uk1,frequency)[self.mindex_mmin_nfn]

        
        if spec2 == spec1 and frequency == frequency2:
            twohalointegrand2 = twohalointegrand1
        else:
            twohalointegrand2 = np.exp(self.lnms[:,np.newaxis,np.newaxis])*self.nfn[:,:,np.newaxis]*self.halobias[:,:,np.newaxis]*Akmz(spec2,uk2,frequency2)
       
            if self.use_counterterms:

                    twohalointegrand2 += self.nmin[:,np.newaxis] * self.mmin_nfn * self.biasmin[:,np.newaxis] * Akmz(spec2,uk2,frequency)[self.mindex_mmin_nfn]
 
       
        
       
        Ptwohalo = np.zeros([z.shape[0],k.shape[0]])
        
        
            
        
        
        #TODO: maybe turn into slicing instead of loop?
        for j in range(0,z.shape[0]):
            for q in range(0,k.shape[0]):
                Ptwohalo[j,q] = pk[j,q]*integrate.simpson(twohalointegrand1[:,j,q],lnms)*integrate.simpson(twohalointegrand2[:,j,q],lnms)



        return Ptwohalo
//  [python]
def test_cdf_2(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 300),np.logspace(1.01, 4, 300)])
    parameters = (1.5, 1.7, 0.1, -1, 2.0)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simps(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
//  [python]
def test_cdf_2(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 300),np.logspace(1.01, 4, 300)])
    parameters = (1.5, 1.7, 0.1, -1, 2.0)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simpson(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
//  [python]
def test_cdf_3(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 200),np.logspace(1.01, 4, 100)])
    parameters = (1.5, 1.7, 1.3, -1, 1.7)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simps(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
//  [python]
def test_cdf_3(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 200),np.logspace(1.01, 4, 100)])
    parameters = (1.5, 1.7, 1.3, -1, 1.7)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simpson(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
//  [python]
def test_cdf_4(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 200),np.logspace(1.01, 4, 100)])
    parameters = (1.5, 1.7, 2.0, -1, 0.3)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simps(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
    assert np.isclose(cdf_directly[-1], 1.0)
//  [python]
def test_cdf_4(conv_lognorm_gamma):
    x = np.concatenate([np.linspace(-8, 10, 200),np.logspace(1.01, 4, 100)])
    parameters = (1.5, 1.7, 2.0, -1, 0.3)
    limits = [0, 1, 10, 100, 1e4, np.max(x)]
    y = conv_lognorm_gamma.pdf(x, *parameters)
    cdf_from_pdf = []
    cdf_directly = []
    for limit in limits:
        nearest_limit = x[np.argmin(np.abs(x - limit))]
        sel = x <= nearest_limit
        cdf_from_pdf.append(scipy.integrate.simpson(y[sel], x[sel]))
        cdf_directly.append(conv_lognorm_gamma.cdf(nearest_limit, *parameters))
    assert np.all(np.isclose(cdf_from_pdf, cdf_directly, rtol=1e-4, atol=1e-4))
    assert np.isclose(cdf_directly[-1], 1.0)
//  [python]
def Pivot_wavelength(band_func, w):
    """
    band_func: function that interpolates the filter response at a given
        set of wavelengths.
    w: wavelengths in A.

    See The Alhambra Photometric System (doi:10.1088/0004-6256/139/3/1242) for more details.
    See also The Mauna Kea Observatories Near-Infrared Filter Set. III. Isophotal Wavelengths and Absolute Calibration (doi:10.1086/429382).
    """
    ## The following equation is from Bessell & Murphy 2012 (eq. A15)
    f_band = band_func(w)
    f_pivot = scipy.integrate.simps(f_band*w, w) / scipy.integrate.simps(f_band/w, w)
    f_pivot = np.sqrt(f_pivot)
    return f_pivot
//  [python]
def Pivot_wavelength(band_func, w):
    """
    band_func: function that interpolates the filter response at a given
        set of wavelengths.
    w: wavelengths in A.

    See The Alhambra Photometric System (doi:10.1088/0004-6256/139/3/1242) for more details.
    See also The Mauna Kea Observatories Near-Infrared Filter Set. III. Isophotal Wavelengths and Absolute Calibration (doi:10.1086/429382).
    """
    ## The following equation is from Bessell & Murphy 2012 (eq. A15)
    f_band = band_func(w)
    f_pivot = scipy.integrate.simpson(f_band*w, w) / scipy.integrate.simpson(f_band/w, w)
    f_pivot = np.sqrt(f_pivot)
    return f_pivot
//  [python]
def PSF_SEDs(gparam, filter_file, bulge_SED_file, disk_SED_file, redshift):
    # get surviving photons given filter and SEDs
    bulge_wave, bulge_photons = chroma.utils.get_photons(bulge_SED_file, filter_file, redshift)
    disk_wave, disk_photons = chroma.utils.get_photons(disk_SED_file, filter_file, redshift)
    bulge_photons /= scipy.integrate.simps(bulge_photons, bulge_wave)
    disk_photons /= scipy.integrate.simps(disk_photons, disk_wave)
    composite_wave = numpy.union1d(bulge_wave, disk_wave)
    composite_wave.sort()
    composite_photons = numpy.interp(composite_wave, bulge_wave, bulge_photons,
                                     left=0.0, right=0.0) * gparam['b_flux'].value \
                        + numpy.interp(composite_wave, disk_wave, disk_photons,
                                       left=0.0, right=0.0) * gparam['d_flux'].value
    waves = bulge_wave, disk_wave, composite_wave
    photonses = bulge_photons, disk_photons, composite_photons
    return waves, photonses
//  [python]
def PSF_SEDs(gparam, filter_file, bulge_SED_file, disk_SED_file, redshift):
    # get surviving photons given filter and SEDs
    bulge_wave, bulge_photons = chroma.utils.get_photons(bulge_SED_file, filter_file, redshift)
    disk_wave, disk_photons = chroma.utils.get_photons(disk_SED_file, filter_file, redshift)
    bulge_photons /= scipy.integrate.simpson(bulge_photons, bulge_wave)
    disk_photons /= scipy.integrate.simpson(disk_photons, disk_wave)
    composite_wave = numpy.union1d(bulge_wave, disk_wave)
    composite_wave.sort()
    composite_photons = numpy.interp(composite_wave, bulge_wave, bulge_photons,
                                     left=0.0, right=0.0) * gparam['b_flux'].value \
                        + numpy.interp(composite_wave, disk_wave, disk_photons,
                                       left=0.0, right=0.0) * gparam['d_flux'].value
    waves = bulge_wave, disk_wave, composite_wave
    photonses = bulge_photons, disk_photons, composite_photons
    return waves, photonses
//  [python]
def alphaCell(self,xC,yC,dx,N=100):
        #d=self.distance(xC,yC)
        #if d>1./np.sqrt(2)*dx:
        #    return self.value(xC,yC)
        h=dx/N
        xL=np.linspace(xC-dx/2.,xC+dx/2.,N+1)
        yL=np.linspace(yC-dx/2.,yC+dx/2.,N+1)
        sumA=np.zeros(4)
        yP=np.ones(N+1)*yL[0]
        sumA[0]=np.mean(self.value(xL,yP))
        yP=np.ones(N+1)*yL[-1]
        sumA[1]=np.mean(self.value(xL,yP))
        xP=np.ones(N+1)*xL[0]
        sumA[2]=np.mean(self.value(xP,yL))
        xP=np.ones(N+1)*xL[-1]
        sumA[3]=np.mean(self.value(xP,yL))
        sum=np.mean(sumA)
        if sum==0:
            return 0.
        elif sum==1:
            return 1.
        else:
            H=np.zeros(N+1)
            for n in range(N+1):
                xP=np.ones(N+1)*xL[n]
                H[n]=scipy.integrate.simps(self.value(xP,yL),yL)
                #H[n]=numpy.trapz(self.value(xP,yL),dx=h)
            return scipy.integrate.simps(H,xL)/dx/dx
//  [python]
def alphaCell(self,xC,yC,dx,N=100):
        #d=self.distance(xC,yC)
        #if d>1./np.sqrt(2)*dx:
        #    return self.value(xC,yC)
        h=dx/N
        xL=np.linspace(xC-dx/2.,xC+dx/2.,N+1)
        yL=np.linspace(yC-dx/2.,yC+dx/2.,N+1)
        sumA=np.zeros(4)
        yP=np.ones(N+1)*yL[0]
        sumA[0]=np.mean(self.value(xL,yP))
        yP=np.ones(N+1)*yL[-1]
        sumA[1]=np.mean(self.value(xL,yP))
        xP=np.ones(N+1)*xL[0]
        sumA[2]=np.mean(self.value(xP,yL))
        xP=np.ones(N+1)*xL[-1]
        sumA[3]=np.mean(self.value(xP,yL))
        sum=np.mean(sumA)
        if sum==0:
            return 0.
        elif sum==1:
            return 1.
        else:
            H=np.zeros(N+1)
            for n in range(N+1):
                xP=np.ones(N+1)*xL[n]
                H[n]=scipy.integrate.simpson(self.value(xP,yL),yL)
                #H[n]=numpy.trapz(self.value(xP,yL),dx=h)
            return scipy.integrate.simpson(H,xL)/dx/dx
//  [python]
def P_R_fog_soft(p, R: float, n: int = None) -> float:

    if n is None:
        n = p.n

    def integrand(t: np.ndarray) -> np.ndarray:
        arr = (np.sin(np.pi / (2 * p.tau_h) * t) ** 2) \
              * (np.exp(-2 * p.alpha * (R - ((c * t) / 2)))) \
              * inverse_square_modified(p, R, t) \
              * xsi_loop(p, R - ((c * t) / 2)) \
              * np.heaviside(p.r_0 - R + (c * t) / 2, 0)

        return arr

    start = 0
    stop = 2 * p.tau_h

    x = np.linspace(start, stop, n)
    y = integrand(x)

    integral = scipy_integrate.simps(y, x)

    return p.c_a * p.p_0 * p.beta * integral
//  [python]
def P_R_fog_soft(p, R: float, n: int = None) -> float:

    if n is None:
        n = p.n

    def integrand(t: np.ndarray) -> np.ndarray:
        arr = (np.sin(np.pi / (2 * p.tau_h) * t) ** 2) \
              * (np.exp(-2 * p.alpha * (R - ((c * t) / 2)))) \
              * inverse_square_modified(p, R, t) \
              * xsi_loop(p, R - ((c * t) / 2)) \
              * np.heaviside(p.r_0 - R + (c * t) / 2, 0)

        return arr

    start = 0
    stop = 2 * p.tau_h

    x = np.linspace(start, stop, n)
    y = integrand(x)

    integral = scipy.integrate.simpson(y, x)

    return p.c_a * p.p_0 * p.beta * integral
//  [python]
def normalisation(Mhalo, cosmo, conc, z):
    """ Returns the 'normalisation factor' that goes into the IA halo model
    power spectrum: satelite fraction * Nsat / tot_ns as a function of Mhalo.
    Mhalo is the vector of halo masses over which to integrate in units of Msol
    cosmo is a pyccl cosmology object
    conc is a concentration relation object
    z is the redshift at which to calculate this
    """

    # Get the halo mass function
    HMF_setup = ccl.halos.MassFuncTinker10(cosmo)
    HMF = HMF_setup.get_mass_function(cosmo, Mhalo, 1. / (1. + z))

    # Get HOD quantities we need
    HODHProf = ccl.halos.HaloProfileHOD(conc)
    Ncen_lens = HODHProf._Nc(Mhalo, 1. / (1. + z))
    Nsat_lens = HODHProf._Ns(Mhalo, 1. / (1. + z))

    # Get total number of satellite galaxies
    tot_ns = scipy.integrate.simps(Ncen_lens * Nsat_lens * HMF, np.log10(Mhalo))
    tot_nc = scipy.integrate.simps((Ncen_lens) * HMF, np.log10(Mhalo))

    tot_all = tot_ns + tot_nc

    # Fraction of satellites:
    f_s = tot_ns / tot_all

    return f_s / tot_ns * Nsat_lens
//  [python]
def normalisation(Mhalo, cosmo, conc, z):
    """ Returns the 'normalisation factor' that goes into the IA halo model
    power spectrum: satelite fraction * Nsat / tot_ns as a function of Mhalo.
    Mhalo is the vector of halo masses over which to integrate in units of Msol
    cosmo is a pyccl cosmology object
    conc is a concentration relation object
    z is the redshift at which to calculate this
    """

    # Get the halo mass function
    HMF_setup = ccl.halos.MassFuncTinker10(cosmo)
    HMF = HMF_setup.get_mass_function(cosmo, Mhalo, 1. / (1. + z))

    # Get HOD quantities we need
    HODHProf = ccl.halos.HaloProfileHOD(conc)
    Ncen_lens = HODHProf._Nc(Mhalo, 1. / (1. + z))
    Nsat_lens = HODHProf._Ns(Mhalo, 1. / (1. + z))

    # Get total number of satellite galaxies
    tot_ns = scipy.integrate.simpson(Ncen_lens * Nsat_lens * HMF, np.log10(Mhalo))
    tot_nc = scipy.integrate.simpson((Ncen_lens) * HMF, np.log10(Mhalo))

    tot_all = tot_ns + tot_nc

    # Fraction of satellites:
    f_s = tot_ns / tot_all

    return f_s / tot_ns * Nsat_lens
//  [python]
def psf(p):
    """
    Calculate PSF at a given theta.
    
    A(p) * PSF(p) = 2 pi \int n(u) u J_0(2 pi u p) du
    
    (where p = theta and A(p) = primary beam pattern)
    """
    # FIXME: Expression needs checking!
    y = n_u * u * scipy.special.jv(0, 2.*np.pi*u*p)
    return 2.*np.pi * scipy.integrate.simps(y, u)
//  [python]
def psf(p):
    """
    Calculate PSF at a given theta.
    
    A(p) * PSF(p) = 2 pi \int n(u) u J_0(2 pi u p) du
    
    (where p = theta and A(p) = primary beam pattern)
    """
    # FIXME: Expression needs checking!
    y = n_u * u * scipy.special.jv(0, 2.*np.pi*u*p)
    return 2.*np.pi * scipy.integrate.simpson(y, u)
//  [python]
def isotopes_evolution(self, t_n, y_n, n, **kwargs):
        '''
        Explicit general diff eq GCE function
        INPUT
        t_n        time_chosen[n]
        y_n        dependent variable at n
        n        index of the timestep
        Functions:
        Infall rate: [Msun/Gyr]
        SFR: [Msun/Gyr]
        '''
        i = kwargs['i']
        Wi_comps = kwargs['Wi_comp'] 
        Z_comps = kwargs['Z_comp'] 
        infall_comp = self.Infall_rate[n] * self.models_BBN[i]
        self.W_i_comp['BBN'][i,n] = infall_comp
        sfr_comp = self.SFR_v[n] * self.Xi_v[i,n] # astration
        if n <= 0:
            val = infall_comp - sfr_comp
        else:
            Wi_vals = {}
            for ch in self.IN.include_channel:
                if ch == 'SNIa':
                    Wi_vals[ch] = 0.5 * (self.Rate_SNIa[n] * # Don't count SNIas twice
                                   self.yield_models['SNIa'][i])
                else:
                    if len(Wi_comps[ch]['birthtime_grid']) > 1.:
                        if not self.yield_models[ch][i].empty:
                            yield_grid = Z_comps[ch]
                            yield_grid['mass'] = Wi_comps[ch]['mass_grid']
                            Wi_vals[ch] = integr.simps(np.multiply(
                                        Wi_comps[ch]['integrand'], 
                                        self.yield_models[ch][i](yield_grid)), 
                                        x=Wi_comps[ch]['mass_grid'])
                        else:
                            Wi_vals[ch] = 0.
                    else:
                        Wi_vals[ch] = 0.
                self.W_i_comp[ch][i,n] = Wi_vals[ch] 
            val = infall_comp - sfr_comp + np.sum([Wi_vals[ch] 
                                        for ch in self.IN.include_channel])
        return val
//  [python]
def isotopes_evolution(self, t_n, y_n, n, **kwargs):
        '''
        Explicit general diff eq GCE function
        INPUT
        t_n        time_chosen[n]
        y_n        dependent variable at n
        n        index of the timestep
        Functions:
        Infall rate: [Msun/Gyr]
        SFR: [Msun/Gyr]
        '''
        i = kwargs['i']
        Wi_comps = kwargs['Wi_comp'] 
        Z_comps = kwargs['Z_comp'] 
        infall_comp = self.Infall_rate[n] * self.models_BBN[i]
        self.W_i_comp['BBN'][i,n] = infall_comp
        sfr_comp = self.SFR_v[n] * self.Xi_v[i,n] # astration
        if n <= 0:
            val = infall_comp - sfr_comp
        else:
            Wi_vals = {}
            for ch in self.IN.include_channel:
                if ch == 'SNIa':
                    Wi_vals[ch] = 0.5 * (self.Rate_SNIa[n] * # Don't count SNIas twice
                                   self.yield_models['SNIa'][i])
                else:
                    if len(Wi_comps[ch]['birthtime_grid']) > 1.:
                        if not self.yield_models[ch][i].empty:
                            yield_grid = Z_comps[ch]
                            yield_grid['mass'] = Wi_comps[ch]['mass_grid']
                            Wi_vals[ch] = integr.simpson(np.multiply(
                                        Wi_comps[ch]['integrand'], 
                                        self.yield_models[ch][i](yield_grid)), 
                                        x=Wi_comps[ch]['mass_grid'])
                        else:
                            Wi_vals[ch] = 0.
                    else:
                        Wi_vals[ch] = 0.
                self.W_i_comp[ch][i,n] = Wi_vals[ch] 
            val = infall_comp - sfr_comp + np.sum([Wi_vals[ch] 
                                        for ch in self.IN.include_channel])
        return val
//  [python]
def LOS_calc_signal(
    ff, D, u, dL, DL=None, dLMode="abs", method="romb", Test=True
):
    assert hasattr(ff, "__call__"), (
        "Arg ff must be a callable (function) taking at least 1 positional ",
        "Pts (a (3,N) np.ndarray of cartesian (X,Y,Z) coordinates) !",
    )
    assert not method == "linspace"
    Pts, k, dLr = LOS_get_sample(
        D, u, dL, DL=DL, dLMode=dLMode, method=method, Test=Test
    )
    out = insp(ff)
    N = np.sum(
        [
            (
                pp.kind == pp.POSITIONAL_OR_KEYWORD
                and pp.default is pp.empty
            )
            for pp in out.parameters.values()
        ]
    )

    if N == 1:
        Vals = ff(Pts)
    elif N == 2:
        Vals = ff(Pts, np.tile(-u, (Pts.shape[1], 1)).T)
    else:
        raise ValueError(
            "The function (ff) assessing the emissivity locally "
            + "must take a single positional argument: Pts a (3,N)"
            + " np.ndarray of (X,Y,Z) cartesian coordinates !"
        )

    Vals[np.isnan(Vals)] = 0.0
    if method == "sum":
        Int = np.sum(Vals) * dLr
    elif method == "simps":
        Int = scpintg.simps(Vals, x=None, dx=dLr)
    elif method == "romb":
        Int = scpintg.romb(Vals, dx=dLr, show=False)
    return Int
//  [python]
def LOS_calc_signal(
    ff, D, u, dL, DL=None, dLMode="abs", method="romb", Test=True
):
    assert hasattr(ff, "__call__"), (
        "Arg ff must be a callable (function) taking at least 1 positional ",
        "Pts (a (3,N) np.ndarray of cartesian (X,Y,Z) coordinates) !",
    )
    assert not method == "linspace"
    Pts, k, dLr = LOS_get_sample(
        D, u, dL, DL=DL, dLMode=dLMode, method=method, Test=Test
    )
    out = insp(ff)
    N = np.sum(
        [
            (
                pp.kind == pp.POSITIONAL_OR_KEYWORD
                and pp.default is pp.empty
            )
            for pp in out.parameters.values()
        ]
    )

    if N == 1:
        Vals = ff(Pts)
    elif N == 2:
        Vals = ff(Pts, np.tile(-u, (Pts.shape[1], 1)).T)
    else:
        raise ValueError(
            "The function (ff) assessing the emissivity locally "
            + "must take a single positional argument: Pts a (3,N)"
            + " np.ndarray of (X,Y,Z) cartesian coordinates !"
        )

    Vals[np.isnan(Vals)] = 0.0
    if method == "sum":
        Int = np.sum(Vals) * dLr
    elif method == "simps":
        Int = scpintg.simpson(Vals, x=None, dx=dLr)
    elif method == "romb":
        Int = scpintg.romb(Vals, dx=dLr, show=False)
    return Int
//  [python]
def green_kubo_D(self, el):
        self.get_v(el)
        # Get velocity autocorrelation function for each site
        vacfs = []
        for site_vel in self.vel_matrix:
            _vacf = np.correlate(site_vel, site_vel, "full")
            vacfs.append(_vacf)
        self.vacfs = vacfs
        D = []
        for vacf in vacfs:
            D.append(integrate.simps(vacf))
        return D
//  [python]
def green_kubo_D(self, el):
        self.get_v(el)
        # Get velocity autocorrelation function for each site
        vacfs = []
        for site_vel in self.vel_matrix:
            _vacf = np.correlate(site_vel, site_vel, "full")
            vacfs.append(_vacf)
        self.vacfs = vacfs
        D = []
        for vacf in vacfs:
            D.append(integrate.simpson(vacf))
        return D
//  [python]
ops, files = parse_command_line()

#Open the efficiency file and read the three columns into three arrays
amp, eff, Deff = numpy.loadtxt(ops.efficiency_file, dtype="double", unpack=True)

#Open the output file and print the header
outfile = open("gamma.dat", 'w')
outfile.write('%     p           n           epsilon         Gmu       gammaAverage    gammaMin      gammaMax\n')
for i in range(ops.nepsilon):
    epsilon = math.exp(math.log(ops.epsilonstart) + i * (math.log(ops.epsilonend) - math.log(ops.epsilonstart)) / (ops.nepsilon - 1))
    for j in range(ops.nGmu):
        Gmu = math.exp(math.log(ops.Gmustart) + j * (math.log(ops.Gmuend) - math.log(ops.Gmustart)) / (ops.nGmu - 1))
        print >>sys.stderr, "%.1f%%: Gmu=%10.4g, epsilon=%10.4g, p=%4.2g\r" % (100.0 * (i * ops.nGmu + j) / (ops.nepsilon * ops.nGmu), Gmu, epsilon, P),

        alpha = epsilon * (LOOPS_RAD_POWER * Gmu)**ops.index

        zofA = cs_gamma.findzofA(Gmu, alpha, amp) 
        dRdz = cs_gamma.finddRdz(Gmu, alpha, ops.frequency, LOOPS_RAD_POWER, zofA)

        Dlnz = numpy.log(zofA[1:]) - numpy.log(zofA[:-1])

        gammaAverage = scipy.integrate.simps(eff[:-1] * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P
        gammaMin = scipy.integrate.simps(numpy.clip(eff[:-1] - Deff[:-1], 0.0, 1.0) * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P
        gammaMax = scipy.integrate.simps(numpy.clip(eff[:-1] + Deff[:-1], 0.0, 1.0) * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P

        outfile.write("%.17g  %.17g  %.17g  %.17g  %.17g  %.17g  %.17g\n" % (P, ops.index, epsilon, Gmu, gammaAverage, gammaMin, gammaMax))
//  [python]
ops, files = parse_command_line()

#Open the efficiency file and read the three columns into three arrays
amp, eff, Deff = numpy.loadtxt(ops.efficiency_file, dtype="double", unpack=True)

#Open the output file and print the header
outfile = open("gamma.dat", 'w')
outfile.write('%     p           n           epsilon         Gmu       gammaAverage    gammaMin      gammaMax\n')
for i in range(ops.nepsilon):
    epsilon = math.exp(math.log(ops.epsilonstart) + i * (math.log(ops.epsilonend) - math.log(ops.epsilonstart)) / (ops.nepsilon - 1))
    for j in range(ops.nGmu):
        Gmu = math.exp(math.log(ops.Gmustart) + j * (math.log(ops.Gmuend) - math.log(ops.Gmustart)) / (ops.nGmu - 1))
        print >>sys.stderr, "%.1f%%: Gmu=%10.4g, epsilon=%10.4g, p=%4.2g\r" % (100.0 * (i * ops.nGmu + j) / (ops.nepsilon * ops.nGmu), Gmu, epsilon, P),

        alpha = epsilon * (LOOPS_RAD_POWER * Gmu)**ops.index

        zofA = cs_gamma.findzofA(Gmu, alpha, amp) 
        dRdz = cs_gamma.finddRdz(Gmu, alpha, ops.frequency, LOOPS_RAD_POWER, zofA)

        Dlnz = numpy.log(zofA[1:]) - numpy.log(zofA[:-1])

        gammaAverage = scipy.integrate.simpson(eff[:-1] * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P
        gammaMin = scipy.integrate.simpson(numpy.clip(eff[:-1] - Deff[:-1], 0.0, 1.0) * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P
        gammaMax = scipy.integrate.simpson(numpy.clip(eff[:-1] + Deff[:-1], 0.0, 1.0) * zofA[:-1] * dRdz[:-1] * -Dlnz) * CUSPS_PER_LOOP / P

        outfile.write("%.17g  %.17g  %.17g  %.17g  %.17g  %.17g  %.17g\n" % (P, ops.index, epsilon, Gmu, gammaAverage, gammaMin, gammaMax))
//  [python]
def moments(velo,flux,SNR=200.,max_mom=3):
    """
    Compute the moments from a line profile.
    """
    mymoms,e_mymoms = np.zeros(max_mom+1),np.zeros(max_mom+1)

    #-- compute zeroth moment (equivalent width)
    m0 = scipy.integrate.simps( (1-flux),x=velo)

    #-- to calculate the uncertainties, we need the error in each velocity
    #   bin, and the error on the zeroth moment
    sigma_i = 1./SNR / np.sqrt(flux)
    Delta_v0 = np.sqrt(scipy.integrate.simps( sigma_i,x=velo)**2)
    e_m0 = np.sqrt(2)*(Delta_v0/m0)

    mymoms[0] = m0
    e_mymoms[0] = e_m0

    #-- calculate other moments
    for n in range(1,max_mom+1):
        mymoms[n] = scipy.integrate.simps((1-flux)*velo**n,x=velo)/ m0
        #-- and the uncertainty on it
        Delta_vn = np.sqrt(scipy.integrate.simps(sigma_i*velo**n)**2)
        e_mymoms[n] = np.sqrt(  (Delta_vn/m0)**2 + (Delta_v0/m0 * mymoms[n])**2 )

    return mymoms,e_mymoms
//  [python]
def moments(velo,flux,SNR=200.,max_mom=3):
    """
    Compute the moments from a line profile.
    """
    mymoms,e_mymoms = np.zeros(max_mom+1),np.zeros(max_mom+1)

    #-- compute zeroth moment (equivalent width)
    m0 = scipy.integrate.simpson( (1-flux),x=velo)

    #-- to calculate the uncertainties, we need the error in each velocity
    #   bin, and the error on the zeroth moment
    sigma_i = 1./SNR / np.sqrt(flux)
    Delta_v0 = np.sqrt(scipy.integrate.simpson( sigma_i,x=velo)**2)
    e_m0 = np.sqrt(2)*(Delta_v0/m0)

    mymoms[0] = m0
    e_mymoms[0] = e_m0

    #-- calculate other moments
    for n in range(1,max_mom+1):
        mymoms[n] = scipy.integrate.simpson((1-flux)*velo**n,x=velo)/ m0
        #-- and the uncertainty on it
        Delta_vn = np.sqrt(scipy.integrate.simpson(sigma_i*velo**n)**2)
        e_mymoms[n] = np.sqrt(  (Delta_vn/m0)**2 + (Delta_v0/m0 * mymoms[n])**2 )

    return mymoms,e_mymoms
//  [python]
def get_sigma2(self):
        ms = self.ms
        kmin = self.p['sigma2_kmin']
        kmax = self.p['sigma2_kmax']
        numks = self.p['sigma2_numks']
        self.ks_sigma2 = np.geomspace(kmin,kmax,numks) # ks for sigma2 integral
        if self.accurate_sigma2:
            self.sPzk = self.P_lin_slow(self.ks_sigma2,self.zs,kmax=kmax)
        else:
            self.sPzk = self.P_lin(self.ks_sigma2,self.zs)
        ks = self.ks_sigma2[None,None,:]
        R = self.R_of_m(ms)[None,:,None]
        W2 = Wkr(ks,R,self.p['Wkr_taylor_switch'])**2.
        Ps = self.sPzk[:,None,:]
        integrand = Ps*W2*ks**2./2./np.pi**2.
        sigma2 = simps(integrand,ks,axis=-1)
        return sigma2
//  [python]
def get_sigma2(self):
        ms = self.ms
        kmin = self.p['sigma2_kmin']
        kmax = self.p['sigma2_kmax']
        numks = self.p['sigma2_numks']
        self.ks_sigma2 = np.geomspace(kmin,kmax,numks) # ks for sigma2 integral
        if self.accurate_sigma2:
            self.sPzk = self.P_lin_slow(self.ks_sigma2,self.zs,kmax=kmax)
        else:
            self.sPzk = self.P_lin(self.ks_sigma2,self.zs)
        ks = self.ks_sigma2[None,None,:]
        R = self.R_of_m(ms)[None,:,None]
        W2 = Wkr(ks,R,self.p['Wkr_taylor_switch'])**2.
        Ps = self.sPzk[:,None,:]
        integrand = Ps*W2*ks**2./2./np.pi**2.
        sigma2 = simpson(integrand,ks,axis=-1)
        return sigma2
//  [python]
ymin, ymax = (4.0, -16.0)
alphas = np.linspace(ymin, ymax, N)
betas = np.linspace(xmin, xmax, N)

# Integration range.
# The integrand drops to zero so fast this range
# is fine for now.
x = np.linspace(-4.0, 4.0, M)

for i, alpha in enumerate(alphas):
    for j, beta in enumerate(betas):
        # f(z) = z⁴+αz²+β
        # g(z) = exp(if(z))
        # Instead of integrating along x-axis we're
        # going to integrate along a contour displaced
        # vertically from the x-axis.
        # A good choice of displacement is the gradient
        # d/(Im f(x+iy))/dy.
        # That way, we're displacing in a direction that makes
        # |exp(if(x+iy))| smaller.
        y = rate*(4*x**3+2*alpha*x+beta)
        z = x+1j*y

        f = z**4+alpha*z**2+beta*z
        g = np.exp(1j*f)

        # ∫f(z)dz = ∫f(z)(dz/dx)dx
        dz = 1.0+1j*rate*(12*x**2+2*alpha)
        I = integrate.simps(g*dz, x)

        table[i, j] = np.abs(I)
//  [python]
ymin, ymax = (4.0, -16.0)
alphas = np.linspace(ymin, ymax, N)
betas = np.linspace(xmin, xmax, N)

# Integration range.
# The integrand drops to zero so fast this range
# is fine for now.
x = np.linspace(-4.0, 4.0, M)

for i, alpha in enumerate(alphas):
    for j, beta in enumerate(betas):
        # f(z) = z⁴+αz²+β
        # g(z) = exp(if(z))
        # Instead of integrating along x-axis we're
        # going to integrate along a contour displaced
        # vertically from the x-axis.
        # A good choice of displacement is the gradient
        # d/(Im f(x+iy))/dy.
        # That way, we're displacing in a direction that makes
        # |exp(if(x+iy))| smaller.
        y = rate*(4*x**3+2*alpha*x+beta)
        z = x+1j*y

        f = z**4+alpha*z**2+beta*z
        g = np.exp(1j*f)

        # ∫f(z)dz = ∫f(z)(dz/dx)dx
        dz = 1.0+1j*rate*(12*x**2+2*alpha)
        I = integrate.simpson(g*dz, x)

        table[i, j] = np.abs(I)
//  [python]
def multidim_int(f, dx, mode):
    """
    numerical integration over 3-dimensional integrals
    with different Newton-Cotes orders (trapz, simpson ...)
    f: function as numpy array
    dx: grid spacing
    mode: type of integration
    """
    
    I_z = np.zeros((f.shape[0], f.shape[1]))
    for i in range(f.shape[0]):
        for j in range(f.shape[1]):
            if mode == 'trapz':
                I_z[i,j] = np.trapz(f[i,j], dx = dx)
            elif mode == 'simps':
                I_z[i,j] = scipy.integrate.simps(f[i,j], dx = dx)
            else:
                I_z[i,j] = nc_integration(f[i,j], dx, mode)
            
    I_yz = np.zeros(f.shape[0])
    for i in range(f.shape[0]):
        if mode == 'trapz':
            I_yz[i] = np.trapz(I_z[i], dx = dx)
        elif mode == 'simps':
            I_yz[i] = scipy.integrate.simps(I_z[i], dx = dx)
        else:
            I_yz[i] = nc_integration(I_z[i], dx, mode)
    
    if mode == 'trapz':
        I_xyz = np.trapz(I_yz, dx = dx)
    elif mode == 'simps':
        I_xyz = scipy.integrate.simps(I_yz, dx = dx)
    else:
        I_xyz = nc_integration(I_yz, dx, mode)
        
    return(I_xyz)
//  [python]
def multidim_int(f, dx, mode):
    """
    numerical integration over 3-dimensional integrals
    with different Newton-Cotes orders (trapz, simpson ...)
    f: function as numpy array
    dx: grid spacing
    mode: type of integration
    """
    
    I_z = np.zeros((f.shape[0], f.shape[1]))
    for i in range(f.shape[0]):
        for j in range(f.shape[1]):
            if mode == 'trapz':
                I_z[i,j] = np.trapz(f[i,j], dx = dx)
            elif mode == 'simps':
                I_z[i,j] = scipy.integrate.simpson(f[i,j], dx = dx)
            else:
                I_z[i,j] = nc_integration(f[i,j], dx, mode)
            
    I_yz = np.zeros(f.shape[0])
    for i in range(f.shape[0]):
        if mode == 'trapz':
            I_yz[i] = np.trapz(I_z[i], dx = dx)
        elif mode == 'simps':
            I_yz[i] = scipy.integrate.simpson(I_z[i], dx = dx)
        else:
            I_yz[i] = nc_integration(I_z[i], dx, mode)
    
    if mode == 'trapz':
        I_xyz = np.trapz(I_yz, dx = dx)
    elif mode == 'simps':
        I_xyz = scipy.integrate.simpson(I_yz, dx = dx)
    else:
        I_xyz = nc_integration(I_yz, dx, mode)
        
    return(I_xyz)
//  [python]
def exp(x,slope,xlo,xhi,efficiency=None,num_int_points=100,subranges=None):

    xnorm = np.linspace(xlo,xhi,num_int_points)
    ynorm = np.exp(-slope*xnorm)

    if efficiency!=None:
        ynorm *= efficiency(xnorm)

    normalization = integrate.simps(ynorm,x=xnorm)

    # Subranges of the normalization.
    if subranges!=None:
        normalization = 0.0
        for sr in subranges:
            xnorm = np.linspace(sr[0],sr[1],num_int_points)
            ynorm = np.exp(-slope*xnorm)

            if efficiency!=None:
                ynorm *= efficiency(xnorm)

            normalization += integrate.simps(ynorm,x=xnorm)

    y = np.exp(-slope*x)/normalization

    #'''
    if efficiency!=None:
        y *= efficiency(x)
    #'''

    return y
//  [python]
def exp(x,slope,xlo,xhi,efficiency=None,num_int_points=100,subranges=None):

    xnorm = np.linspace(xlo,xhi,num_int_points)
    ynorm = np.exp(-slope*xnorm)

    if efficiency!=None:
        ynorm *= efficiency(xnorm)

    normalization = integrate.simpson(ynorm,x=xnorm)

    # Subranges of the normalization.
    if subranges!=None:
        normalization = 0.0
        for sr in subranges:
            xnorm = np.linspace(sr[0],sr[1],num_int_points)
            ynorm = np.exp(-slope*xnorm)

            if efficiency!=None:
                ynorm *= efficiency(xnorm)

            normalization += integrate.simpson(ynorm,x=xnorm)

    y = np.exp(-slope*x)/normalization

    #'''
    if efficiency!=None:
        y *= efficiency(x)
    #'''

    return y
//  [python]
def cost_funct(self,
                   edge):
        '''
        Computes the line integral per unit pixel length along the posterior curve, or candidate edge, given 
        the image gradient.
        
        We numerically integrate the edge by computing the curvilinear coordinates along the image gradient 
        using euclidean distance and Simpson's rule. This is then normalised by the length of the edge to
        penalise sharp movements.

        INPUTS:
        -------------------
            edge (np.array) : edge indices in xy-space, shape=(N, 2), i.e. 
                new_edge = np.array([[x0, y0],...[xN, yN]])
                
        RETURNS:
        -------------------
            cost (np.float64) : Cost of the edge.
        '''
        # Evaluate edge along interpolated gradient image
        edge = edge[edge[:,0].argsort(), :]
        grad_score = self.grad_interp(edge[:,1], edge[:,0], grid=False)+self.kde_thresh
        #grad_score = self.grad_interp(edge[:,0], edge[:,1])

        # Compute cumulative sum of euclidean distance between pixel indexes of edge.
        # This is the equivalent of computing the curvilinear coordinates of the edge
        pixel_diff = np.cumsum(np.sqrt(np.sum(np.diff(edge, axis=0)**2, axis=1)))

        # Compute integrand of arc length of edge
        pixel_deriv = self.finite_diff(edge[:,1], typ=0, h=1)
        integrand = np.sqrt(1 + pixel_deriv**2)

        # Compute cost = 1 / (line integral / arc length) = arc length / line integral - smaller costs are better 
        line_integral = scipy.integrate.simps(grad_score[:-1], pixel_diff)
        arc_length = scipy.integrate.simps(integrand, edge[:-1,0])
                                    
        # Cost is the line integral per unit pixel length
        cost = arc_length / line_integral 
        
        return cost