w = S4Wiggler(K_vertical=kValue,period_length=per,number_of_periods=nPer, flag_emittance=use_emittances, emin=e_min,emax=e_max,ng_e=10, ng_j=nTrajPoints) print(w.info()) ls = S4WigglerLightSource(name="Untitled", electron_beam=syned_electron_beam, wiggler_magnetic_structure=w) beam = ls.get_beam(NRAYS=NRAYS) compare_rays_with_shadow3_beam(beam.rays,beam_shadow3,do_plot=False,do_assert=True) # # check new sync_f function # from numpy.testing import assert_almost_equal from shadow4.sources.wiggler.s4_wiggler_light_source import sync_f_sigma_and_pi from srxraylib.sources.srfunc import sync_f rAngle = numpy.array([1,2,3,4]) rEnergy = 1.3 s,p = sync_f_sigma_and_pi(rAngle,rEnergy) s0 = sync_f(rAngle, rEnergy, polarization=1) p0 = sync_f(rAngle, rEnergy, polarization=2) assert_almost_equal(s,s0[:,0]) assert_almost_equal(p, p0[:, 0]) print(">>>>s: ",s,s0[:,0]) print(">>>>p: ",p,p0[:,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
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
# # fits the dependence of the width of the emission vs energy to get an estimation of the sampling interval # # RENERGY = numpy.array([0.01,0.1,1.0]) RENERGY = numpy.logspace( -6, 2, 100) # energies from 1e-6 to 100 times the critical energy OUT = RENERGY * 0.0 for i, rEnergy in enumerate(RENERGY): # rEnergy = 0.01 rAngle = numpy.linspace(-1000, 1000, 2000) f_s = sync_f(rAngle, rEnergy=rEnergy, polarization=1, gauss=0, l2=1, l3=0) #CALCULATE fwhm tt = numpy.where( f_s >= max(f_s) * 0.01) # tjis is the width at 0.01 of the height if f_s[tt].size > 1: binSize = rAngle[1] - rAngle[0] fwhm = binSize * (tt[0][-1] - tt[0][0]) fwhm_coordinates = (rAngle[tt[0][0]], rAngle[tt[0][-1]]) print("FWHM: ", fwhm) print("FWHM coordinates: ", fwhm_coordinates) OUT[i] = fwhm_coordinates[1] if False: f_tot = sync_f(rAngle, rEnergy=rEnergy,
def __calculate_rays(self, user_unit_to_m=1.0, 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=True): """ 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 self.__result_cdf is None: self.__calculate_radiation() if verbose: print(">>> Results of calculate_radiation") print(">>> trajectory.shape: ", self.__result_trajectory.shape) print(">>> cdf: ", self.__result_cdf.keys()) wiggler = self.get_magnetic_structure() syned_electron_beam = self.get_electron_beam() sampled_photon_energy, sampled_theta, sampled_phi = self._sample_photon_energy_theta_and_phi( NRAYS) if verbose: print( ">>> sampled sampled_photon_energy,sampled_theta,sampled_phi: ", sampled_photon_energy, sampled_theta, sampled_phi) if SEED != 0: numpy.random.seed(SEED) sigmas = syned_electron_beam.get_sigmas_all() rays = numpy.zeros((NRAYS, 18)) # # sample sizes (cols 1-3) # # if wiggler._FLAG_EMITTANCE: if numpy.array(numpy.abs(sigmas)).sum() == 0: wiggler._FLAG_EMITTANCE = False if wiggler._FLAG_EMITTANCE: x_electron = numpy.random.normal(loc=0.0, scale=sigmas[0], size=NRAYS) y_electron = 0.0 z_electron = numpy.random.normal(loc=0.0, scale=sigmas[2], size=NRAYS) else: x_electron = 0.0 y_electron = 0.0 z_electron = 0.0 # traj[0,ii] = yx[i] # traj[1,ii] = yy[i]+j * per - start_len # traj[2,ii] = 0.0 # traj[3,ii] = betax[i] # traj[4,ii] = betay[i] # traj[5,ii] = 0.0 # traj[6,ii] = curv[i] # traj[7,ii] = bz[i] PATH_STEP = self.__result_cdf["step"] X_TRAJ = self.__result_cdf["x"] Y_TRAJ = self.__result_cdf["y"] SEEDIN = self.__result_cdf["cdf"] ANGLE = self.__result_cdf["angle"] CURV = self.__result_cdf["curv"] EPSI_PATH = numpy.arange( CURV.size) * PATH_STEP # self._result_trajectory[7,:] # ! C We define the 5 arrays: # ! C Y_X(5,N) ---> X(Y) # ! C Y_XPRI(5,N) ---> X'(Y) # ! C Y_CURV(5,N) ---> CURV(Y) # ! C Y_PATH(5,N) ---> PATH(Y) # ! C F(1,N) contains the array of Y values where the nodes are located. # CALL PIECESPL(SEED_Y, Y_TEMP, NP_SY, IER) # CALL CUBSPL (Y_X, X_TEMP, NP_TRAJ, IER) # CALL CUBSPL (Y_Z, Z_TEMP, NP_TRAJ, IER) # CALL CUBSPL (Y_XPRI, ANG_TEMP, NP_TRAJ, IER) # CALL CUBSPL (Y_ZPRI, ANG2_TEMP, NP_TRAJ, IER) # CALL CUBSPL (Y_CURV, C_TEMP, NP_TRAJ, IER) # CALL CUBSPL (Y_PATH, P_TEMP, NP_TRAJ, IER) SEED_Y = interp1d(SEEDIN, Y_TRAJ, kind='linear') Y_X = interp1d(Y_TRAJ, X_TRAJ, kind='cubic') Y_XPRI = interp1d(Y_TRAJ, ANGLE, kind='cubic') Y_CURV = interp1d(Y_TRAJ, CURV, kind='cubic') Y_PATH = interp1d(Y_TRAJ, EPSI_PATH, kind='cubic') # ! C+++ # ! C Compute the path length to the middle (origin) of the wiggler. # ! C We need to know the "center" of the wiggler coordinate. # ! C input: Y_PATH ---> spline array # ! C NP_TRAJ ---> # of points # ! C Y_TRAJ ---> calculation point (ind. variable) # ! C output: PATH0 ---> value of Y_PATH at X = Y_TRAJ. If # ! C Y_TRAJ = 0, then PATH0 = 1/2 length # ! C of trajectory. # ! C+++ Y_TRAJ = 0.0 # CALL SPL_INT (Y_PATH, NP_TRAJ, Y_TRAJ, PATH0, IER) PATH0 = Y_PATH(Y_TRAJ) # ! C # ! C These flags are set because of the original program structure. # ! C # F_PHOT = 0 # F_COLOR = 3 # FSOUR = 3 # FDISTR = 4 ws_ev, ws_f, tmp = wiggler_spectrum( self.__result_trajectory, enerMin=wiggler._EMIN, enerMax=wiggler._EMAX, nPoints=500, # per=self.syned_wiggler.period_length(), electronCurrent=syned_electron_beam._current, outFile="", elliptical=False) ws_flux_per_ev = ws_f / (ws_ev * 1e-3) samplerE = Sampler1D(ws_flux_per_ev, ws_ev) sampled_energies, h, h_center = samplerE.get_n_sampled_points_and_histogram( NRAYS) ############################################### gamma = syned_electron_beam.gamma() m2ev = codata.c * codata.h / codata.e TOANGS = m2ev * 1e10 ##################################################### RAD_MIN = 1.0 / numpy.abs(self.__result_cdf["curv"]).max() critical_energy = TOANGS * 3.0 * numpy.power( gamma, 3) / 4.0 / numpy.pi / 1.0e10 * (1.0 / RAD_MIN) 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._EMIN / critical_energy) x = numpy.log10( wiggler._EMIN / (4 * critical_energy)) # the wiggler that does not have an unique # Ec. To be safe, I use 4 times the # Ec vale to make the interval wider than for the BM 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) # a = numpy.linspace(-0.6,0.6,150) a = angle_array_mrad ##################################################################### a8 = 1.0 hdiv_mrad = 1.0 # i_a = self.syned_electron_beam._current # # fm = sync_f(a*self.syned_electron_beam.gamma()/1e3,eene,polarization=0) * \ # numpy.power(eene,2)*a8*i_a*hdiv_mrad*numpy.power(self.syned_electron_beam._energy_in_GeV,2) # # plot(a,fm,title="sync_f") # # samplerAng = Sampler1D(fm,a) # # sampled_theta,hx,h = samplerAng.get_n_sampled_points_and_histogram(10*NRAYS) # plot(h,hx) for itik in range(NRAYS): # ARG_Y = GRID(2,ITIK) # CALL SPL_INT (SEED_Y, NP_SY, ARG_Y, Y_TRAJ, IER) arg_y = numpy.random.random() # ARG_Y[itik] Y_TRAJ = SEED_Y(arg_y) # ! [email protected] 2014-05-19 # ! in wiggler some problems arise because spl_int # ! does not return a Y value in the correct range. # ! In those cases, we make a linear interpolation instead. # if ((y_traj.le.y_temp(1)).or.(y_traj.gt.y_temp(NP_SY))) then # y_traj_old = y_traj # CALL LIN_INT (SEED_Y, NP_SY, ARG_Y, Y_TRAJ, IER) # print*,'SOURCESYNC: bad y_traj from SPL_INT, corrected with LIN_SPL: ',y_traj_old,'=>',y_traj # endif # # CALL SPL_INT (Y_X, NP_TRAJ, Y_TRAJ, X_TRAJ, IER) # CALL SPL_INT (Y_XPRI, NP_TRAJ, Y_TRAJ, ANGLE, IER) # CALL SPL_INT (Y_CURV, NP_TRAJ, Y_TRAJ, CURV, IER) # CALL SPL_INT (Y_PATH, NP_TRAJ, Y_TRAJ, EPSI_PATH, IER) # END IF X_TRAJ = Y_X(Y_TRAJ) ANGLE = Y_XPRI(Y_TRAJ) CURV = Y_CURV(Y_TRAJ) EPSI_PATH = Y_PATH(Y_TRAJ) # print("\n>>><<<",arg_y,Y_TRAJ,X_TRAJ,ANGLE,CURV,EPSI_PATH) # EPSI_PATH = EPSI_PATH - PATH0 ! now refer to wiggler's origin # IF (CURV.LT.0) THEN # POL_ANGLE = 90.0D0 ! instant orbit is CW # ELSE # POL_ANGLE = -90.0D0 ! CCW # END IF # IF (CURV.EQ.0) THEN # R_MAGNET = 1.0D+20 # ELSE # R_MAGNET = ABS(1.0D0/CURV) # END IF # POL_ANGLE = TORAD*POL_ANGLE EPSI_PATH = EPSI_PATH - PATH0 # now refer to wiggler's origin if CURV < 0: POL_ANGLE = 90.0 # instant orbit is CW else: POL_ANGLE = -90.0 # CCW if CURV == 0.0: R_MAGNET = 1.0e20 else: R_MAGNET = numpy.abs(1.0 / CURV) POL_ANGLE = POL_ANGLE * numpy.pi / 180.0 # ! 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 # ! BUG [email protected] found that these routine does not make the # ! calculation correctly. Changed to new one BINORMAL # !CALL GAUSS (SIGMAX, EPSI_X, EPSI_WX, XXX, E_BEAM(1), istar1) # !CALL GAUSS (SIGMAZ, EPSI_Z, EPSI_WZ, ZZZ, E_BEAM(3), istar1) # ! # ! 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) # # ! then calculate the new recalculated sigmas (rSigmas) and correlation rho of the # ! normal bivariate distribution at the point in the electron trajectory # ! rsigmaX = sqrt(<x2>) # ! rsigmaXp = sqrt(<x'2>) # ! rhoX = <x x'>/ (rsigmaX rsigmaXp) (same for Z) # # if (abs(sigmaX) .lt. 1e-15) then !no emittance # sigmaXp = 0.0d0 # XXX = 0.0 # E_BEAM(1) = 0.0 # else # sigmaXp = epsi_Xold/sigmaX ! true only at waist, use epsi_xOld as it has been redefined :( # rSigmaX = sqrt( (epsi_wX**2) * (sigmaXp**2) + sigmaX**2 ) # rSigmaXp = sigmaXp # if (abs(rSigmaX*rSigmaXp) .lt. 1e-15) then !no emittance # rhoX = 0.0 # else # rhoX = epsi_wx * sigmaXp**2 / (rSigmaX * rSigmaXp) # endif # # CALL BINORMAL (rSigmaX, rSigmaXp, rhoX, XXX, E_BEAM(1), istar1) # endif # if wiggler._FLAG_EMITTANCE: # CALL BINORMAL (rSigmaX, rSigmaXp, rhoX, XXX, E_BEAM(1), istar1) # [ c11 c12 ] [ sigma1^2 rho*sigma1*sigma2 ] # [ c21 c22 ] = [ rho*sigma1*sigma2 sigma2^2 ] sigmaX, sigmaXp, sigmaZ, sigmaZp = syned_electron_beam.get_sigmas_all( ) epsi_wX = sigmaX * sigmaXp rSigmaX = numpy.sqrt((epsi_wX**2) * (sigmaXp**2) + sigmaX**2) rSigmaXp = sigmaXp rhoX = epsi_wX * sigmaXp**2 / (rSigmaX * rSigmaXp) mean = [0, 0] cov = [[sigmaX**2, rhoX * sigmaX * sigmaXp], [rhoX * sigmaX * sigmaXp, sigmaXp**2]] # diagonal covariance sampled_x, sampled_xp = numpy.random.multivariate_normal( mean, cov, 1).T # plot_scatter(sampled_x,sampled_xp) XXX = sampled_x E_BEAM1 = sampled_xp epsi_wZ = sigmaZ * sigmaZp rSigmaZ = numpy.sqrt((epsi_wZ**2) * (sigmaZp**2) + sigmaZ**2) rSigmaZp = sigmaZp rhoZ = epsi_wZ * sigmaZp**2 / (rSigmaZ * rSigmaZp) mean = [0, 0] cov = [[sigmaZ**2, rhoZ * sigmaZ * sigmaZp], [rhoZ * sigmaZ * sigmaZp, sigmaZp**2]] # diagonal covariance sampled_z, sampled_zp = numpy.random.multivariate_normal( mean, cov, 1).T ZZZ = sampled_z E_BEAM3 = sampled_zp else: sigmaXp = 0.0 XXX = 0.0 E_BEAM1 = 0.0 rhoX = 0.0 sigmaZp = 0.0 ZZZ = 0.0 E_BEAM3 = 0.0 # # ! C # ! C For normal wiggler, XXX is perpendicular to the electron trajectory at # ! C the point defined by (X_TRAJ,Y_TRAJ,0). # ! C # IF (F_WIGGLER.EQ.1) THEN ! normal wiggler # YYY = Y_TRAJ - XXX*SIN(ANGLE) # XXX = X_TRAJ + XXX*COS(ANGLE) YYY = Y_TRAJ - XXX * numpy.sin(ANGLE) XXX = X_TRAJ + XXX * numpy.cos(ANGLE) rays[itik, 0] = XXX rays[itik, 1] = YYY rays[itik, 2] = ZZZ # # directions # # ! 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 # IF (F_WIGGLER.EQ.3) ANGLE=0 ! Elliptical Wiggler. # 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) DIREC2 = 1.0 # ! 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_norm = numpy.sqrt(E_TEMP1**2 + E_TEMP2**2 + E_TEMP3**2) E_TEMP3 /= e_temp_norm E_TEMP2 /= e_temp_norm E_TEMP1 /= e_temp_norm CORREC = numpy.sqrt(1.0 - E_TEMP3**2) # IF (FDISTR.EQ.6) THEN # 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 # ARG_ENER = WRAN (ISTAR1) # RAD_MIN = ABS(R_MAGNET) # # i1 = 1 # CALL WHITE & # (RAD_MIN,CORREC,ARG_ENER,ARG_ANG,Q_WAVE,ANGLEV,POL_DEG,i1) # END IF RAD_MIN = numpy.abs(R_MAGNET) # CALL WHITE (RAD_MIN,CORREC,ARG_ENER,ARG_ANG,Q_WAVE,ANGLEV,POL_DEG,i1) ARG_ANG = numpy.random.random() ARG_ENER = numpy.random.random() # print(" >> R_MAGNET, DIREC",R_MAGNET,DIREC1,DIREC2) # print(" >> RAD_MIN,CORREC,ARG_ENER,ARG_ANG,",RAD_MIN,CORREC,ARG_ENER,ARG_ANG) ####################################################################### # gamma = self.syned_electron_beam.gamma() # m2ev = codata.c * codata.h / codata.e # TOANGS = m2ev * 1e10 # critical_energy = TOANGS*3.0*numpy.power(gamma,3)/4.0/numpy.pi/1.0e10*(1.0/RAD_MIN) # sampled_photon_energy = sampled_energies[itik] # wavelength = codata.h * codata.c / codata.e /sampled_photon_energy # Q_WAVE = 2 * numpy.pi / (wavelength*1e2) # print(" >> PHOTON ENERGY, Ec, lambda, Q: ",sampled_photon_energy,critical_energy,wavelength*1e10,Q_WAVE) ################################################################################### sampled_photon_energy = sampled_energies[itik] # wavelength = codata.h * codata.c / codata.e /sampled_photon_energy critical_energy = TOANGS * 3.0 * numpy.power( gamma, 3) / 4.0 / numpy.pi / 1.0e10 * (1.0 / RAD_MIN) eene = sampled_photon_energy / critical_energy # TODO: remove old after testing... method = "new" if method == "old": # fm = sync_f(a*1e-3*self.syned_electron_beam.gamma(),eene,polarization=0) * \ # numpy.power(eene,2)*a8*self.syned_electron_beam._current*hdiv_mrad * \ # numpy.power(self.syned_electron_beam._energy_in_GeV,2) fm_s = sync_f(a*1e-3*self.syned_electron_beam.gamma(),eene,polarization=1) * \ numpy.power(eene,2)*a8*self.syned_electron_beam._current*hdiv_mrad * \ numpy.power(self.syned_electron_beam._energy_in_GeV,2) fm_p = sync_f(a*1e-3*self.syned_electron_beam.gamma(),eene,polarization=2) * \ numpy.power(eene,2)*a8*self.syned_electron_beam._current*hdiv_mrad * \ numpy.power(self.syned_electron_beam._energy_in_GeV,2) else: fm_s, fm_p = sync_f_sigma_and_pi( a * 1e-3 * syned_electron_beam.gamma(), eene) cte = eene**2 * a8 * syned_electron_beam._current * hdiv_mrad * syned_electron_beam._energy_in_GeV**2 fm_s *= cte fm_p *= cte fm = fm_s + fm_p fm_pol = numpy.zeros_like(fm) for i in range(fm_pol.size): if fm[i] == 0.0: fm_pol[i] = 0 else: fm_pol[i] = fm_s[i] / fm[i] fm.shape = -1 fm_s.shape = -1 fm_pol.shape = -1 pol_deg_interpolator = interp1d(a * 1e-3, fm_pol) samplerAng = Sampler1D(fm, a * 1e-3) # samplerPol = Sampler1D(fm_s/fm,a*1e-3) # plot(a*1e-3,fm_s/fm) if fm.min() == fm.max(): print("Warning: cannot compute divergence for ray index %d" % itik) sampled_theta = 0.0 else: sampled_theta = samplerAng.get_sampled(ARG_ENER) sampled_pol_deg = pol_deg_interpolator(sampled_theta) # print("sampled_theta: ",sampled_theta, "sampled_energy: ",sampled_photon_energy, "sampled pol ",sampled_pol_deg) ANGLEV = sampled_theta ANGLEV += E_BEAM3 # IF (ANGLEV.LT.0.0) I_CHANGE = -1 # ANGLEV = ANGLEV + E_BEAM(3) # ! 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) DIREC3 = numpy.tan(ANGLEV) / numpy.cos(ANGLEX) # IF (F_WIGGLER.EQ.3) THEN # CALL ROTATE (DIREC, ANGLE3,ANGLE2,ANGLE1,DIREC) # END IF # CALL NORM (DIREC,DIREC) direc_norm = numpy.sqrt(DIREC1**2 + DIREC2**2 + DIREC3**2) DIREC1 /= direc_norm DIREC2 /= direc_norm DIREC3 /= direc_norm rays[itik, 3] = DIREC1 # VX rays[itik, 4] = DIREC2 # VY rays[itik, 5] = DIREC3 # VZ if user_unit_to_m != 1.0: rays[:, 0] /= user_unit_to_m rays[:, 1] /= user_unit_to_m rays[:, 2] /= user_unit_to_m # # sample divergences (cols 4-6): the Shadow way # # # 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_pol_deg 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 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_energies 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 return rays
# psi energy # psi_max = 800e-6 #10 / gamma PSI = numpy.linspace(-psi_max, psi_max, 100) codata_mee = 1e-6 * codata.m_e * codata.c**2 / codata.e gamma = ener_gev * 1e3 / codata_mee if False: PSITHETA = numpy.zeros((PSI.size, XP.size)) POWER = numpy.zeros_like(ENERGIES) for i, energy in enumerate(ENERGIES): PSITHETA = sync_f(PSI * gamma, rEnergy=energy / Ec, polarization=0, gauss=0, l2=1, l3=0) PSITHETA /= PSITHETA.sum() * (PSI[1] - PSI[0]) * (XP[1] - XP[0]) PSITHETA *= w[i] POWER[i] = PSITHETA.sum() * (PSI[1] - PSI[0]) * (XP[1] - XP[0]) plot_image(PSITHETA.T, 1e6 * XP, 1e6 * PSI, aspect='auto', title="Energy: %f eV " % energy, ytitle="Psi / urad", xtitle="theta / urad") plot(ENERGIES, POWER) #,e,w,legend=["integrated","reference"])