def generateEigenmodes(self, nx, ny, ekev, xMin, xMax, yMin, yMax, sigX, sigY, d2Waist): """ Generates eigenmodes of the partially coherent GSM beam :param nx: wfr horizontal dimensions in pixels (int) :param ny: wfr vertical dimensions in pixels (int) :param ekev: wfr energy in keV (float) :param xMin: wfr horizontal spatial minimum (float) :param xMax: wfr horizontal spatial maximum (float) :param yMin: wfr vertical spatial minimum (float) :param yMax: wfr vertical spatial maximum (float) :param sigX: fundamental gaussian horizontal FWHM (1st dev.) (float) :param sigY: fundamental gaussian vertical FWHM (1st dev.) (float) :param d2Waist: distance to waist - defines beam curvature (float) """ for mx, my in self.eigenModes: if mx == 0 and my == 0: self.wfr = Wavefront( build_gauss_wavefront_xy(nx, ny, ekev, xMin, xMax, yMin, yMax, sigX, sigY, d2Waist, _mx=mx, _my=my)) self.wfr.params.type = 'Gaussian Schell Model Type Beam' else: tmp_gsn = Wavefront( build_gauss_wavefront_xy(nx, ny, ekev, xMin, xMax, yMin, yMax, sigX, sigY, d2Waist, _mx=mx, _my=my)) addSlice(self.wfr, tmp_gsn) del tmp_gsn
def do_wpg_calculation(self): theta_fwhm = self.calculate_theta_fwhm_cdr(self.ekev, self.qnC) k = 2*numpy.sqrt(2*numpy.log(2)) sigX = 12.4e-10*k/(self.ekev*4*numpy.pi*theta_fwhm) print('sigX, waist_fwhm [um], far field theta_fwhms [urad]: {}, {},{}'.format( sigX*1e6, sigX*k*1e6, theta_fwhm*1e6) ) #define limits range_xy = theta_fwhm/k*self.distance*7. # sigma*7 beam size self.range_xy = range_xy npoints=180 wfr0 = build_gauss_wavefront_xy(npoints, npoints, self.ekev, -range_xy/2, range_xy/2, -range_xy/2, range_xy/2, sigX, sigX, self.distance, pulseEn=self.pulseEnergy, pulseTau=self.coh_time/numpy.sqrt(2), repRate=1/(numpy.sqrt(2)*self.pulse_duration)) return Wavefront(wfr0)
def gsmSource(wfr, mx, my, sigX=None, sigY=None, d2waist=None): """ takes an existing wavefield structure and uses it to generate a gsm source w/ a coherence function defined by starikov and wolf """ if sigX == None: sigX = (wfr.params.Mesh.xMax - wfr.params.Mesh.xMin) / 10 if sigY == None: sigY = (wfr.params.Mesh.yMax - wfr.params.Mesh.yMin) / 10 wfr.params.type = 'Gaussian Schell Model Type Beam' #### GENERATE TRANSVERSE ELECTRIC MODE PAIRS wfr.params.eigenmodes = ordered_pairs(mx, my) #xMin, xMax, yMin, yMax = wfr.get_limits() for mx, my in wfr.params.eigenmodes: tmp_gsn = Wavefront( build_gauss_wavefront_xy(wfr.params.Mesh.nx, wfr.params.Mesh.ny, wfr.params.photonEnergy / 1000, *wfr.get_limits(), sigX, sigY, wfr.params.Mesh.zCoord, _mx=mx, _my=my)) addSlice(wfr, tmp_gsn) return wfr
%%%%def generate_mode(self, mode_no, eigenfn, outPath = None): gauss_0 = primary_gaussian() # properties of gaussian gauss_0.d2waist = 0 print("Generating Mode {}".format(mode_no)) mx = self.modeIndices[n][0] my = self.modeIndices[n][1] xw = self.rho_I * yw = self.rho_I * M2x = (2*mx)+1 M2y = (2*my)+1 wfr = Wavefront(build_gauss_wavefront_xy(gauss_0.nx ,gauss_0.ny, self.EkeV, self.xMin, self.xMax, self.yMin, self.yMax, gauss_0.sigX*(M2x**-0.5), gauss_0.sigY*(M2y**-0.5), gauss_0.d2waist, tiltX = 0, tiltY = 0, _mx = mx, _my = my)) if outPath is not None: wfr.store_hdf5(outdir + "wfr_mode_{}.hdf5".format(mode_no)) return wfr
ax1 = fig.add_subplot(111) ax1.plot(ax_x, Ix, color="blue", label="Horizontal Profile") ax1.set_ylabel("Intensity (W/$mm^2$)", fontsize=22) ax1.plot(ax_y, Iy, color="red", label="Vertical Profile") ax1.set_xlabel("Position ($\mu m$)", fontsize=22) plt.legend(fontsize=22) if show == True: plt.show() def plotWavefront(wfr): fig = plt.figure(figsize=[12, 8]) ii = wfr.get_intensity()[:, :, 0] ph = wfr.get_phase()[:, :, 0] plt.imshow(ph * ii) if __name__ == '__main__': ### CONSTRUCT ARB. WFR wfr = Wavefront( build_gauss_wavefront_xy(256, 256, 9.2, -5e-07, 5e-07, -5e-07, 5e-07, 1e-07, 1e-07, 1e-09)) plotWavefront(wfr)
def test_gsm(self, beta = 1, nx = 10, ny = 1, pos = "end", export = False, outdir = ""): """ Initialise GSM beam as a container of multiple coherent modes Modes dictionary is setup by order {wfr, eigenvalue/weight} :param p_mu: rms width of the degree of coherence :param p_I: rms width of the intensity profile :param n: number of values for eigenvalue calculation (almost arb.) """ print("Initialising Gaussian-Schell Model Beam") self.log.info("Initialising Gaussian-Schell Model Beam") gauss_0 = primary_gaussian() # properties of gaussian N = nx*ny results = [] if export == True: os.mkdir(outdir) else: pass for itr in range(N): self.wfr.eigenval.append(eigenvaluePartCoh(1, beta,itr)) self.wfr.eigenval = self.wfr.eigenval[0:N] self.wfr.eigenfn = gen_modes(nx, ny) if pos == "start": gauss_0.d2waist = 0 elif pos == "end": gauss_0.d2waist = 2.012 else: assert("wavefront posn' should be 'start' or 'end'") print("Generating {} Coherent Modes".format(N)) self.log.info("Generating {} Coherent Modes".format(N)) eField = np.zeros((2048, 2048, 1)) if pos == "start": gauss_0.d2waist = 0 elif pos == "end": gauss_0.d2waist = 2.012 else: assert("wavefront posn' should be 'start' or 'end'") print(self.wfr.eigenfn) print("Generating {} Coherent Modes".format(N)) self.log.info("Generating {} Coherent Modes".format(N)) for itr in range(N): res = [] res.append(self.wfr.eigenfn[itr]) res.append(self.wfr.eigenval[itr]) if itr % 5 == 0: print("Generating Mode {}/{}".format(itr+1, N)) self.log.info("Generating Mode {}/{}".format(itr+1, N)) _mx = self.wfr.eigenfn[itr][0] _my = self.wfr.eigenfn[itr][1] M2x = (2*_mx)+1 M2y = (2*_my)+1 self.wfr.modes.append(Wavefront(build_gauss_wavefront_xy(gauss_0.nx ,gauss_0.ny, self.global_E*1e-03, gauss_0.xMin, gauss_0.xMax, gauss_0.yMin,gauss_0.yMax, gauss_0.sigX*M2x**-0.25, gauss_0.sigY*M2y**-0.25, gauss_0.d2waist, tiltX = 0, tiltY = 0, _mx = - _mx, ## NOTE NEGATIVE _my = _my, pulseEn = 2.51516e-2))) self.wfr.type = 'gsm' print("Coherent Modes Generated") self.log.info("Coherent Modes Generated") print("Testing Coherent Modes") self.log.info("Testing Coherent Modes") axis_x = np.linspace(-0.002, 0.002, 2048) axis_y = np.linspace(-0.002, 0.002, 2048) eField = np.zeros((2048,2048,1)) for itr in range(len(self.wfr.modes)): eField += self.wfr.modes[itr].data.arrEhor[:,:,:,0] * self.wfr.eigenval[itr] [cohx, cohy] = coherence_log(eField, axis_x, axis_y) self.log.info("**************************************************") self.log.info("Addition of Mode {}".format(itr)) self.log.info("Mode Weighting {}".format(self.wfr.eigenval[itr])) self.log.info("Mode Weighting {}".format(self.wfr.eigenfn[itr])) self.log.info("\n") self.log.info("Ix: {} m\nJx: {} m".format(cohx[2], cohx[3])) self.log.info("Iy: {} m\nJy: {} m".format(cohy[2], cohy[3])) self.log.info("x-beta: {} \n y-beta: {}".format(cohx[4], cohy[4])) res.append(cohx[2]) res.append(cohy[2]) res.append(cohx[3]) res.append(cohy[3]) res.append(cohx[4]) res.append(cohy[4]) results.append(res) return results
def constructTestWaveField(npoints=256,ekeV=0.6,z1=5, show=False): # Simple function for generating simple Gaussian wavefield for testing purposes from wpg.srwlib import srwl_uti_ph_en_conv from extensions.gvrutils import calculate_theta_fwhm_cdr from wpg.generators import build_gauss_wavefront_xy # set wavefield parameters qnC = 0.01 wlambda = srwl_uti_ph_en_conv(ekeV, _in_u='keV', _out_u='nm') theta_fwhm = calculate_theta_fwhm_cdr(ekeV,qnC) k = 2*np.sqrt(2*np.log(2)) range_xy = (theta_fwhm/k*z1*5.)*2.0 sigX = 12.4e-10*k/(ekeV*4*np.pi*theta_fwhm) # construct wavefield wf0=build_gauss_wavefront_xy(nx=npoints, ny=npoints, ekev=ekeV, xMin=-range_xy/2 ,xMax=range_xy/2, yMin=-range_xy/2, yMax=range_xy/2, sigX=sigX, sigY=sigX, d2waist=z1, _mx=0, _my=0 ) wfr = Wavefront(srwl_wavefront=wf0) print('Wavelength=%f, theta FWWM=%f, range XY = %f, sig X = %f' % (wlambda, theta_fwhm, range_xy, sigX)) wfr._srwl_wf.unitElFld = 1#'sqrt(Phot/s/0.1%bw/mm^2)' if show==True: #display the wavefield plotWavefront(wfr, 'Wavefield at source') return wfr def generate_mode_test(self, mode_no, eigenfn, outdir, gwaist = None): gauss_0 = primary_gaussian() # properties of gaussian gauss_0.d2waist = -9.0000 if gwaist is not None: gauss_0.d2waist = gwaist print("Generating Mode {}".format(mode_no)) _mx = eigenfn[mode_no][0] _my = eigenfn[mode_no][1] M2x = (2*_mx)+1 M2y = (2*_my)+1 GsnBm = SRWLGsnBm(_x = 0, _y = 0, _z = 0, _sigX = 100e-06,#gauss_0.sigX*(M2x**-0.25), _sigY = 100e-06,#gauss_0.sigY*(M2y**-0.25), _xp = 0, #gauss_0.xp, _yp = 0,#gauss_0.yp, _mx = _mx, _my = _my, _avgPhotEn = gauss_0.E) wfr = Wavefront(build_gaussian(GsnBm, gauss_0.nx*2, gauss_0.ny*2, gauss_0.xMin*2, gauss_0.xMax*2, gauss_0.yMin*2, gauss_0.yMax*2)) wfr.store_hdf5(outdir + "wfr_mode_{}.hdf5".format(mode_no)) return wfr
def constructWavefield( ekeV, qnC, z1, range_xy, strOutputDataFolder=None, dimension=2, beta=0.7, # 'tunable' parameter — sets global degree of coherence threshold=0.8, # ignore modes with eigenvalue < this value npoints=512, nslices=10, display=True, ): """ Define Transverse Optical Modes """ k = 2 * np.sqrt(2 * np.log(2)) wlambda = 12.4 * 1e-10 / ekeV # wavelength theta_fwhm = calculate_theta_fwhm_cdr(ekeV, qnC) sigX = 12.4e-10 * k / (ekeV * 4 * np.pi * theta_fwhm) # coherence width: widthCoherence = beta * sigX # get first n eigenvalues for transverse modes n = 99 e0 = eigenvaluePartCoh(sigX, widthCoherence, range(0, n)) # keep only modes for which eigenvalue > threshold e = e0[e0 > threshold] if display: plotEigenValues(e0, threshold) # generate mode indices modes = modes2D(9, N=len(e)) dimension = 2 # value should be 3 for 3D wavefront, 2 for 2D wavefront wf = [] for mx, my in modes: # define unique filename for storing results ip = np.floor(ekeV) frac = np.floor((ekeV - ip) * 1e3) # build initial gaussian wavefront if dimension == 2: wfr0 = build_gauss_wavefront_xy( nx=npoints, ny=npoints, ekev=ekeV, xMin=-range_xy / 2, xMax=range_xy / 2, yMin=-range_xy / 2, yMax=range_xy / 2, sigX=sigX, sigY=sigX, d2waist=z1, _mx=mx, _my=my, ) else: # build initial 3d gaussian beam tau = 1 # not sure if this parameter is even used - check meaning. wfr0 = build_gauss_wavefront( nx=npoints, ny=npoints, nz=nslices, ekev=ekev, xMin=-range_xy / 2, xMax=range_xy / 2, yMin=-range_xy / 2, yMax=range_xy / 2, tau=tau, sigX=sigX, sigY=sigX, d2waist=z1, _mx=mx, _my=my, ) if display == True: print( "dy {:.1f} um".format( (mwf.params.Mesh.yMax - mwf.params.Mesh.yMin) * 1e6 / (mwf.params.Mesh.ny - 1.0) ) ) print( "dx {:.1f} um".format( (mwf.params.Mesh.xMax - mwf.params.Mesh.xMin) * 1e6 / (mwf.params.Mesh.nx - 1.0) ) ) plot_t_wf(mwf) look_at_q_space(mwf) # init WPG Wavefront helper class mwf = Wavefront(wfr0) # store wavefront to HDF5 file if strOutputDataFolder: fname0 = ( "g" + str(int(ip)) + "_" + str(int(frac)) + "kev" + "_tm" + str(mx) + str(my) ) ifname = os.path.join(strOutputDataFolder, fname0 + ".h5") mwf.store_hdf5(ifname) print("Saved wavefront to HDF5 file: {}".format(ifname)) else: ifname = None wf.append([mx, my, ifname, mwf]) # plotWavefront(mwf, 'at '+str(z1)+' m') # look_at_q_space(mwf) fwhm_x = calculate_fwhm_x(mwf) print( "FWHMx [mm], theta_fwhm [urad]: {}, {}".format( fwhm_x * 1e3, fwhm_x / z1 * 1e6 ) ) # show_slices_hsv(mwf, slice_numbers=None, pretitle='SLICETYSLICE') return wf, modes, e