Exemplo n.º 1
0
def flux_vs_psi(divergence=numpy.linspace(-50, 50, 1000),
                electronEnergy=2.0,
                r_m=7.6136,
                photon_energy=0.1,
                i_a=0.5):

    codata_mee = 1e-6 * codata.m_e * codata.c**2 / codata.e
    cte = (3.0e0 / 4 / numpy.pi) * codata.h * codata.c * numpy.power(
        1e3 / codata_mee, 3) / codata.e

    ec_ev = cte * numpy.power(electronEnergy, 3) / r_m


    f_1 = sync_ang(1,divergence,polarization=0, \
        e_gev=electronEnergy,i_a=i_a,hdiv_mrad=1.0,r_m=r_m,energy=photon_energy,ec_ev=ec_ev)

    return f_1
Exemplo n.º 2
0
    def generate(self):

        if self.figure_canvas is not None:
            self.mainArea.layout().removeWidget(self.figure_canvas)

        #
        # Calculating the critical energy in eV following Green pag.3.
        #
        gamma = self.ELECTRON_ENERGY * 1e3 / codata_mee  # the electron energy is given in GeV.
        critical_wavelength = 4.0 * np.pi * self.MAGNETIC_RADIUS / 3.0 / np.power(
            gamma, 3)  # wavelength in m.
        ec_ev = m2ev / critical_wavelength  # critical energy in eV.

        #
        # Constructing the angle and energy grids.
        #
        if self.ENERGY_POINTS == 1:
            # monochromatic bunch.
            ENERGY_MIN = ENERGY_MAX = self.ENERGY

        else:
            ENERGY_MIN = self.ENERGY_MIN
            ENERGY_MAX = self.ENERGY_MAX

        energies = np.linspace(start=ENERGY_MIN,
                               stop=ENERGY_MAX,
                               num=self.ENERGY_POINTS)

        if self.ANGLE_DEVIATION_POINTS == 1:
            # unidirectional bunch.
            ANGLE_DEVIATION_MIN = ANGLE_DEVIATION_MAX = self.ANGLE_DEVIATION * 1e-6  # urad --> rad

        else:
            ANGLE_DEVIATION_MIN = self.ANGLE_DEVIATION_MIN * 1e-6  # urad --> rad
            ANGLE_DEVIATION_MAX = self.ANGLE_DEVIATION_MAX * 1e-6  # urad --> rad

        deviations = np.linspace(start=ANGLE_DEVIATION_MIN,
                                 stop=ANGLE_DEVIATION_MAX,
                                 num=self.ANGLE_DEVIATION_POINTS)

        sync_ang_deviations = np.multiply(
            deviations,
            1e3)  # sync_ang takes as an input angles in mrad, not urad.
        photon_bunch = PolarizedPhotonBunch([])

        for energy in energies:

            photon_bunch_to_add = stokes_calculator(energy,
                                                    sync_ang_deviations,
                                                    self.ELECTRON_ENERGY,
                                                    self.ELECTRON_CURRENT,
                                                    self.HORIZONTAL_DIVERGENCE,
                                                    float(ec_ev))
            photon_bunch.addBunch(photon_bunch_to_add)

        #
        # Dump data to file if requested.
        #
        if self.DUMP_TO_FILE:

            print("BendingMagnet: Writing data in {file}...\n".format(
                file=self.FILE_NAME))

            with open(self.FILE_NAME, "w") as file:
                try:
                    file.write("#S 1 photon bunch\n"
                               "#N 9\n"
                               "#L  Energy [eV]  Vx  Vy  Vz  S0  S1  S2  S3\n")
                    file.write(photon_bunch.toString())
                    file.close()
                    print("File written to disk: %s" % self.FILE_NAME)
                except:
                    raise Exception(
                        "BendingMagnet: The data could not be dumped onto the specified file!\n"
                    )

        #
        # Plotting the emission profiles according to user input if requested.
        #
        if self.VIEW_EMISSION_PROFILE == 1:

            self.fig.clf()  # clear the current Figure.
            self.figure_canvas.draw()

        elif self.VIEW_EMISSION_PROFILE == 0:

            self.fig.clf()  # clear the current Figure.
            ax = self.fig.add_subplot(111)

            toptitle = "Bending Magnet angular emission"
            xtitle = "Psi[mrad]"
            ytitle = "Power density[Watts/mrad]"

            if self.ENERGY_POINTS == 1:
                flux = sync_ang(1,
                                sync_ang_deviations,
                                polarization=0,
                                e_gev=self.ELECTRON_ENERGY,
                                i_a=self.ELECTRON_CURRENT,
                                hdiv_mrad=1.0,
                                energy=self.ENERGY,
                                ec_ev=ec_ev)

                ax.plot(sync_ang_deviations,
                        flux,
                        'g',
                        label="E={} keV".format(self.ENERGY * 1e-3))

            else:
                flux_Emin = sync_ang(
                    1,
                    sync_ang_deviations,
                    polarization=0,  # energy = lower limit.
                    e_gev=self.ELECTRON_ENERGY,
                    i_a=self.ELECTRON_CURRENT,
                    hdiv_mrad=1.0,
                    energy=self.ENERGY_MIN,
                    ec_ev=ec_ev)

                flux_Emax = sync_ang(
                    1,
                    sync_ang_deviations,
                    polarization=0,  # energy = upper limit.
                    e_gev=self.ELECTRON_ENERGY,
                    i_a=self.ELECTRON_CURRENT,
                    hdiv_mrad=1.0,
                    energy=self.ENERGY_MAX,
                    ec_ev=ec_ev)

                ax.plot(sync_ang_deviations,
                        flux_Emin,
                        'r',
                        label="E min={} keV".format(self.ENERGY_MIN * 1e-3))
                ax.plot(sync_ang_deviations,
                        flux_Emax,
                        'b',
                        label="E max={} keV".format(self.ENERGY_MAX * 1e-3))

            ax.set_title(toptitle)
            ax.set_xlabel(xtitle)
            ax.set_ylabel(ytitle)
            ax.set_xlim(sync_ang_deviations.min(), sync_ang_deviations.max())
            ax.legend(bbox_to_anchor=(1.1, 1.05))

            self.figure_canvas.draw()

            print("BendingMagnet: Photon bunch generated.\n")
            self.send("photon bunch", photon_bunch)
Exemplo n.º 3
0
def xoppy_calc_bm(MACHINE_NAME="ESRF bending magnet",RB_CHOICE=0,MACHINE_R_M=25.0,BFIELD_T=0.8,\
                  BEAM_ENERGY_GEV=6.04,CURRENT_A=0.1,HOR_DIV_MRAD=1.0,VER_DIV=0,\
                  PHOT_ENERGY_MIN=100.0,PHOT_ENERGY_MAX=100000.0,NPOINTS=500,LOG_CHOICE=1,\
                  PSI_MRAD_PLOT=1.0,PSI_MIN=-1.0,PSI_MAX=1.0,PSI_NPOINTS=500,TYPE_CALC=0,FILE_DUMP=0):
    print("Inside xoppy_calc_bm. ")

    # electron energy in GeV
    gamma = BEAM_ENERGY_GEV*1e3 / srfunc.codata_mee

    r_m = MACHINE_R_M      # magnetic radius in m
    if RB_CHOICE == 1:
        r_m = srfunc.codata_me * srfunc.codata_c / srfunc.codata_ec / BFIELD_T * numpy.sqrt(gamma * gamma - 1)

    # calculate critical energy in eV
    ec_m = 4.0*numpy.pi*r_m/3.0/numpy.power(gamma,3) # wavelength in m
    ec_ev = srfunc.m2ev / ec_m

    fm = None
    a = None
    energy_ev = None

    if TYPE_CALC == 0:
        if LOG_CHOICE == 0:
            energy_ev = numpy.linspace(PHOT_ENERGY_MIN,PHOT_ENERGY_MAX,NPOINTS) # photon energy grid
        else:
            energy_ev = numpy.logspace(numpy.log10(PHOT_ENERGY_MIN),numpy.log10(PHOT_ENERGY_MAX),NPOINTS) # photon energy grid

        a5 = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=0, \
                             e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                             psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a5par = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=1, \
                                e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                                psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a5per = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=2, \
                                e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                                psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        if VER_DIV == 0:
            coltitles=['Photon Energy [eV]','Photon Wavelength [A]','E/Ec','Flux_spol/Flux_total','Flux_ppol/Flux_total','Flux[Phot/sec/0.1%bw]','Power[Watts/eV]']
            title='integrated in Psi,'
        if VER_DIV == 1:
            coltitles=['Photon Energy [eV]','Photon Wavelength [A]','E/Ec','Flux_spol/Flux_total','Flux_ppol/Flux_total','Flux[Phot/sec/0.1%bw/mrad(Psi)]','Power[Watts/eV/mrad(Psi)]']
            title='at Psi=0,'
        if VER_DIV == 2:
            coltitles=['Photon Energy [eV]','Photon Wavelength [A]','E/Ec','Flux_spol/Flux_total','Flux_ppol/Flux_total','Flux[Phot/sec/0.1%bw]','Power[Watts/eV]']
            title='in Psi=[%e,%e]'%(PSI_MIN,PSI_MAX)
        if VER_DIV == 3:
            coltitles=['Photon Energy [eV]','Photon Wavelength [A]','E/Ec','Flux_spol/Flux_total','Flux_ppol/Flux_total','Flux[Phot/sec/0.1%bw/mrad(Psi)]','Power[Watts/eV/mrad(Psi)]']
            title='at Psi=%e mrad'%(PSI_MIN)

        a6=numpy.zeros((7,len(energy_ev)))
        a1 = energy_ev
        a6[0,:] = (a1)
        a6[1,:] = srfunc.m2ev * 1e10 / (a1)
        a6[2,:] = (a1)/ec_ev # E/Ec
        a6[3,:] = numpy.array(a5par)/numpy.array(a5)
        a6[4,:] = numpy.array(a5per)/numpy.array(a5)
        a6[5,:] = numpy.array(a5)
        a6[6,:] = numpy.array(a5)*1e3 * srfunc.codata_ec

    if TYPE_CALC == 1:  # angular distributions over over all energies
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,NPOINTS) # angle grid

        a6 = numpy.zeros((6,NPOINTS))
        a6[0,:] = angle_mrad # angle in mrad
        a6[1,:] = angle_mrad*gamma/1e3 # Psi[rad]*Gamma
        a6[2,:] = srfunc.sync_f(angle_mrad * gamma / 1e3)
        a6[3,:] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=1)
        a6[4,:] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=2)
        a6[5,:] = srfunc.sync_ang(0, angle_mrad, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, e_gev=BEAM_ENERGY_GEV, r_m=r_m)

        coltitles=['Psi[mrad]','Psi[rad]*Gamma','F','F s-pol','F p-pol','Power[Watts/mrad(Psi)]']

    if TYPE_CALC == 2:  # angular distributions at a single energy
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,NPOINTS) # angle grid

        a6 = numpy.zeros((7,NPOINTS))
        a6[0,:] = angle_mrad # angle in mrad
        a6[1,:] = angle_mrad*gamma/1e3 # Psi[rad]*Gamma
        a6[2,:] = srfunc.sync_f(angle_mrad * gamma / 1e3)
        a6[3,:] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=1)
        a6[4,:] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=2)
        tmp = srfunc.sync_ang(1, angle_mrad, energy=PHOT_ENERGY_MIN, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, e_gev=BEAM_ENERGY_GEV, ec_ev=ec_ev)
        tmp.shape = -1
        a6[5,:] = tmp
        a6[6,:] = a6[5,:] * srfunc.codata_ec * 1e3

        coltitles=['Psi[mrad]','Psi[rad]*Gamma','F','F s-pol','F p-pol','Flux[Ph/sec/0.1%bw/mrad(Psi)]','Power[Watts/eV/mrad(Psi)]']

    if TYPE_CALC == 3:  # angular,energy distributions flux
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,NPOINTS) # angle grid

        if LOG_CHOICE == 0:
            energy_ev = numpy.linspace(PHOT_ENERGY_MIN,PHOT_ENERGY_MAX,NPOINTS) # photon energy grid
        else:
            energy_ev = numpy.logspace(numpy.log10(PHOT_ENERGY_MIN),numpy.log10(PHOT_ENERGY_MAX),NPOINTS) # photon energy grid

        # fm[angle,energy]
        fm = srfunc.sync_ene(4, energy_ev, ec_ev=ec_ev, e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, \
                                      hdiv_mrad=HOR_DIV_MRAD, psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a = numpy.linspace(PSI_MIN,PSI_MAX,PSI_NPOINTS)

        a6 = numpy.zeros((4,len(a)*len(energy_ev)))
        ij = -1
        for i in range(len(a)):
            for j in range(len(energy_ev)):
                ij += 1
                a6[0,ij] = a[i]
                a6[1,ij] = energy_ev[j]
                a6[2,ij] = fm[i,j] * srfunc.codata_ec * 1e3
                a6[3,ij] = fm[i,j]

        coltitles=['Psi [mrad]','Photon Energy [eV]','Power [Watts/eV/mrad(Psi)]','Flux [Ph/sec/0.1%bw/mrad(Psi)]']

    # write spec file
    ncol = len(coltitles)
    npoints = len(a6[0,:])

    if FILE_DUMP == 1:
        outFile = "bm.spec"
        f = open(outFile,"w")
        f.write("#F "+outFile+"\n")
        f.write("\n")
        f.write("#S 1 bm results\n")
        f.write("#N %d\n"%(ncol))
        f.write("#L")
        for i in range(ncol):
            f.write("  "+coltitles[i])
        f.write("\n")

        for i in range(npoints):
                f.write((" %e "*ncol+"\n")%(tuple(a6[:,i].tolist())))
        f.close()
        print("File written to disk: " + outFile)

    return a6.T, fm, a, energy_ev
Exemplo n.º 4
0
def xoppy_calc_wiggler_radiation(
    ELECTRONENERGY=3.0,
    ELECTRONCURRENT=0.1,
    PERIODID=0.120,
    NPERIODS=37.0,
    KV=22.416,
    DISTANCE=30.0,
    HSLITPOINTS=500,
    VSLITPOINTS=500,
    PHOTONENERGYMIN=100.0,
    PHOTONENERGYMAX=100100.0,
    PHOTONENERGYPOINTS=101,
    NTRAJPOINTS=1001,
    FIELD=0,
    FILE="/Users/srio/Oasys/Bsin.txt",
    POLARIZATION=0,  # 0=total, 1=parallel (s), 2=perpendicular (p)
    SHIFT_X_FLAG=0,
    SHIFT_X_VALUE=0.0,
    SHIFT_BETAX_FLAG=0,
    SHIFT_BETAX_VALUE=0.0,
    CONVOLUTION=1,
    PASSEPARTOUT=3.0,
    h5_file="wiggler_radiation.h5",
    h5_entry_name="XOPPY_RADIATION",
    h5_initialize=True,
    h5_parameters=None,
    do_plot=False,
):

    # calculate wiggler trajectory
    if FIELD == 0:
        (traj, pars) = srfunc.wiggler_trajectory(
            b_from=0,
            inData="",
            nPer=int(NPERIODS),  #37,
            nTrajPoints=NTRAJPOINTS,
            ener_gev=ELECTRONENERGY,
            per=PERIODID,
            kValue=KV,
            trajFile="",
            shift_x_flag=SHIFT_X_FLAG,
            shift_x_value=SHIFT_X_VALUE,
            shift_betax_flag=SHIFT_BETAX_FLAG,
            shift_betax_value=SHIFT_BETAX_VALUE)
    if FIELD == 1:
        # magnetic field from B(s) map
        (traj,
         pars) = srfunc.wiggler_trajectory(b_from=1,
                                           nPer=1,
                                           nTrajPoints=NTRAJPOINTS,
                                           ener_gev=ELECTRONENERGY,
                                           inData=FILE,
                                           trajFile="",
                                           shift_x_flag=SHIFT_X_FLAG,
                                           shift_x_value=SHIFT_X_VALUE,
                                           shift_betax_flag=SHIFT_BETAX_FLAG,
                                           shift_betax_value=SHIFT_BETAX_FLAG)
    if FIELD == 2:
        raise ("Not implemented")

    energy, flux, power = srfunc.wiggler_spectrum(
        traj,
        enerMin=PHOTONENERGYMIN,
        enerMax=PHOTONENERGYMAX,
        nPoints=PHOTONENERGYPOINTS,
        electronCurrent=ELECTRONCURRENT,
        outFile="",
        elliptical=False,
        polarization=POLARIZATION)

    try:
        cumulated_power = power.cumsum() * numpy.abs(energy[0] - energy[1])
    except:
        cumulated_power = 0.0
    print("\nPower from integral of spectrum (sum rule): %8.3f W" %
          (cumulated_power[-1]))

    try:
        cumulated_power = cumtrapz(power, energy, initial=0)
    except:
        cumulated_power = 0.0
    print("Power from integral of spectrum (trapezoid rule): %8.3f W" %
          (cumulated_power[-1]))

    codata_mee = 1e-6 * codata.m_e * codata.c**2 / codata.e  # electron mass in meV
    gamma = ELECTRONENERGY * 1e3 / codata_mee

    Y = traj[1, :].copy()
    divX = traj[3, :].copy()
    By = traj[7, :].copy()

    # rho = (1e9 / codata.c) * ELECTRONENERGY / By
    # Ec0 = 3 * codata.h * codata.c * gamma**3 / (4 * numpy.pi * rho) / codata.e
    # Ec = 665.0 * ELECTRONENERGY**2 * numpy.abs(By)
    # Ecmax = 665.0 * ELECTRONENERGY** 2 * (numpy.abs(By)).max()
    coeff = 3 / (
        4 *
        numpy.pi) * codata.h * codata.c**2 / codata_mee**3 / codata.e  # ~665.0
    Ec = coeff * ELECTRONENERGY**2 * numpy.abs(By)
    Ecmax = coeff * ELECTRONENERGY**2 * (numpy.abs(By)).max()

    # approx formula for divergence (first formula in pag 43 of Tanaka's paper)
    sigmaBp = 0.597 / gamma * numpy.sqrt(Ecmax / PHOTONENERGYMIN)

    # we use vertical interval 6*sigmaBp and horizontal interval = vertical + trajectory interval

    divXX = numpy.linspace(divX.min() - PASSEPARTOUT * sigmaBp,
                           divX.max() + PASSEPARTOUT * sigmaBp, HSLITPOINTS)

    divZZ = numpy.linspace(-PASSEPARTOUT * sigmaBp, PASSEPARTOUT * sigmaBp,
                           VSLITPOINTS)

    e = numpy.linspace(PHOTONENERGYMIN, PHOTONENERGYMAX, PHOTONENERGYPOINTS)

    p = numpy.zeros((PHOTONENERGYPOINTS, HSLITPOINTS, VSLITPOINTS))

    for i in range(e.size):
        Ephoton = e[i]

        # vertical divergence
        intensity = srfunc.sync_g1(Ephoton / Ec, polarization=POLARIZATION)

        Ecmean = (Ec * intensity).sum() / intensity.sum()

        fluxDivZZ = srfunc.sync_ang(1,
                                    divZZ * 1e3,
                                    polarization=POLARIZATION,
                                    e_gev=ELECTRONENERGY,
                                    i_a=ELECTRONCURRENT,
                                    hdiv_mrad=1.0,
                                    energy=Ephoton,
                                    ec_ev=Ecmean)

        if do_plot:
            from srxraylib.plot.gol import plot
            plot(divZZ,
                 fluxDivZZ,
                 title="min intensity %f" % fluxDivZZ.min(),
                 xtitle="divZ",
                 ytitle="fluxDivZZ",
                 show=1)

        # horizontal divergence after Tanaka
        if False:
            e_over_ec = Ephoton / Ecmax
            uudlim = 1.0 / gamma
            uud = numpy.linspace(-uudlim * 0.99, uudlim * 0.99, divX.size)
            uu = e_over_ec / numpy.sqrt(1 - gamma**2 * uud**2)
            plot(uud, 2 * numpy.pi / numpy.sqrt(3) * srfunc.sync_g1(uu))

        # horizontal divergence
        # intensity = srfunc.sync_g1(Ephoton / Ec, polarization=POLARIZATION)
        intensity_interpolated = interpolate_multivalued_function(
            divX,
            intensity,
            divXX,
            Y,
        )

        if CONVOLUTION:  # do always convolution!
            intensity_interpolated.shape = -1
            divXX_window = divXX[-1] - divXX[0]
            divXXCC = numpy.linspace(-0.5 * divXX_window, 0.5 * divXX_window,
                                     divXX.size)
            fluxDivZZCC = srfunc.sync_ang(1,
                                          divXXCC * 1e3,
                                          polarization=POLARIZATION,
                                          e_gev=ELECTRONENERGY,
                                          i_a=ELECTRONCURRENT,
                                          hdiv_mrad=1.0,
                                          energy=Ephoton,
                                          ec_ev=Ecmax)
            fluxDivZZCC.shape = -1

            intensity_convolved = numpy.convolve(
                intensity_interpolated / intensity_interpolated.max(),
                fluxDivZZCC / fluxDivZZCC.max(),
                mode='same')
        else:
            intensity_convolved = intensity_interpolated

        if i == 0:
            print(
                "\n\n============ sizes vs photon energy ======================="
            )
            print(
                "Photon energy/eV  FWHM X'/urad  FWHM Y'/urad  FWHM X/mm  FWHM Z/mm "
            )

        print("%16.3f  %12.3f  %12.3f  %9.2f  %9.2f" %
              (Ephoton, 1e6 * get_fwhm(intensity_convolved, divXX)[0],
               1e6 * get_fwhm(fluxDivZZ, divZZ)[0],
               1e3 * get_fwhm(intensity_convolved, divXX)[0] * DISTANCE,
               1e3 * get_fwhm(fluxDivZZ, divZZ)[0] * DISTANCE))

        if do_plot:
            plot(divX,
                 intensity / intensity.max(),
                 divXX,
                 intensity_interpolated / intensity_interpolated.max(),
                 divXX,
                 intensity_convolved / intensity_convolved.max(),
                 divXX,
                 fluxDivZZCC / fluxDivZZCC.max(),
                 title="min intensity %f, Ephoton=%6.2f" %
                 (intensity.min(), Ephoton),
                 xtitle="divX",
                 ytitle="intensity",
                 legend=["orig", "interpolated", "convolved", "kernel"],
                 show=1)

        # combine H * V
        INTENSITY = numpy.outer(
            intensity_convolved / intensity_convolved.max(),
            fluxDivZZ / fluxDivZZ.max())
        p[i, :, :] = INTENSITY

        if do_plot:
            from srxraylib.plot.gol import plot_image, plot_surface, plot_show
            plot_image(INTENSITY,
                       divXX,
                       divZZ,
                       aspect='auto',
                       title="E=%6.2f" % Ephoton,
                       show=1)
            # to create oasys icon...
            # plot_surface(INTENSITY, divXX, divZZ, title="", show=0)
            # import matplotlib.pylab as plt
            # plt.xticks([])
            # plt.yticks([])
            # plt.axis('off')
            # plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off',
            #                 labeltop='off', labelright='off', labelbottom='off')
            #
            # plot_show()
    #

    h = divXX * DISTANCE * 1e3  # in mm for the h5 file
    v = divZZ * DISTANCE * 1e3  # in mm for the h5 file

    print("\nWindow size: %f mm [H] x %f mm [V]" %
          (h[-1] - h[0], v[-1] - v[0]))
    print("Window size: %g rad [H] x %g rad [V]" %
          (divXX[-1] - divXX[0], divZZ[-1] - divZZ[0]))

    # normalization and total flux
    for i in range(e.size):
        INTENSITY = p[i, :, :]
        # norm = INTENSITY.sum() * (h[1] - h[0]) * (v[1] - v[0])
        norm = trapezoidal_rule_2d_1darrays(INTENSITY, h, v)
        p[i, :, :] = INTENSITY / norm * flux[i]

    # fit
    fit_ok = False
    try:
        power = p.sum(axis=0) * (e[1] - e[0]) * codata.e * 1e3
        print(
            "\n\n============= Fitting power density to a 2D Gaussian. ==============\n"
        )
        print(
            "Please use these results with care: check if the original data looks like a Gaussian."
        )
        fit_parameters = fit_gaussian2d(power, h, v)
        print(info_params(fit_parameters))
        H, V = numpy.meshgrid(h, v)
        data_fitted = twoD_Gaussian((H, V), *fit_parameters)
        print("  Total power (sum rule) in the fitted data [W]: ",
              data_fitted.sum() * (h[1] - h[0]) * (v[1] - v[0]))
        # plot_image(data_fitted.reshape((h.size,v.size)),h, v,title="FIT")
        print("====================================================\n")
        fit_ok = True
    except:
        pass

    # output file
    if h5_file != "":
        try:
            if h5_initialize:
                h5w = H5SimpleWriter.initialize_file(
                    h5_file, creator="xoppy_wigglers.py")
            else:
                h5w = H5SimpleWriter(h5_file, None)
            h5w.create_entry(h5_entry_name, nx_default=None)
            h5w.add_stack(e,
                          h,
                          v,
                          p,
                          stack_name="Radiation",
                          entry_name=h5_entry_name,
                          title_0="Photon energy [eV]",
                          title_1="X gap [mm]",
                          title_2="Y gap [mm]")
            h5w.create_entry("parameters",
                             root_entry=h5_entry_name,
                             nx_default=None)
            if h5_parameters is not None:
                for key in h5_parameters.keys():
                    h5w.add_key(key,
                                h5_parameters[key],
                                entry_name=h5_entry_name + "/parameters")
            h5w.create_entry("trajectory",
                             root_entry=h5_entry_name,
                             nx_default="transversal trajectory")
            h5w.add_key("traj", traj, entry_name=h5_entry_name + "/trajectory")
            h5w.add_dataset(traj[1, :],
                            traj[0, :],
                            dataset_name="transversal trajectory",
                            entry_name=h5_entry_name + "/trajectory",
                            title_x="s [m]",
                            title_y="X [m]")
            h5w.add_dataset(traj[1, :],
                            traj[3, :],
                            dataset_name="transversal velocity",
                            entry_name=h5_entry_name + "/trajectory",
                            title_x="s [m]",
                            title_y="Vx/c")
            h5w.add_dataset(traj[1, :],
                            traj[7, :],
                            dataset_name="Magnetic field",
                            entry_name=h5_entry_name + "/trajectory",
                            title_x="s [m]",
                            title_y="Bz [T]")
            if fit_ok:
                h5w.add_image(power,
                              h,
                              v,
                              image_name="PowerDensity",
                              entry_name=h5_entry_name,
                              title_x="X [mm]",
                              title_y="Y [mm]")

                h5w.add_image(data_fitted.reshape(h.size, v.size),
                              h,
                              v,
                              image_name="PowerDensityFit",
                              entry_name=h5_entry_name,
                              title_x="X [mm]",
                              title_y="Y [mm]")
                h5w.add_key("fit_info",
                            info_params(fit_parameters),
                            entry_name=h5_entry_name + "/PowerDensityFit")
            print("File written to disk: %s" % h5_file)
        except:
            print("ERROR initializing h5 file")

    return e, h, v, p, traj
Exemplo n.º 5
0
def xoppy_calc_bm(MACHINE_NAME="ESRF bending magnet",RB_CHOICE=0,MACHINE_R_M=25.0,BFIELD_T=0.8,\
                  BEAM_ENERGY_GEV=6.04,CURRENT_A=0.1,HOR_DIV_MRAD=1.0,VER_DIV=0,\
                  PHOT_ENERGY_MIN=100.0,PHOT_ENERGY_MAX=100000.0,NPOINTS=500,LOG_CHOICE=1,\
                  PSI_MRAD_PLOT=1.0,PSI_MIN=-1.0,PSI_MAX=1.0,PSI_NPOINTS=500,TYPE_CALC=0,FILE_DUMP=0):

    # electron energy in GeV
    gamma = BEAM_ENERGY_GEV * 1e3 / srfunc.codata_mee

    r_m = MACHINE_R_M  # magnetic radius in m
    if RB_CHOICE == 1:
        r_m = srfunc.codata_me * srfunc.codata_c / srfunc.codata_ec / BFIELD_T * numpy.sqrt(
            gamma * gamma - 1)

    # calculate critical energy in eV
    ec_m = 4.0 * numpy.pi * r_m / 3.0 / numpy.power(gamma,
                                                    3)  # wavelength in m
    ec_ev = srfunc.m2ev / ec_m

    fm = None
    a = None
    energy_ev = None

    if TYPE_CALC == 0:
        if LOG_CHOICE == 0:
            energy_ev = numpy.linspace(PHOT_ENERGY_MIN, PHOT_ENERGY_MAX,
                                       NPOINTS)  # photon energy grid
        else:
            energy_ev = numpy.logspace(numpy.log10(PHOT_ENERGY_MIN),
                                       numpy.log10(PHOT_ENERGY_MAX),
                                       NPOINTS)  # photon energy grid

        a5 = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=0, \
                             e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                             psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a5par = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=1, \
                                e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                                psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a5per = srfunc.sync_ene(VER_DIV, energy_ev, ec_ev=ec_ev, polarization=2, \
                                e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, hdiv_mrad=HOR_DIV_MRAD, \
                                psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        if VER_DIV == 0:
            coltitles = [
                'Photon Energy [eV]', 'Photon Wavelength [A]', 'E/Ec',
                'Flux_spol/Flux_total', 'Flux_ppol/Flux_total',
                'Flux[Phot/sec/0.1%bw]', 'Power[Watts/eV]'
            ]
            title = 'integrated in Psi,'
        if VER_DIV == 1:
            coltitles = [
                'Photon Energy [eV]', 'Photon Wavelength [A]', 'E/Ec',
                'Flux_spol/Flux_total', 'Flux_ppol/Flux_total',
                'Flux[Phot/sec/0.1%bw/mrad(Psi)]', 'Power[Watts/eV/mrad(Psi)]'
            ]
            title = 'at Psi=0,'
        if VER_DIV == 2:
            coltitles = [
                'Photon Energy [eV]', 'Photon Wavelength [A]', 'E/Ec',
                'Flux_spol/Flux_total', 'Flux_ppol/Flux_total',
                'Flux[Phot/sec/0.1%bw]', 'Power[Watts/eV]'
            ]
            title = 'in Psi=[%e,%e]' % (PSI_MIN, PSI_MAX)
        if VER_DIV == 3:
            coltitles = [
                'Photon Energy [eV]', 'Photon Wavelength [A]', 'E/Ec',
                'Flux_spol/Flux_total', 'Flux_ppol/Flux_total',
                'Flux[Phot/sec/0.1%bw/mrad(Psi)]', 'Power[Watts/eV/mrad(Psi)]'
            ]
            title = 'at Psi=%e mrad' % (PSI_MIN)

        a6 = numpy.zeros((7, len(energy_ev)))
        a1 = energy_ev
        a6[0, :] = (a1)
        a6[1, :] = srfunc.m2ev * 1e10 / (a1)
        a6[2, :] = (a1) / ec_ev  # E/Ec
        a6[3, :] = numpy.array(a5par) / numpy.array(a5)
        a6[4, :] = numpy.array(a5per) / numpy.array(a5)
        a6[5, :] = numpy.array(a5)
        a6[6, :] = numpy.array(a5) * 1e3 * srfunc.codata_ec

    if TYPE_CALC == 1:  # angular distributions over over all energies
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,
                                    NPOINTS)  # angle grid

        a6 = numpy.zeros((6, NPOINTS))
        a6[0, :] = angle_mrad  # angle in mrad
        a6[1, :] = angle_mrad * gamma / 1e3  # Psi[rad]*Gamma
        a6[2, :] = srfunc.sync_f(angle_mrad * gamma / 1e3)
        a6[3, :] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=1)
        a6[4, :] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=2)
        a6[5, :] = srfunc.sync_ang(0,
                                   angle_mrad,
                                   i_a=CURRENT_A,
                                   hdiv_mrad=HOR_DIV_MRAD,
                                   e_gev=BEAM_ENERGY_GEV,
                                   r_m=r_m)

        coltitles = [
            'Psi[mrad]', 'Psi[rad]*Gamma', 'F', 'F s-pol', 'F p-pol',
            'Power[Watts/mrad(Psi)]'
        ]

    if TYPE_CALC == 2:  # angular distributions at a single energy
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,
                                    NPOINTS)  # angle grid

        a6 = numpy.zeros((7, NPOINTS))
        a6[0, :] = angle_mrad  # angle in mrad
        a6[1, :] = angle_mrad * gamma / 1e3  # Psi[rad]*Gamma
        a6[2, :] = srfunc.sync_f(angle_mrad * gamma / 1e3)
        a6[3, :] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=1)
        a6[4, :] = srfunc.sync_f(angle_mrad * gamma / 1e3, polarization=2)
        tmp = srfunc.sync_ang(1,
                              angle_mrad,
                              energy=PHOT_ENERGY_MIN,
                              i_a=CURRENT_A,
                              hdiv_mrad=HOR_DIV_MRAD,
                              e_gev=BEAM_ENERGY_GEV,
                              ec_ev=ec_ev)
        tmp.shape = -1
        a6[5, :] = tmp
        a6[6, :] = a6[5, :] * srfunc.codata_ec * 1e3

        coltitles = [
            'Psi[mrad]', 'Psi[rad]*Gamma', 'F', 'F s-pol', 'F p-pol',
            'Flux[Ph/sec/0.1%bw/mrad(Psi)]', 'Power[Watts/eV/mrad(Psi)]'
        ]

    if TYPE_CALC == 3:  # angular,energy distributions flux
        angle_mrad = numpy.linspace(-PSI_MRAD_PLOT, +PSI_MRAD_PLOT,
                                    NPOINTS)  # angle grid

        if LOG_CHOICE == 0:
            energy_ev = numpy.linspace(PHOT_ENERGY_MIN, PHOT_ENERGY_MAX,
                                       NPOINTS)  # photon energy grid
        else:
            energy_ev = numpy.logspace(numpy.log10(PHOT_ENERGY_MIN),
                                       numpy.log10(PHOT_ENERGY_MAX),
                                       NPOINTS)  # photon energy grid

        # fm[angle,energy]
        fm = srfunc.sync_ene(4, energy_ev, ec_ev=ec_ev, e_gev=BEAM_ENERGY_GEV, i_a=CURRENT_A, \
                                      hdiv_mrad=HOR_DIV_MRAD, psi_min=PSI_MIN, psi_max=PSI_MAX, psi_npoints=PSI_NPOINTS)

        a = numpy.linspace(PSI_MIN, PSI_MAX, PSI_NPOINTS)

        a6 = numpy.zeros((4, len(a) * len(energy_ev)))
        ij = -1
        for i in range(len(a)):
            for j in range(len(energy_ev)):
                ij += 1
                a6[0, ij] = a[i]
                a6[1, ij] = energy_ev[j]
                a6[2, ij] = fm[i, j] * srfunc.codata_ec * 1e3
                a6[3, ij] = fm[i, j]

        coltitles = [
            'Psi [mrad]', 'Photon Energy [eV]', 'Power [Watts/eV/mrad(Psi)]',
            'Flux [Ph/sec/0.1%bw/mrad(Psi)]'
        ]

    # write spec file
    ncol = len(coltitles)
    npoints = len(a6[0, :])

    if FILE_DUMP:
        outFile = "bm.spec"
        f = open(outFile, "w")
        f.write("#F " + outFile + "\n")
        f.write("\n")
        f.write("#S 1 bm results\n")
        f.write("#N %d\n" % (ncol))
        f.write("#L")
        for i in range(ncol):
            f.write("  " + coltitles[i])
        f.write("\n")

        for i in range(npoints):
            f.write((" %e " * ncol + "\n") % (tuple(a6[:, i].tolist())))
        f.close()
        print("File written to disk: " + outFile)

    if TYPE_CALC == 0:
        if LOG_CHOICE == 0:
            print("\nPower from integral of spectrum: %15.3f W" %
                  (a5.sum() * 1e3 * srfunc.codata_ec *
                   (energy_ev[1] - energy_ev[0])))

    return a6.T, fm, a, energy_ev
Exemplo n.º 6
0
    def __calculate_rays(self,
                         F_COHER=0, NRAYS=5000, SEED=123456,
                         EPSI_DX=0.0, EPSI_DZ=0.0,
                         psi_interval_in_units_one_over_gamma=None,
                         psi_interval_number_of_points=1001,
                         verbose=False):
        """
        compute the rays in SHADOW matrix (shape (npoints,18) )
        :param F_COHER: set this flag for coherent beam
        :param user_unit_to_m: default 1.0 (m)
        :return: rays, a numpy.array((npoits,18))
        """

        if SEED != 0:
            numpy.random.seed(SEED)

        rays = numpy.zeros((NRAYS,18))

        #RAD_MIN= numpy.abs(self.get_magnetic_structure().radius())
        #RAD_MAX= numpy.abs(self.get_magnetic_structure().radius())

        # r_aladdin	=  bending magnet radius in units of length used for source size, CCW rings negative.
        r_aladdin = self.get_magnetic_structure().radius()

        if r_aladdin < 0:
            POL_ANGLE = -90.0 * numpy.pi / 2
        else:
            POL_ANGLE = 90.0 * numpy.pi / 2

        HDIV1 = 0.5 * self.get_magnetic_structure().horizontal_divergence()
        HDIV2 = HDIV1

        gamma = self.get_electron_beam().gamma()
        critical_energy = self.get_magnetic_structure().get_critical_energy(self.get_electron_beam().energy())

        if psi_interval_in_units_one_over_gamma is None:
            c = numpy.array([-0.3600382, 0.11188709])  # see file fit_psi_interval.py
            x = numpy.log10(self.get_magnetic_structure()._EMIN / critical_energy)
            y_fit = c[1] + c[0] * x
            psi_interval_in_units_one_over_gamma = 10 ** y_fit  # this is the semi interval
            psi_interval_in_units_one_over_gamma *= 4  # doubled interval
            if psi_interval_in_units_one_over_gamma < 2:
                psi_interval_in_units_one_over_gamma = 2

        if verbose:
            print(">>> psi_interval_in_units_one_over_gamma: ",psi_interval_in_units_one_over_gamma)


        angle_array_mrad = numpy.linspace(-0.5*psi_interval_in_units_one_over_gamma * 1e3 / gamma,
                                          0.5*psi_interval_in_units_one_over_gamma * 1e3 / gamma,
                                          psi_interval_number_of_points)

        if self.get_magnetic_structure().is_monochromatic():
            if verbose:
                print(">>> calculate_rays: is monochromatic")
                print(">>> calculate_rays: sync_ang (s) E=%f GeV, I=%f A, D=%f mrad, R=%f m, PhE=%f eV, Ec=%f eV, PhE/Ec=%f "% ( \
                    self.get_electron_beam().energy(),
                    self.get_electron_beam().current(),
                    (HDIV1 + HDIV2) * 1e3,
                    self.get_magnetic_structure().radius(),  # not needed anyway
                    self.get_magnetic_structure()._EMIN,
                    critical_energy,
                    self.get_magnetic_structure()._EMIN/critical_energy,
                      ))


            angular_distribution_s = sync_ang(1,#Flux at a given photon energy
                                            angle_array_mrad,
                                            polarization=1,#1 Parallel (l2=1, l3=0, in Sokolov&Ternov notation)
                                            e_gev=self.get_electron_beam().energy(),
                                            i_a=self.get_electron_beam().current(),
                                            hdiv_mrad=(HDIV1+HDIV2)*1e3,
                                            r_m=self.get_magnetic_structure().radius(),#not needed anyway
                                            energy=self.get_magnetic_structure()._EMIN,
                                            ec_ev=critical_energy)


            if verbose:
                print(">>> calculate_rays: sync_ang (p)")

            angular_distribution_p = sync_ang(1,#Flux at a given photon energy
                                            angle_array_mrad,
                                            polarization=2,#1 Parallel (l2=1, l3=0, in Sokolov&Ternov notation)
                                            e_gev=self.get_electron_beam().energy(),
                                            i_a=self.get_electron_beam().current(),
                                            hdiv_mrad=(HDIV1+HDIV2)*1e3,
                                            r_m=self.get_magnetic_structure().radius(),#not needed anyway
                                            energy=self.get_magnetic_structure()._EMIN,
                                            ec_ev=critical_energy)

            angular_distribution_s = angular_distribution_s.flatten()
            angular_distribution_p = angular_distribution_p.flatten()

            if verbose:
                from srxraylib.plot.gol import plot
                plot(angle_array_mrad,angular_distribution_s,
                     angle_array_mrad,angular_distribution_p,xtitle="angle / mrad",legend=["s","p"])

            sampler_angle = Sampler1D(angular_distribution_s+angular_distribution_p,angle_array_mrad*1e-3)
            if verbose:
                print(">>> calculate_rays: get_n_sampled_points (angle)")
            sampled_angle = sampler_angle.get_n_sampled_points(NRAYS)
            if verbose:
                print(">>> calculate_rays: DONE get_n_sampled_points (angle)  %d points"%(sampled_angle.size))

            pol_deg_interpolator = interp1d(angle_array_mrad*1e-3,
                    angular_distribution_s/(angular_distribution_s+angular_distribution_p))
            sampled_polarization = pol_deg_interpolator(sampled_angle)

            sampled_photon_energy = numpy.zeros_like(sampled_angle) + self.get_magnetic_structure()._EMIN

        else: # polychromatic

            photon_energy_array = numpy.linspace(self.get_magnetic_structure()._EMIN,
                                                 self.get_magnetic_structure()._EMAX,
                                                 self.get_magnetic_structure()._NG_E)

            if verbose:
                print(">>> sync_ene: calculating energy distribution")

            fm_s = sync_ene(4,photon_energy_array,
                          ec_ev=self.get_magnetic_structure().get_critical_energy(self.get_electron_beam().energy()),
                          e_gev=self.get_electron_beam().energy(),
                          i_a=self.get_electron_beam().current(),
                          hdiv_mrad=1,
                          psi_min=angle_array_mrad.min(),
                          psi_max=angle_array_mrad.max(),
                          psi_npoints=angle_array_mrad.size,
                          polarization=1)

            fm_p = sync_ene(4,photon_energy_array,
                          ec_ev=self.get_magnetic_structure().get_critical_energy(self.get_electron_beam().energy()),
                          e_gev=self.get_electron_beam().energy(),
                          i_a=self.get_electron_beam().current(),
                          hdiv_mrad=1,
                          psi_min=angle_array_mrad.min(),
                          psi_max=angle_array_mrad.max(),
                          psi_npoints=angle_array_mrad.size,
                          polarization=2)

            fm = fm_s + fm_p

            if verbose:
                print(">>> DONE sync_ene: calculating energy distribution",photon_energy_array.shape,fm.shape)
                from srxraylib.plot.gol import plot,plot_image
                plot(photon_energy_array,fm[fm.shape[0]//2,:],xtitle="Energy / eV",ytitle="Flux at zero elevation")
                plot(angle_array_mrad, fm[:,0], xtitle="Angle / mrad", ytitle="Flux at Emin="%(photon_energy_array[0]))
                print(">>>>>>>",fm.shape,angle_array_mrad.shape,photon_energy_array.shape)
                plot_image(fm,angle_array_mrad,photon_energy_array,aspect='auto',show=0,title="flux",xtitle="Psi / mrad",ytitle="Energy / eV")
                plot_image(fm_s/fm,angle_array_mrad,photon_energy_array,aspect='auto',title="polarization",xtitle="Psi / mrad",ytitle="Energy / eV")

            fm1 = numpy.zeros_like(fm)
            for i in range(fm.shape[0]):
                fm1[i,:] = fm[i,:] / (photon_energy_array*0.001)  # in photons/ev

            # plot_image(fm,angle_array_mrad,photon_energy_array,aspect='auto',show=0)
            # plot_image(fm_s/fm,angle_array_mrad,photon_energy_array,aspect='auto',title="polarization")


            sampler2 = Sampler2D(fm1,angle_array_mrad*1e-3,photon_energy_array)
            sampled_angle,sampled_photon_energy = sampler2.get_n_sampled_points(NRAYS)


            Angle_array_mrad = numpy.outer(angle_array_mrad,numpy.ones_like(photon_energy_array))
            Photon_energy_array = numpy.outer(numpy.ones_like(angle_array_mrad),photon_energy_array)
            Pi = numpy.array([Angle_array_mrad.flatten()*1e-3, Photon_energy_array.flatten()]).transpose()

            P = numpy.array([sampled_angle, sampled_photon_energy]).transpose()
            sampled_polarization = interpolate.griddata(Pi, (fm_s/fm).flatten(), P, method = "cubic")

        for itik in range(NRAYS):
            # ! Synchrontron depth
            ANGLE  =  numpy.random.random() * (HDIV1 + HDIV2) - HDIV2
            EPSI_PATH =  numpy.abs(r_aladdin) * ANGLE

            if self.get_magnetic_structure()._FLAG_EMITTANCE:
                sigma_x, sigma_xp, sigma_z, sigma_zp = self.get_electron_beam().get_sigmas_all()

                # ! calculation of the electrom beam moments at the current position
                # ! (sX,sZ) = (epsi_wx,epsi_ez):
                # ! <x2> = sX^2 + sigmaX^2
                # ! <x x'> = sX sigmaXp^2
                # ! <x'2> = sigmaXp^2                 (same for Z)

                epsi_wX = EPSI_DX + EPSI_PATH # sigma_x * sigma_xp


                # ! C
                # ! C Compute the actual distance (EPSI_W*) from the orbital focus
                # ! C
                # EPSI_WX = EPSI_DX + EPSI_PATH
                # EPSI_WZ = EPSI_DZ + EPSI_PATH

                rSigmaX = numpy.sqrt( (epsi_wX**2) * (sigma_xp**2) + sigma_x**2 )
                rSigmaXp = sigma_xp
                if rSigmaX * rSigmaXp != 0.0:
                    rhoX = epsi_wX * sigma_xp**2 / (rSigmaX * rSigmaXp)
                else:
                    rhoX = 0.0
                mean = [0, 0]
                cov = [[rSigmaX**2, rhoX*rSigmaX*rSigmaXp], [rhoX*rSigmaX*rSigmaXp, rSigmaXp**2]]  # diagonal covariance
                sampled_x, sampled_xp = numpy.random.multivariate_normal(mean, cov, 1).T
                # plot_scatter(sampled_x,sampled_xp,title="X")
                XXX = sampled_x
                E_BEAM1 = sampled_xp


                epsi_wZ = EPSI_DZ + EPSI_PATH # sigma_z * sigma_zp
                rSigmaZ = numpy.sqrt( (epsi_wZ**2) * (sigma_zp**2) + sigma_z**2 )
                rSigmaZp = sigma_zp
                if rSigmaZ * rSigmaZp != 0.0:
                    rhoZ = epsi_wZ * sigma_zp**2 / (rSigmaZ * rSigmaZp)
                else:
                    rhoZ = 0.0
                mean = [0, 0]
                cov = [[rSigmaZ**2, rhoZ*rSigmaZ*rSigmaZp], [rhoZ*rSigmaZ*rSigmaZp, rSigmaZp**2]]  # diagonal covariance
                sampled_z, sampled_zp = numpy.random.multivariate_normal(mean, cov, 1).T
                # plot_scatter(sampled_z,sampled_zp,title="Z")
                ZZZ = sampled_z
                E_BEAM3 = sampled_zp

                # print(">>>>>>>>>",sampled_x,sampled_z)
            else:
                sigma_x, sigma_xp, sigma_z, sigma_zp = (0.0, 0.0, 0.0, 0.0)
                rhoX = 0.0
                XXX = 0.0
                E_BEAM1 = 0.0
                ZZZ = 0.0
                E_BEAM3 = 0.0


            # ! C
            # ! C Synchrotron depth distribution
            # ! C
            # 440	CONTINUE
            # ! CC	R_ALADDIN NEGATIVE FOR COUNTER-CLOCKWISE SOURCE
            # IF (R_ALADDIN.LT.0) THEN
            # YYY = (ABS(R_ALADDIN) + XXX) * SIN(ANGLE)
            # ELSE
            # YYY = ( R_ALADDIN - XXX) * SIN(ANGLE)
            # END IF
            # XXX  =   COS(ANGLE) * XXX + R_ALADDIN * (1.0D0 - COS(ANGLE))


            # Synchrotron depth distribution
            # R_ALADDIN NEGATIVE FOR COUNTER-CLOCKWISE SOURCE
            if r_aladdin < 0:
                YYY = numpy.abs(r_aladdin + XXX) * numpy.sin(ANGLE)
            else:
                YYY = numpy.abs(r_aladdin - XXX) * numpy.sin(ANGLE)

            XXX = numpy.cos(ANGLE) * XXX + r_aladdin * (1.0 - numpy.cos(ANGLE))

            rays[itik,0] = XXX
            rays[itik,1] = YYY
            rays[itik,2] = ZZZ

            # ! C
            # ! C Synchrotron source
            # ! C Note. The angle of emission IN PLANE is the same as the one used
            # ! C before. This will give rise to a source curved along the orbit.
            # ! C The elevation angle is instead characteristic of the SR distribution.
            # ! C The electron beam emittance is included at this stage. Note that if
            # ! C EPSI = 0, we'll have E_BEAM = 0.0, with no changes.
            # ! C
            # ANGLEX =   ANGLE + E_BEAM(1)
            # DIREC(1)  =   TAN(ANGLEX)
            # IF (R_ALADDIN.LT.0.0D0) DIREC(1) = - DIREC(1)
            # DIREC(2)  =   1.0D0
            # ARG_ANG  =   GRID(6,ITIK)

            ANGLEX = ANGLE + E_BEAM1
            DIREC1 = numpy.tan(ANGLEX)
            if r_aladdin < 0:
                DIREC1 *= -1.0
            DIREC2 = 1.0
            ARG_ANG = numpy.random.random()

            # ! C
            # ! C In the case of SR, we take into account the fact that the electron
            # ! C trajectory is not orthogonal to the field. This will give a correction
            # ! C to the photon energy.  We can write it as a correction to the
            # ! C magnetic field strength; this will linearly shift the critical energy
            # ! C and, with it, the energy of the emitted photon.
            # ! C
            # E_TEMP(3) =   TAN(E_BEAM(3))/COS(E_BEAM(1))
            # E_TEMP(2) =   1.0D0
            # E_TEMP(1) =   TAN(E_BEAM(1))
            # CALL NORM (E_TEMP,E_TEMP)
            # CORREC =   SQRT(1.0D0-E_TEMP(3)**2)
            # 4400 CONTINUE
            E_TEMP3 = numpy.tan(E_BEAM3) / numpy.cos(E_BEAM1)
            E_TEMP2 = 1.0
            E_TEMP1 = numpy.tan(E_BEAM1)
            E_TEMP_MOD = numpy.sqrt(E_TEMP1**2 + E_TEMP2**2 + E_TEMP3**2)
            E_TEMP3 /= E_TEMP_MOD
            E_TEMP2 /= E_TEMP_MOD
            E_TEMP1 /= E_TEMP_MOD

            # IF (FDISTR.EQ.6) THEN ! exect synchtotron
            #     CALL ALADDIN1 (ARG_ANG,ANGLEV,F_POL,IER)
            #     Q_WAVE =   TWOPI*PHOTON(1)/TOCM*CORREC
            #     POL_DEG =   ARG_ANG
            # ELSE IF (FDISTR.EQ.4) THEN  ! synchrotron
            #     print*,"R_MAGNET, DIREC",R_MAGNET,DIREC
            #     ARG_ENER =   WRAN (ISTAR1)
            #     RAD_MIN =   ABS(R_MAGNET)
            #
            #     i1 = 1
            #     arg_ener = 0.5
            #     arg_ang = 0.5
            #     CALL WHITE (RAD_MIN,CORREC,ARG_ENER,ARG_ANG,Q_WAVE,ANGLEV,POL_DEG,i1)
            #
            #     print*,"RAD_MIN,CORREC,ARG_ENER,ARG_ANG,Q_WAVE,ANGLEV,POL_DEG",RAD_MIN,CORREC,ARG_ENER,ARG_ANG,Q_WAVE,ANGLEV,POL_DEG
            #     !Q_WAVE =   TWOPI*PHOTON(1)/TOCM*CORREC
            #     print*,"ENER,ANGLEV: ",Q_WAVE*TOCM/TWOPI,ANGLEV
            # END IF

            # interpolate for the photon energy,vertical angle,and the degree of polarization.

            wavelength = codata.h * codata.c / codata.e / sampled_photon_energy[itik]
            Q_WAVE = 2 * numpy.pi / (wavelength*1e2)
            ANGLEV = sampled_angle[itik]
            POL_DEG = sampled_polarization[itik]


            # IF (ANGLEV.LT.0.0) I_CHANGE = -1
            # ANGLEV =   ANGLEV + E_BEAM(3)
            if ANGLEV < 0:
                I_CHANGE = -1
            ANGLEV += E_BEAM3

            # ------ NOT LONGER DONE ------
            # ! C
            # ! C Test if the ray is within the specified limits
            # ! C
            # IF (FGRID.EQ.0.OR.FGRID.EQ.2) THEN
            #     IF (ANGLEV.GT.VDIV1.OR.ANGLEV.LT.-VDIV2) THEN
            #         ARG_ANG = WRAN(ISTAR1)
            #         ! C
            #         ! C If it is outside the range, then generate another ray.
            #         ! C
            #         GO TO 4400
            #     END IF
            # END IF


            # DIREC(3)  =   TAN(ANGLEV)/COS(ANGLEX)
            # CALL NORM (DIREC,DIREC)

            DIREC3 = numpy.tan(ANGLEV) / numpy.cos(ANGLEX)

            DIREC_MOD = numpy.sqrt(DIREC1**2 + DIREC2**2 + DIREC3**2)
            DIREC3 /= DIREC_MOD
            DIREC2 /= DIREC_MOD
            DIREC1 /= DIREC_MOD

            # print(">>>>DIREC,FGRID,R_ALADDIN: ",itik,DIREC1,DIREC2,DIREC3)

            rays[itik,3] = DIREC1
            rays[itik,4] = DIREC2
            rays[itik,5] = DIREC3


            #
            # electric field vectors (cols 7-9, 16-18) and phases (cols 14-15)
            #

        # ! C
        # ! C  ---------------------------------------------------------------------
        # ! C                 POLARIZATION
        # ! C
        # ! C   Generates the polarization of the ray. This is defined on the
        # ! C   source plane, so that A_VEC is along the X-axis and AP_VEC is along Z-axis.
        # ! C   Then care must be taken so that A will be perpendicular to the ray
        # ! C   direction.
        # ! C
        # ! C
        # A_VEC(1) = 1.0D0
        # A_VEC(2) = 0.0D0
        # A_VEC(3) = 0.0D0

        DIREC = rays[:,3:6].copy()
        A_VEC = numpy.zeros_like(DIREC)
        A_VEC[:,0] = 1.0

        # ! C
        # ! C   Rotate A_VEC so that it will be perpendicular to DIREC and with the
        # ! C   right components on the plane.
        # ! C
        # CALL CROSS (A_VEC,DIREC,A_TEMP)
        A_TEMP = self.__cross(A_VEC, DIREC)
        # CALL CROSS (DIREC,A_TEMP,A_VEC)
        A_VEC = self.__cross(DIREC, A_TEMP)
        # CALL NORM (A_VEC,A_VEC)
        A_VEC = self.__norm(A_VEC)
        # CALL CROSS (A_VEC,DIREC,AP_VEC)
        AP_VEC = self.__cross(A_VEC, DIREC)
        # CALL NORM (AP_VEC,AP_VEC)
        AP_VEC = self.__norm(AP_VEC)

        #
        # obtain polarization for each ray (interpolation)
        #


        POL_DEG = sampled_polarization
        DENOM = numpy.sqrt(1.0 - 2.0 * POL_DEG + 2.0 * POL_DEG**2)
        AX = POL_DEG/DENOM
        for i in range(3):
            A_VEC[:,i] *= AX

        AZ = (1.0-POL_DEG)/DENOM
        for i in range(3):
            AP_VEC[:,i] *= AZ


        rays[:,6:9] =  A_VEC
        rays[:,15:18] = AP_VEC

        #
        # ! C
        # ! C Now the phases of A_VEC and AP_VEC.
        # ! C

        #
        POL_ANGLE = 0.5 * numpy.pi # TO BE CHECKED

        if F_COHER == 1:
            PHASEX = 0.0
        else:
            PHASEX = numpy.random.random(NRAYS) * 2 * numpy.pi

        # PHASEZ = PHASEX + POL_ANGLE * numpy.sign(ANGLEV)

        rays[:,13] = 0.0 # PHASEX
        rays[:,14] = 0.0 # PHASEZ

        # set flag (col 10)
        rays[:,9] = 1.0

        #
        # photon energy (col 11)
        #

        # A2EV = 2.0*numpy.pi/(codata.h*codata.c/codata.e*1e2)
        # sampled_photon_energy = sampled_photon_energy
        wavelength = codata.h * codata.c / codata.e /sampled_photon_energy
        Q_WAVE = 2 * numpy.pi / (wavelength*1e2)
        rays[:,10] =  Q_WAVE # sampled_photon_energy * A2EV

        # col 12 (ray index)
        rays[:,11] =  1 + numpy.arange(NRAYS)

        # col 13 (optical path)
        rays[:,11] = 0.0

        POL_ANGLE = 0.5 * numpy.pi

        if F_COHER == 1:
            PHASEX = 0.0
        else:
            PHASEX = numpy.random.random(NRAYS) * 2 * numpy.pi

        PHASEZ = PHASEX + POL_ANGLE * numpy.sign(ANGLEV)

        rays[:,13] = PHASEX
        rays[:,14] = PHASEZ


        return rays