num_data_all = 8000 # test #path = 'test_data/' #first_number = 1 #num_data_all = 2000 crystal_structure = 'fcc' material = 'Au' lc = 4.065 spatial_domain = (51.2, 51.2) # A qstem = PyQSTEM('HRTEM') image_size = (256, 256) # px resolution = spatial_domain[0] / image_size[0] # [A/px] print("Running on host '{}'".format(platform.node())) for data_index in range(first_number, num_data_all): print('Processing Data [{}/{}]'.format(data_index, num_data_all)) random_size = random.uniform(20, 30) # A random_NP = Random_NP(crystal_structure,material, lc, random_size, spatial_domain)
num_data_all = 8000 # test #path = 'test_data/' #first_number = 1 #num_data_all = 2000 crystal_structure = 'fcc' material = 'Au' lc = 4.065 spatial_domain = (51.2, 51.2) # A qstem = PyQSTEM('TEM') image_size = (256, 256) # px resolution = spatial_domain[0] / image_size[0] # [A/px] def HRTEM_multiprocessing(data_index): print('Processing data [{}/{}]'.format(data_index, num_data_all)) random_size = random.uniform(10, 20) # A random_NP = Random_NP(crystal_structure, material, lc, random_size, spatial_domain) random_NP_model = random_NP.get_model()
def IMG_sim(system,temparams): qstem = PyQSTEM('TEM') # Initialize a QSTEM simulation of TEM image. #Read the TEM parameters (given in a temparams list.) tilt,plane_grid,num_slices,resample,dose,v0,defocus,Cs,df,MTF_param,blur,temsurface,rotation = temparams #Define defocus function to calculate Scherzer defocus (and offset from Scherzer defocus): def defocusfunc(focus): result=[0,focus[1]] if focus[0]=='Scherzer': prov_sys=molecule('H',vacuum=2) qstem.set_atoms(prov_sys) qstem.build_wave('plane',v0,plane_grid) prov_wave=qstem.get_wave() lam=prov_wave.wavelength result[0]=-1.2*math.sqrt(lam*Cs) else: result[0]=0 return sum(result) defocus=defocusfunc(defocus) # Rotate temsurface to the top: system.rotate(temsurface,[0,1,0],center='COU') # Apply rotation to system and reference system. system.rotate(rotation,v=[0,1,0],center="COU") # Apply the tilt system.rotate(tilt,[1,0,0],center="COU") qstem.set_atoms(system) #Set the atoms for the first PyQSTEM simulation. qstem.build_wave('plane',v0,plane_grid) #Build the plane wave on the defined grid. wave=qstem.get_wave() #Save the plane wave in Python. qstem.build_potential(num_slices) #Build the electrostatic potential from the system using tabulated data for each atom. From Rez et al.: "Dirac-Fock calculations of X-ray scattering factors and contributions to the mean inner potential for electron scattering". potential=qstem.get_potential_or_transfunc() #Save the potential in Python. Have a look at it. qstem.run() #Run the qstem simulation. wave=qstem.get_wave() #Get the exit wave. ctf = CTF(defocus=defocus,Cs=Cs,focal_spread=df) #Define a contrast transfer function from relevant parameters. img_wave=wave.apply_ctf(ctf) #Apply the CTF to the exit wave and save the resulting image wave. img=img_wave.detect(dose=dose,resample=resample,MTF_param=MTF_param,blur=blur) # Apply the detector PSF and resample the image. # Remove the tilt of the system. system.rotate(-tilt,[1,0,0],center="COU") # Rotate the system back. system.rotate(-rotation,v=[0,1,0],center="COU") # Rotate temsurface back. system.rotate([0,1,0],temsurface,center='COU') return img,img_wave,defocus
def snrmaster(Nanoparticle,subsys100,subsys111, temparams, nmean, indexed_surfaces,plot,debug_box): #Produce the Nanoparticle SNR reference cell Nanoparticlesnr = Atoms() for i in Nanoparticle: Nanoparticlesnr.append(i) Nanoparticlesnr.set_cell(Nanoparticle.cell) Nanoparticlesnr.center() #Same procedure for the SNR reference cell Referencesnr = Atoms() for i in Nanoparticle: if i.symbol==metal: Referencesnr.append(i) Referencesnr.set_cell(Nanoparticle.cell) Referencesnr.center() #Read the TEM parameters tilt,plane_grid,num_slices,resample,dose,v0,defocus,Cs,df,MTF_param,blur,temsurface,rotation = temparams SNRparams=[0,plane_grid,num_slices,resample,dose,v0,defocus,Cs,df,MTF_param,blur,[0,1,0],0] qstem = PyQSTEM('TEM') #Rotate systems to the surface we wish to investigate. Referencesnr.rotate(temsurface,[0,1,0],center='COU') Nanoparticlesnr.rotate(temsurface,[0,1,0],center='COU') #Rotate the system according to rotation parameter: Referencesnr.rotate(rotation,[0,1,0],center='COU') Nanoparticlesnr.rotate(rotation,[0,1,0],center='COU') #Tilt NP and reference S/N in order to match the system we visualise and the system we calculate S/N from. Nanoparticlesnr.rotate(tilt,[1,0,0],center="COU") Referencesnr.rotate(tilt,[1,0,0],center="COU") # First setup of the TEM objects for the NP and the reference system. # The setup happens before the loop designed to get an average since we need an img_wave object to define the S/N box. img_snr,img_wave_snr,defocus_value=IMG_sim(Nanoparticlesnr,SNRparams) img_reference_snr,img_wave_reference_snr,defocus_value=IMG_sim(Referencesnr,SNRparams) #Find the height and width of the box within which to calculate the value of the signal. def heightbox(): dire = abs(temsurface[0])+abs(temsurface[1])+abs(temsurface[2]) if (dire == 1): subsys = subsys100 if (dire == 3): subsys = subsys111 zmax = 0 xmax = 0 ymax = 0 zmaxmetal = 0 xmaxmetal = 0 ymaxmetal = 0 #Maximum x, y and z values are found for the subsystem: xmin = 0 ymin = 0 for i in subsys: if(i.position[2]>zmax): zmax = i.position[2] if(i.position[2]>zmaxmetal and i.symbol == metal): zmaxmetal = i.position[2] if abs(i.position[0])>xmax: xmax=abs(i.position[0]) if abs(i.position[0])>xmaxmetal and i.symbol == metal: xmaxmetal=abs(i.position[0]) if abs(i.position[1])>ymax: ymax=abs(i.position[1]) if abs(i.position[1])>ymax and i.symbol == metal: ymaxmetal=abs(i.position[1]) if i.position[0]<xmin and i.symbol != metal: xmin=i.position[0] if i.position[1]<ymin and i.symbol !=metal: ymin=i.position[1] #Determine if adsorbate atoms have x-y-coordinates outside the subsystem unit cell. xyoffsets=[0] if xmax>xmaxmetal: xyoffsets.append(xmax-xmaxmetal) if ymax>ymaxmetal: xyoffsets.append(ymax-ymaxmetal) if ymin<0: xyoffsets.append(abs(ymin)) if xmin<0: xyoffsets.append(abs(xmin)) #Determine the offset in x,y,z: zoffset=zmax-zmaxmetal xyoffset=max(xyoffsets) return zoffset, xyoffset #Define a function to determine x,y and z coordinates for the SNR box in the nanoparticle unit cell: def coordinatesbox(): xmax = 0 height = heightbox()[0] ind = indexed_surfaces[tuple(temsurface)][0] zmax = 0 for i in indexed_surfaces[tuple(temsurface)]: pos = Nanoparticlesnr[i].position[1] if(pos>zmax): zmax = pos zmin = zmax for i in indexed_surfaces[tuple(temsurface)]: pos = Nanoparticlesnr[i].position[1] if(pos<zmin): zmin = pos zdif = zmax-zmin z = zmax height = (height + zdif)*1.2 for i in indexed_surfaces[tuple(temsurface)]: pos = Nanoparticlesnr[i].position[0] if(pos>xmax): xmax = pos xmin = xmax for i in indexed_surfaces[tuple(temsurface)]: pos = Nanoparticlesnr[i].position[0] if(pos<xmin): xmin = pos xmax=xmax+heightbox()[1] xmin=xmin-heightbox()[1] return (xmin,xmax,z,z+height) xmin,xmax,zmin,zmax = coordinatesbox() xmin,xmax,zmin,zmax = coordinatesbox() #Conversion between number of data points and length scale dpl = len(img_snr.T[0])/img_wave_snr.get_extent()[1] #Convert from lengths to corresponding index values in image array xmindata = math.floor(xmin*dpl) xmaxdata = math.floor(xmax*dpl) zmindata = math.floor(zmin*dpl) zmaxdata = math.floor(zmax*dpl) #Define RMS function. def rms(img): rms = np.sqrt(np.sum(img*img)/len(img.flat)) return rms #Define SNR function. def snrfunc(signal,noise): #We find the SNR of both the image and the corresponding inverted image. We return the maximum value. s1 = signal s2 = util.invert(signal) n1 = noise n2 = util.invert(noise) snr1 = rms(s1)/rms(n1) snr2 =rms(s2)/rms(n2) return max(snr1,snr2) zlen = zmaxdata - zmindata #Define arrays to contain SNR values. snrarr = [] nnrarr = [] # Make first data point of the average imgdif = img_snr-img_reference_snr #Select the data points where signal and noise is calculated from: imgcut = imgdif[xmindata:xmaxdata,zmindata:zmaxdata] imgcutnoise = imgdif[0:20,0:20] #If debug_box=True, set the pixel values corresponding to the SNR boxes to 0. if debug_box: imgdif[xmindata:xmaxdata,zmindata:zmaxdata]=0 imgdif[0:20,0:20]=0 imgcut_reference_snr=img_reference_snr[xmindata:xmaxdata,-1-zlen:-1] imgcutnoise_reference_snr = img_reference_snr[0:20,0:20] #For debugging. extentcut = [xmindata,xmaxdata,zmindata,zmaxdata] snr = snrfunc(imgcut,imgcutnoise) snrref = snrfunc(imgcut_reference_snr,imgcutnoise_reference_snr) snrarr.append(snr) nnrarr.append(snrref) #Loop over nmean for i in range(1,nmean): #Construct qstem objects again for use in the averaging img_snr,img_wave_snr,defocus_value=IMG_sim(Nanoparticlesnr,SNRparams) img_reference_snr,img_wave_reference_snr,defocus_value=IMG_sim(Referencesnr,SNRparams) #calculate SNR and NNR and append to array imgdif = img_snr-img_reference_snr imgcut = imgdif[xmindata:xmaxdata,zmindata:zmaxdata] imgcutnoise = imgdif[0:20,0:20] #imgcut_reference_snr=img_reference_snr[xmindata:xmaxdata,zmindata:zmaxdata] imgcut_reference_snr=img_reference_snr[xmindata:xmaxdata,-1-zlen:-1] imgcutnoise_reference_snr = img_reference_snr[0:20,0:20] extentcut = [xmindata,xmaxdata,zmindata,zmaxdata] snr = snrfunc(imgcut,imgcutnoise) snrref = snrfunc(imgcut_reference_snr,imgcutnoise_reference_snr) snrarr.append(snr) nnrarr.append(snrref) #Rotate and tilt back Nanoparticlesnr.rotate(-tilt,[1,0,0],center="COU") Referencesnr.rotate(-tilt,[1,0,0],center="COU") Referencesnr.rotate(-rotation,[0,1,0],center='COU') Nanoparticlesnr.rotate(-rotation,[0,1,0],center='COU') Nanoparticlesnr.rotate([0,1,0],temsurface,center='COU') Referencesnr.rotate([0,1,0],temsurface,center='COU') finalsnr = np.average(snrarr) finalsnrdb = 10*math.log10(finalsnr) finalnnr = np.average(nnrarr) finalnnrdb = 10*math.log10(finalnnr) print('Average SNR: '+str(finalsnr)) print('Average SNR in dB:' +str(finalsnrdb)) print('Average reference NNR: ' + str(finalnnr)) print('Average reference NNR in dB: ' +str(finalnnrdb)) #If plot=True, plot the different pixel arrays used in the calculation of SNR: if(plot): figimgsnr, axs = plt.subplots(1,3,figsize=(10,7),dpi=300) axs[0].imshow(img_snr.T,extent=img_wave_snr.get_extent(),cmap='gray',interpolation='nearest',origin='lower') axs[1].imshow(img_reference_snr.T,extent=img_wave_reference_snr.get_extent(),cmap='gray',interpolation='nearest',origin='lower') axs[2].imshow(imgdif.T,extent=img_wave_reference_snr.get_extent(),cmap='gray',interpolation='nearest',origin='lower') figsnr = plt.figure(figsize=(5,4),dpi=200) x = np.arange(nmean) plt.plot(x,snrarr,label='S/N ratio',linewidth=2,marker='s',color='blue') plt.plot(x,nnrarr,label='N/N ratio',linewidth=2,marker='o',color='red') plt.axhline(y=np.average(snrarr), xmin=0, xmax=nmean, color='green',linestyle='--',label='Average S/N:\n {:.3} dB'.format(finalsnrdb)) plt.axhline(y=np.average(nnrarr), xmin=0, xmax=nmean, color='black',linestyle='--',label='Average N/N:\n {:.3} dB'.format(finalnnrdb)) plt.rcParams['mathtext.fontset'] = 'cm' plt.rcParams['font.family'] = 'serif' plt.xlabel('Data points') plt.ylabel('Ratio value') plt.title('Average value of S/N-ratio') plt.legend() #Depending on what is needed, return the following objects: return snrarr,nnrarr,finalsnr,finalsnrdb,img_snr,img_reference_snr,img_wave_snr,img_wave_reference_snr
cell=atoms.get_cell() cell[1,0]=0 atoms.set_cell(cell) atoms.wrap() # wrap atoms outside the unit cell atoms.center() # center the atoms in the unit cell #atoms_plot(atoms,direction=1,scale_atoms=.5) atoms*=(3,3,1) scan_range=[[cell[0,0],2*cell[0,0],30], [cell[1,1],2*cell[1,1],30]] qstem = PyQSTEM('STEM') qstem.set_atoms(atoms) resolution = (0.02,0.02) # resolution in x and y-direction [Angstrom] samples = (300,300) # samples in x and y-direction defocus = -10 # defocus [Angstrom] v0 = 300 # acceleration voltage [keV] alpha = 15 # convergence angle [mrad] astigmatism = 0 # astigmatism magnitude [Angstrom] astigmatism_angle = 30 # astigmatism angle [deg.] aberrations = {'a33': 0, 'phi33': 60} # higher order aberrations [Angstrom] or [deg.] qstem.build_probe(v0,alpha,(300,300),resolution=(0.02,0.02),defocus=defocus,astig_mag=astigmatism, astig_angle=astigmatism_angle,aberrations=aberrations) wave=qstem.get_wave()
#divider = make_axes_locatable(ax2) #cax2 = divider.append_axes("right", size="5%", pad=0.05) #plt.colorbar(im,cax=cax2,label='e/Angstrom**2') #plt.tight_layout() #plt.show() print('Total charge (in elementary charges):', np.sum(rho * Lx * Ly * Lz / (Nx * Ny * Nz))) V = poisson_solver(rho, atoms, smooth=0, units='QSTEM') V_dft = create_potential_slices(V, 10, (Lx, Ly, Lz)) V_dft.array = np.tile(V_dft.array, (3, 3, 1)) tiled_atoms = atoms * (3, 3, 1) qstem = PyQSTEM('STEM') qstem.set_atoms(tiled_atoms) cell = atoms.get_cell() scan_range = [[cell[0, 0], 2 * cell[0, 0], 25], [cell[1, 1], 2 * cell[1, 1], 25]] resolution = (0.02, 0.02) # resolution in x and y-direction [Angstrom] samples = (300, 300) # samples in x and y-direction defocus = -10 # defocus [Angstrom] v0 = 300 # acceleration voltage [keV] alpha = 15 # convergence angle [mrad] astigmatism = 0 # astigmatism magnitude [Angstrom] astigmatism_angle = 0 # astigmatism angle [deg.] aberrations = { 'a33': 0, 'phi33': 0
[0, 0, 0, 1]] # QSTEM requires a right-angled unit cell atoms = Graphite(symbol='C', latticeconstant={ 'a': 2.46, 'c': 6.70 }, directions=directions, size=(2, 1, 1)) del atoms[atoms.get_positions()[:, 2] < atoms.get_cell()[2, 2] / 2] # delete the one of the layers in the graphite unit cell atoms.wrap() atoms.center(vacuum=2, axis=2) qstem = PyQSTEM('TEM') qstem.set_atoms(atoms) v0 = 300 qstem.build_wave('plane', v0, (100, 100)) wave = qstem.get_wave() #wave.view() #plt.show() qstem.build_potential(5) potential = qstem.get_potential_or_transfunc() potential.view(method='real')
from pyqstem.util import atoms_plot from pyqstem import PyQSTEM from pyqstem.potentials import poisson_solver,create_potential_slices mpl.rc('font',**{'size' : 13}) rho=np.load('test/graphene.npy') # all-electron density from GPAW using LDA atoms=read('test/graphene.cif',index=0) # atomic configuration Lx,Ly,Lz=np.diag(atoms.get_cell()) Nx,Ny,Nz=rho.shape V=poisson_solver(rho,atoms,smooth=0,units='QSTEM') V_dft=create_potential_slices(V,10,(Lx,Ly,Lz)) qstem=PyQSTEM('TEM') qstem.set_atoms(atoms) qstem.build_wave('plane',80,(Nx,Ny)) qstem.build_potential(1) print(qstem.get_potential_samples()) V_qstem=qstem.get_potential_or_transfunc() V_qstem.view(method='real') print(atoms.get_cell()) print(V_qstem.sampling) print(Lz/10.) qstem.run()
a = 2.64 atoms = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[a, a, a, 90, 90, 90]) #atoms_plot(atoms,direction=1,scale_atoms=.5) cell = atoms.get_cell() atoms *= (15, 15, 20) #view(atoms) scan_range = [[cell[0, 0], 2 * cell[0, 0], 30], [cell[1, 1], 2 * cell[1, 1], 30]] qstem = PyQSTEM('CBED') qstem.set_atoms(atoms) resolution = (0.02, 0.02) # resolution in x and y-direction [Angstrom] samples = (400, 400) # samples in x and y-direction defocus = 0 # defocus [Angstrom] v0 = 200 # acceleration voltage [keV] alpha = 8 # convergence angle [mrad] astigmatism = 0 # astigmatism magnitude [Angstrom] astigmatism_angle = 30 # astigmatism angle [deg.] aberrations = { 'a33': 0, 'phi33': 60 } # higher order aberrations [Angstrom] or [deg.] qstem.build_probe(v0,