diff --git a/configs/default.toml b/configs/default.toml new file mode 100644 index 0000000..7a57264 --- /dev/null +++ b/configs/default.toml @@ -0,0 +1,42 @@ +title = "Default configuration" + +[scan] +scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather; "states"="STATES" -- dIdV scancs at the eigenenergies, beware it still uses all other states for calculations # +tip_type = 'fixed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # +scan_window = [[0, 0, 10], [15.9, 15.9, 11.9]] # [[x0, y0, z0], [x1, y1, z1]] -- scan window in Angstroms, used for fixed scan # +scan_dim = [128, 128, 20] # [Nx, Ny, Nz] -- number of points in [x, y, z] used for fixed scan # +V = -0.5 # !!!! V = Vmin for SCAN !!!! # +V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # +dV = 0.1 # # voltage step , dV <= 0.1 V # +eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # +tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # +sample_orbs = 'sp' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # + +[input] +path = './' # where are files fron DFT code # +dft_code = 'aims' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # +geometry_file = 'geometry.in' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # +pbc = [0,0] # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # +lvs = [[1,0,0],[0,1,0],[0,0,1]] # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # +spin = false # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # +cp2k_name = 'crazy_mol' # Name used in CP2K calculations or GPAW calc # +Q = 0.0 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # +K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # +data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # + +[advanced] +cut_atoms = -1 # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # +lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # +lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # +work_function = 5.0 # 5.0 eV is standart # +work_function_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # +fermi = 0.0 # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # +cut_min = -3 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # +cut_max = 3 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # + +[output] +plot_atoms = false # True / False -- plot "png" images (2D constant height) # +PNG = false # True / False -- write ".xyz" WSxM files (2D constant height) # +WSxM = false # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # +NPY = true # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # +XSF = false # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # diff --git a/ppstm_run.py b/ppstm_run.py new file mode 100644 index 0000000..ed5f58a --- /dev/null +++ b/ppstm_run.py @@ -0,0 +1,92 @@ +import os +import sys +import tomli + +from pyPPSTM import basUtils as bU +from pyPPSTM import ReadSTM +from pyPPSTM import STMutils +from pyPPSTM import visualization + +def main(config: dict): + # ppafm needed for relaxed tip scans and npy+xsf output + tip_type = config['scan']['tip_type'] + npy_or_xsf_output = config['output']['NPY'] or config['output']['XSF'] + if tip_type in ['relaxed', 'r'] or npy_or_xsf_output: + try: + import ppafm.io as io + except ImportError: + raise ImportError("ppafm is required for relaxed tip scans and NPY/XSF output.") + + # Set tip coefficients + tip_orb = config['scan']['tip_orb'] + tip_coeffs = STMutils.get_tip_coefficients(tip_orb) + print(f"Set tip coefficients for {tip_orb}: {tip_coeffs}") + + # Read eigenenergies and coefficients + eigenenergies, coefs, atoms = ReadSTM.read_dft(config) + print(f"Read eigenenergies and coefficients.") + + # Set up atom plotting if enabled + if config['output']['plot_atoms']: + try: + geom_plot, _, _ = bU.loadAtoms( + os.path.join( + config['input']['path'], + 'input_plot.xyz' + ) + ) + except FileNotFoundError: + geom_plot = None + print("WARNING: Atom plotting disabled due to missing input_plot.xyz file.") + + # Get tip positions + ( + tip_r, + tip_r0, + lvec, + extent, + atomic_head_or_info + ) = STMutils.get_tip_positions(config) + print(f"Tip positions read for a {config['scan']['tip_type']} scan.") + + # Run STM scan + current, didv = STMutils.run_stm_scan( + config, + eigenenergies, + coefs, + tip_r, + atoms + ) + print(f"STM scan complete for scan type {config['scan']['scan_type']}.") + + # Get voltages and names + voltages, names = visualization.get_voltages_and_names(config, eigenenergies) + + # Output results + if config['output']['PNG']: + visualization.plot_png(config, current, didv, voltages, names, lvec, extent, geom_plot) + print(f"PNG output complete.") + if config['output']['WSxM']: + visualization.plot_wsxm(config, current, didv, voltages, names, tip_r0) + print(f"WSXM output complete.") + if config['output']['XSF']: + visualization.save_xsf(config, current, didv, voltages, names, geom_plot, lvec) + print(f"XSF output complete.") + if config['output']['NPY']: + visualization.save_npy(config, current, didv, voltages, names, lvec, atomic_head_or_info) + print(f"NPY output complete.") + + print(f"Output finished, exiting.") + +if __name__=='__main__': + # Get config file from command line + config_file = sys.argv[1] + + # Load config file + with open(config_file, 'rb') as f: + config = tomli.load(f) + + print(f"Loaded config from {config_file}") + print(f"Config: {config}") + + main(config) diff --git a/pyPPSTM/ReadSTM.py b/pyPPSTM/ReadSTM.py index 357dcdd..965cdaa 100644 --- a/pyPPSTM/ReadSTM.py +++ b/pyPPSTM/ReadSTM.py @@ -12,6 +12,8 @@ import time +from typing import Tuple + # this library has functions for reading STM coefficients and make a grid for non-relaxed 3D scan # global variables: @@ -201,18 +203,16 @@ def to_fermi(eig, fermi, orig_fermi=0.0): eig -= fermi return eig; -def cut_eigenenergies(eig): +def cut_eigenenergies(eig, cut_min, cut_max): ''' Removes eigenstates (molecular orbitals) that are far from the energy important for scanning - ''' - j = 1 - global n_min_ , n_max_ - for i in eig: - n_min_ = j if (i < cut_min_ ) else n_min_ - n_max_ = j if (i < cut_max_ ) else n_max_ - j += 1 - assert (n_min_ < n_max_), "no orbitals left for dI/dV" - return eig[n_min_:n_max_]; + ''' + global n_min_, n_max_ + n_min_ = sum(eig < cut_min) + n_max_ = sum(eig < cut_max) + + mask = (eig > cut_min) & (eig < cut_max) + return eig[mask] # procedure for handling the coefficients: @@ -307,7 +307,7 @@ def read_AIMS_all(name = 'KS_eigenvectors.band_1.kpt_1.out', geom='geometry.in', eig[i] = float(pre_eig[i]) del pre_eig, tmp; eig = to_fermi(eig, fermi, orig_fermi=0.0) - eig = cut_eigenenergies(eig) + eig = cut_eigenenergies(eig, cut_min, cut_max) print("eigenenergies read") # ****** TO BE REMOVED ******** """ @@ -399,7 +399,7 @@ def read_GPAW_all(name = 'OUTPUT.gpw', fermi = None, orbs = 'sp', pbc=(1,1), ima eig = calc.get_eigenvalues(kpt=0, spin=0, broadcast=True) at_num = slab.get_atomic_numbers() eig = to_fermi(eig, fermi, orig_fermi=calc.get_fermi_level()) - eig = cut_eigenenergies(eig) + eig = cut_eigenenergies(eig, cut_min, cut_max) print("eigen-energies read") # obtaining the LCAO coefficients (automatically removed unwanted states - molecular orbitals - and atoms) coef = np.zeros((n_max_-n_min_,num_at_,Ynum_)) @@ -475,7 +475,7 @@ def read_FIREBALL_all(name = 'phi_' , geom='answer.bas', fermi=None, orbs = 'sp' assert (len(eig)==n_bands), "number of bands wrongly specified" eig = to_fermi(eig, fermi, orig_fermi=float(pre_eig[2])) del pre_eig; - eig = cut_eigenenergies(eig) + eig = cut_eigenenergies(eig, cut_min, cut_max) print("eigen-energies read") print(" loading the LCAO coefficients") @@ -540,7 +540,7 @@ def read_CP2K_all(name, fermi=None, orbs='sp', pbc=(1,1), imaginary = False, cut # select relevant MOs eig = to_fermi(eig, fermi, orig_fermi=fermi_energy) - eig = cut_eigenenergies(eig) + eig = cut_eigenenergies(eig, cut_min, cut_max) # copy coefficients of relevant MOs coef = np.zeros((n_max_-n_min_,num_at_,Ynum_)) @@ -686,4 +686,148 @@ def read_cp2k_MO_file(fn, spin): # done return labels, evals, occs, evecs, fermi_energy -############## END OF LIBRARY ################################## + +def read_dft( + config: dict +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """ + Reads DFT input using the configuration dictionary. + + Args: + config (dict): Configuration dictionary. + + Returns: + Tuple[np.ndarray, np.ndarray, np.ndarray]: Eigenvalues, coefficients, and atomic positions. + """ + + input_params = config['input'] + scan_params = config['scan'] + advanced_params = config['advanced'] + + path = input_params["path"] + geometry_file = input_params["geometry_file"] + dft_code = input_params["dft_code"] + cp2k_name = input_params["cp2k_name"] + spin = input_params["spin"] + + common_params = { + 'fermi': advanced_params['fermi'], + 'pbc': input_params['pbc'], + 'orbs': scan_params['sample_orbs'], + 'cut_min': advanced_params['cut_min'], + 'cut_max': advanced_params['cut_max'], + 'cut_at': advanced_params['cut_atoms'], + 'lower_atoms': advanced_params['lower_atoms'], + 'lower_coefs': advanced_params['lower_coefs'] + } + + if input_params['dft_code'].lower() in ('fireball', 'cp2k'): + lvs = input_params['lvs'] + pbc = input_params['pbc'] + if isinstance(lvs, (list, tuple, np.ndarray)): + cell = np.array( + [ + [lvs[0][0], lvs[0][1], 0.0], + [lvs[1][0], lvs[1][1], 0.0], + [0.0, 0.0, 99.9] + ] + ) if (len(lvs) == 2) else lvs + elif isinstance(lvs, (str)): + cell = np.loadtxt(lvs) + elif pbc == [0, 0]: + cell = np.zeros((3,3)) + else: + raise ValueError("pbc requested, but lvs not specified") + + if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): + eigEn, coefs, Ratin = read_FIREBALL_all( + name=path+'phik_0001_', + geom=path+geometry_file, + lvs=cell, + **common_params + ) + + elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): + eigEn, coefs, Ratin = read_GPAW_all( + name=path+cp2k_name+'.gpw', + **common_params + ) + + elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): + if ((spin == None) or (spin == False)): + name = 'KS_eigenvectors.band_1.kpt_1.out' + elif spin in ['up', 'alpha']: + name = 'KS_eigenvectors_up.band_1.kpt_1.out' + elif spin in ['down', 'beta', 'dn']: + name = 'KS_eigenvectors_dn.band_1.kpt_1.out' + elif spin == 'both': + name_up = 'KS_eigenvectors_up.band_1.kpt_1.out' + name_dn = 'KS_eigenvectors_dn.band_1.kpt_1.out' + else : + raise ValueError(f"Unknown spin: {spin}") + + if spin != 'both': + eigEn, coefs, Ratin = read_AIMS_all( + name=path+name, + geom=path+geometry_file, + **common_params + ) + else: + eigEn1, coefs1, Ratin = read_AIMS_all( + name=path+name_up, + geom=path+geometry_file, + **common_params + ) + eigEn2, coefs2, Ratin = read_AIMS_all( + name=path+name_dn, + geom=path+geometry_file, + **common_params + ) + eigEn = np.concatenate((eigEn1, eigEn2), axis=0) + coefs = np.concatenate((coefs1, coefs2), axis=0) + + elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): + if ((spin == None)or(spin == False)): + eigEn, coefs, Ratin = read_CP2K_all( + name = path + cp2k_name , + lvs=cell, + **common_params + ) + elif ((spin == 'up')or(spin == 'alpha')): + eigEn, coefs, Ratin = read_CP2K_all( + name=path+cp2k_name, + lvs=cell, + spin='alpha', + **common_params + ) + elif (spin == 'both'): + eigEn1, coefs1, Ratin = read_CP2K_all( + name=path+cp2k_name, + lvs=cell, + spin='alpha', + **common_params + ) + eigEn2, coefs2, Ratin = read_CP2K_all( + name = path + cp2k_name , + lvs=cell, + spin='beta', + **common_params + ) + eigEn = np.concatenate((eigEn1, eigEn2), axis=0) + coefs = np.concatenate((coefs1, coefs2), axis=0) + elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): + eigEn, coefs, Ratin = read_CP2K_all( + name=path+cp2k_name, + lvs=cell, + spin='beta', + **common_params + ) + else : + raise ValueError(f"Unknown spin: {spin}") + + else: + raise ValueError(f"Unknown DFT code: {dft_code}") + + return eigEn, coefs, Ratin + + ############## END OF LIBRARY ################################## diff --git a/pyPPSTM/STMutils.py b/pyPPSTM/STMutils.py new file mode 100644 index 0000000..ad29fe9 --- /dev/null +++ b/pyPPSTM/STMutils.py @@ -0,0 +1,242 @@ +import os +import numpy as np + +from typing import Dict, Tuple + +import pyPPSTM.ReadSTM as RS +import pyPPSTM.ProbeSTM as PS +import pyPPSTM.basUtils as BU + +def get_tip_coefficients(tip_orb: str) -> Dict: + """ + Returns list of coefficients for tip orbitals. + 's' -- s, + 'pxy' -- px & py, + 'spxy' -- 50% s & 50% pxy, + '5spxy' -- 5% s & 95% pxy, + '10spxy' -- 10% s & 90% pxy, + 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)), + 'pz' -- pz, + For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz + + Args: + tip_orb (str): The tip orbital. + + Returns: + coeffs (Dict): The list of coefficients for the tip orbital. + """ + tc = { + "s": 0.0, + "px": 0.0, + "py": 0.0, + "pz": 0.0, + "dz2": 0.0, + "dxz": 0.0, + "dyz": 0.0 + } + # [s, px, py, pz, dz2, dxz, dyz ] + if (tip_orb == 's'): + tc['s'] = 1.0 + elif (tip_orb == 'pxy'): + tc['px'] = 0.5 + tc['py'] = 0.5 + elif (tip_orb == 'spxy'): + tc['s'] = 0.5 + tc['px'] = 0.25 + tc['py'] = 0.25 + elif (tip_orb == '5spxy'): + tc['s'] = 0.05 + tc['px'] = 0.475 + tc['py'] = 0.475 + elif (tip_orb == '10spxy'): + tc['s'] = 0.10 + tc['px'] = 0.45 + tc['py'] = 0.45 + elif (tip_orb == 'CO'): + tc['s'] = 0.15 + tc['px'] = 0.5 + tc['py'] = 0.5 + elif (tip_orb == 'pz'): + tc['pz'] = 1.0 + elif (tip_orb == 'dz2'): + tc['dz2'] = 1.0 + elif (tip_orb == 'dxzyz'): + tc['dxz'] = 0.5 + tc['dyz'] = 0.5 + else: + raise ValueError(f"Invalid tip orbital: {tip_orb}") + return tc + +def get_tip_positions(config: dict): + """ + Get the tip positions for relaxed or fixed scan. + + Args: + config (dict): The configuration dictionary. + + Returns: + tip_r (np.ndarray): The tip positions. + tip_r0 (np.ndarray): The initial tip positions. + lvec (np.ndarray): The lattice vectors. + extent (tuple): The extent of the scan. + atomic_info_or_head (tuple): The atomic information or head. + """ + tip_type = config['scan']['tip_type'] + + if ((tip_type =='relaxed') or (tip_type == 'r')): + try: + import ppafm.io as io + except ImportError: + raise ImportError("ppafm is required for relaxed tip scans.") + + Q = config['input']['Q'] + K = config['input']['K'] + data_format = config['input']['data_format'] + + path_pos = os.path.join( + config['input']['path'], + f"Q{Q:1.2f}K{K:1.2f}/" + ) + tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( + path_pos+'PPpos', + data_format=data_format + ) + + extent = ( + lvec[0,0], lvec[0,0]+lvec[1,0], + lvec[0,1], lvec[0,1]+lvec[2,1] + ) + + dx=lvec[1,0]/(nDim[2]-1) + dy=lvec[2,1]/(nDim[1]-1) + dz=lvec[3,2]/(nDim[0]-1) + tip_r0 = RS.mkSpaceGrid( + lvec[0,0], lvec[0,0]+lvec[1,0], dx, + lvec[0,1], lvec[0,1]+lvec[2,1], dy, + lvec[0,2], lvec[0,2]+lvec[3,2], dz + ) + + else: + sw = np.asarray(config['scan']['scan_window']) + scan_dim = np.asarray(config['scan']['scan_dim']) + extent = ( + sw[0,0], sw[1,0], + sw[0,1], sw[1,1], + ) + dx = (sw[1,0]-sw[0,0])/scan_dim[0] + dy = (sw[1,1]-sw[0,1])/scan_dim[1] + dz = (sw[1,2]-sw[0,2])/scan_dim[2] + tip_r = RS.mkSpaceGrid( + sw[0,0], sw[1,0], dx, + sw[0,1], sw[1,1], dy, + sw[0,2], sw[1,2], dz + ) + lvec = np.asarray([ + [sw[0,0], sw[0,1], sw[0,2]], + [sw[1,0]-sw[0,0], 0., 0.], + [0., sw[1,1]-sw[0,1], 0.], + [0., 0., sw[1,2]-sw[0,2]] + ]) + tip_r0 = tip_r + + if config['output']['plot_atoms']: + atoms, _, _ = BU.loadAtoms( + os.path.join( + config['input']['path'], + 'input_plot.xyz' + ) + ) + atomic_info_or_head = (atoms, lvec) + else: + atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) + + return tip_r, tip_r0, lvec, extent, atomic_info_or_head + +def run_stm_scan( + config: dict, + eigs: np.ndarray, + coefs: np.ndarray, + tip_positions: np.ndarray, + atoms: np.ndarray, +) -> Tuple: + """ + Helper function for running the STM calculations for a given configuration. + + Args: + config (dict): The configuration dictionary. + eigs (np.ndarray): Eigenenergies. + coefs (np.ndarray): KS coefficients. + tip_positions (np.ndarray): Tip positions. + atoms (np.ndarray): Atom positions, types, charges. + + Returns: + result (Tuple): (STM, didv) - The result of the STM calculations. + """ + + V = config['scan']['V'] + V_max = config['scan']['V_max'] + dV = config['scan']['dV'] + + scan_type = config['scan']['scan_type'] + didv_args = { + 'WF': config['advanced']['work_function'], + 'eta': config['scan']['eta'], + 'eig': eigs, + 'R': tip_positions, + 'Rat': atoms, + 'coes': coefs, + 'orbs': config['scan']['sample_orbs'], + } + tip_coefficients = get_tip_coefficients(config['scan']['tip_orb']) + + if scan_type in ['didv', 'dIdV', 'didv-single']: + didv = PS.dIdV( + V, + **didv_args, + **tip_coefficients, + ) + # Add one dimension to the didv array + didv = didv[None, :] + current = None + + elif scan_type in ['states', 'STATES']: + states = np.sort(eigs) + mask = (states >= V) & (states <= V_max) + states = states[mask] + + didvs = [] + for state in states: + didv = PS.dIdV( + V=state, + **didv_args, + **tip_coefficients, + ) + didvs.append(didv) + didv = np.stack(didvs, axis=0) + current = None + + elif scan_type in ['STM', 'STM-single']: + nV = abs(V/dV)+1 + current = PS.STM( + V, + nV, + WF_decay=config['advanced']['work_function_decay'], + **didv_args, + **tip_coefficients, + ) + # Add one dimension to the current array + current = current[None, :] + didv = None + elif scan_type in ['v-scan', 'V-scan', 'Voltage-scan']: + current, didv = PS.MSTM( + V, + V_max, + dV=dV, + WF_decay=config['advanced']['work_function_decay'], + **didv_args, + **tip_coefficients, + ) + else: + raise ValueError(f"Invalid scan type: {scan_type}") + + return current, didv diff --git a/pyPPSTM/visualization.py b/pyPPSTM/visualization.py new file mode 100644 index 0000000..564d3ed --- /dev/null +++ b/pyPPSTM/visualization.py @@ -0,0 +1,169 @@ +import numpy as np +import matplotlib.pyplot as plt + +from pyPPSTM import elements +from pyPPSTM import basUtils as Bu + + +def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): + plt.fig = plt.gcf() + es = atoms[0]; xs = atoms[1]; ys = atoms[2] + for i in range(len(xs)): + fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## + if not edge: + ec=fc + circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) + plt.fig.gca().add_artist(circle) + +def plotGeom( atoms=None, atomSize=0.1 ): + if atoms is not None: + plotAtoms( atoms, atomSize=atomSize ) + +def get_voltages_and_names(config, eigs): + scan_type = config['scan']['scan_type'] + + V = config['scan']['V'] + V_max = config['scan']['V_max'] + dV = config['scan']['dV'] + + if scan_type in ['states', 'STATES']: + states = np.sort(eigs) + mask = (states >= V) & (states <= V_max) + voltages = states[mask] + names = [f"{V:.5f}" for V in voltages] + else: + voltages = np.arange(V, V_max+0.001 ,dV) + names = [f"{V:.1f}" for V in voltages] + + return voltages, names + +def get_number_of_voltages_and_heights(config, current, didv): + scan_type = config['scan']['scan_type'] + + if scan_type in ['STM', 'STM-single']: + nV = current.shape[0] + nH = current.shape[1] + else: + nV = didv.shape[0] + nH = didv.shape[1] + + return nV, nH + +def plot_png(config, current, didv, voltages, names, lvec, extent, geom_plot): + tip_type = config['scan']['tip_type'] + tip_orb = config['scan']['tip_orb'] + eta = config['scan']['eta'] + work_function = config['advanced']['work_function'] + wf_decay = config['advanced']['work_function_decay'] + + nV, nH = get_number_of_voltages_and_heights(config, current, didv) + for vv in range(nV): + for k in range(nH): + #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb + name_plot = f'{names[vv]};height:{k};tip:{tip_type};{tip_orb}' + if didv is not None: + # ploting part here: + plt.figure(figsize=(0.5*lvec[1,0], 0.5*lvec[2,1])) + plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent, cmap='gray') + plotGeom(atoms=geom_plot) + plt.xlabel(r' Tip_x $\AA$') + plt.ylabel(r' Tip_y $\AA$') + plt.title("dIdV:"+name_plot) + save_name = f'didv_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function-voltages[vv]*wf_decay}_eta_{eta:.1f}_{k:03d}.png' + plt.savefig(save_name, bbox_inches='tight') + plt.close() + if current is not None: + # ploting part here: + plt.figure(figsize=(0.5*lvec[1,0], 0.5*lvec[2,1])) + plt.imshow(current[vv,k,:,:], origin='lower', extent=extent, cmap='gray') + plotGeom(atoms=geom_plot) + plt.xlabel(r' Tip_x $\AA$') + plt.ylabel(r' Tip_y $\AA$') + plt.title("STM:"+name_plot) + save_name = f'STM_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function:.1f}_WF_decay_{wf_decay:.1f}_eta_{eta:.1f}_{k:03d}.png' + plt.savefig(save_name, bbox_inches='tight') + plt.close() + +def plot_wsxm(config, current, didv, voltages, names, tip_r0): + tip_type = config['scan']['tip_type'] + tip_orb = config['scan']['tip_orb'] + eta = config['scan']['eta'] + work_function = config['advanced']['work_function'] + wf_decay = config['advanced']['work_function_decay'] + nV, nH = get_number_of_voltages_and_heights(config, current, didv) + + for vv in range(nV): + for k in range(nH): + if didv is not None: + name_file = f'didv_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function-voltages[vv]*wf_decay}_eta_{eta:.1f}_{k:03d}.wsxm' + tmp_curr=didv[vv,k,:,:].flatten() + out_curr=np.zeros((len(tmp_curr),3)) + out_curr[:,0]=tip_r0[k,:,:,0].flatten() + out_curr[:,1]=tip_r0[k,:,:,1].flatten() + out_curr[:,2]=tmp_curr.copy() + f=open(name_file,'w') + print("WSxM file copyright Nanotec Electronica", file=f) + print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) + print("X[A] Y[A] Z[A]", file=f) + print("", file=f) + np.savetxt(f, out_curr) + f.close() + + if current is not None: + name_file = f'STM_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function:.1f}_WF_decay_{wf_decay:.1f}_eta_{eta:.1f}_{k:03d}.wsxm' + tmp_curr=current[vv,k,:,:].flatten() + out_curr=np.zeros((len(tmp_curr),3)) + out_curr[:,0]=tip_r0[k,:,:,0].flatten() + out_curr[:,1]=tip_r0[k,:,:,1].flatten() + out_curr[:,2]=tmp_curr.copy() + f=open(name_file,'w') + print("WSxM file copyright Nanotec Electronica", file=f) + print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) + print("X[A] Y[A] Z[A]", file=f) + print("", file=f) + np.savetxt(f, out_curr) + f.close() + +def save_xsf(config, current, didv, voltages, names, geom_plot, lvec): + try: + import ppafm.io as io + except ImportError: + raise ImportError("ppafm needed for XSF output") + + tip_type = config['scan']['tip_type'] + tip_orb = config['scan']['tip_orb'] + eta = config['scan']['eta'] + work_function = config['advanced']['work_function'] + wf_decay = config['advanced']['work_function_decay'] + + xsf_head = Bu.At2XSF(geom_plot) if geom_plot is not None else io.XSF_HEAD_DEFAULT + nV, nH = get_number_of_voltages_and_heights(config, current, didv) + + for vv in range(nV): + if didv is not None: + name_file = f'didv_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function-voltages[vv]*wf_decay}_eta_{eta:.1f}.xsf' + io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) + if current is not None: + name_file = f'STM_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function:.1f}_WF_decay_{wf_decay:.1f}_eta_{eta:.1f}.xsf' + io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) + +def save_npy(config, current, didv, voltages, names, lvec, atomic_info_or_head): + try: + import ppafm.io as io + except ImportError: + raise ImportError("ppafm needed for NPY output") + tip_type = config['scan']['tip_type'] + tip_orb = config['scan']['tip_orb'] + eta = config['scan']['eta'] + work_function = config['advanced']['work_function'] + wf_decay = config['advanced']['work_function_decay'] + + nV, nH = get_number_of_voltages_and_heights(config, current, didv) + + for vv in range(nV): + if didv is not None: + name_file = f'didv_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function-voltages[vv]*wf_decay}_eta_{eta:.1f}' + io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) + if current is not None: + name_file = f'STM_{names[vv]}_tip_{tip_type}-{tip_orb}_WF_{work_function:.1f}_WF_decay_{wf_decay:.1f}_eta_{eta:.1f}' + io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) diff --git a/tests/4N-coronene/PPSTM b/tests/4N-coronene/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/4N-coronene/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/4N-coronene/PPSTM_simple.py b/tests/4N-coronene/PPSTM_simple.py deleted file mode 100755 index 05b319a..0000000 --- a/tests/4N-coronene/PPSTM_simple.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 1 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather; "states"="STATES" -- dIdV scancs at the eigenenergies, beware it still uses all other states for calculations # -tip_type = 'relaxed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.5 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'sp' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'fireball' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'crazy_mol.xyz' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (0,0) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = None # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'crazy_mol' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [ 0.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [ 0.0, 15.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 10.0, 12.0, 0.1 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.50 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = True # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/4N-coronene/PPSTM_simple_pxy.py b/tests/4N-coronene/PPSTM_simple_pxy.py deleted file mode 100755 index 00eabe4..0000000 --- a/tests/4N-coronene/PPSTM_simple_pxy.py +++ /dev/null @@ -1,435 +0,0 @@ -#!/usr/bin/python3 -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 1 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -# scan_type: 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -scan_type = 'v-scan' -# tip_type: 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -tip_type = 'relaxed' -# V: voltage of !!!! V = Vmin for SCANs (Vscan, states) !!!! # -V = -0.5 -# V_max: max voltages for SCANs ; note: V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -V_max = +0.5 -# dV: voltage step , dV <= 0.1 V ; for Vscan and STM only# -dV = 0.1 -# eta: Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -eta = 0.1 -# WF_decay: Only for STM or Vscan: 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -WF_decay = 0.5 -# tip_orb: 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -tip_orb = 'pxy' -# sample_orbs: orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -sample_orbs = 'sp' -# dft_code: 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -dft_code = 'fireball' -# geometry_file: E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -geometry_file = 'crazy_mol.xyz' -# pbc: (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -pbc = (0, 0) -# lvs: None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -lvs = None -# spin: None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -spin = None -# cp2k_name: Name used in CP2K calculations or GPAW calc # -cp2k_name = 'crazy_mol' -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [0.0, 20.0, 0.25] # [xmin, xmax, dx] # -y = [0.0, 15.0, 0.25] # [ymin, ymax, dy] # -# !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -z = [10.0, 12.0, 0.1] -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -# Q: charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -Q = 0.00 -# K: x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -K = 0.50 -# data_format: 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -data_format = 'npy' -# -# *****Output options ****** -# -# PNG: True / False -- plot "png" images (2D constant height) # -PNG = False -# WSXM: True / False -- write ".xyz" WSxM files (2D constant height) # -WSxM = False -XSF = True # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = True # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -# plot_atoms: True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -plot_atoms = True -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -# fermi: None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -fermi = None -# cut_min: cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_min = -2.5 -# cut_out: cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -cut_max = +2.5 -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import sys -import os -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import pyPPSTM.ReadSTM as RS -import pyPPSTM as PS -import numpy as np -import matplotlib -# Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -matplotlib.use('Agg') -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r')): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert(PNG or WSxM or XSF or NPY), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1., 0., 0., 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0., 0.5, 0.5, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5, 0.25, 0.25, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - # [s, px, py, pz, dz2, dxz, dyz ] - tc = [0.05, 0.475, 0.475, 0., 0., 0., 0.] -elif (tip_orb == '10spxy'): - tc = [0.10, 0.45, 0.45, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15, 0.5, 0.5, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0., 0., 0., 1., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0., 0., 0., 0., 1., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0., 0., 0., 0., 0., 0.5, 0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit."); exit() - -# print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - # print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type == 'relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos = "Q%1.2fK%1.2f/" % (Q, K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( - path_pos+'PPpos', data_format=data_format) - extent = (lvec[0, 0], lvec[0, 0]+lvec[1, 0], - lvec[0, 1], lvec[0, 1]+lvec[2, 1]) - # print "DEBUG: extent", extent - print("PP postions imported") - dx = lvec[1, 0]/(nDim[2]-1); dy = lvec[2, 1] / \ - (nDim[1]-1); dz = lvec[3, 2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0, 0], lvec[0, 0]+lvec[1, 0], dx, lvec[0, 1], - lvec[0, 1]+lvec[2, 1], dy, lvec[0, 2], lvec[0, 2]+lvec[3, 2], dz) - # print "DEBUG: dx, dy, dz", dx, dy, dz - # print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0], x[1], y[0], y[1]) - tip_r = RS.mkSpaceGrid(x[0], x[1], x[2], y[0], - y[1], y[2], z[0], z[1], z[2]) - lvec = np.array([[x[0], y[0], z[0]], [x[1]-x[0], 0., 0.], - [0., y[1]-y[0], 0.], [0., 0., z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - # print "DEBUG: extent", extent - # print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or (dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or (dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0], lvs[0][1], 0.0], [lvs[1][0], lvs[1][1], 0.0], [ - 0.0, 0.0, 99.9]]) if len(lvs) == 2 else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0, 0)) or (pbc == (0., 0.))): - cell = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something.") - exit() - # print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or (dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name=files_path + 'phik_0001_', geom=files_path+geometry_file, lvs=cell, fermi=fermi, - orbs=sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs) - -elif ((dft_code == 'gpaw') or (dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all(name=files_path + cp2k_name + '.gpw', fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or (dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up') or (spin == 'alpha') or (spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down') or (spin == 'beta') or (spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else: - print("unknown spin, I'm going to sleep. Good Night") - exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name=files_path + name, geom=files_path + geometry_file, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name=files_path + name, geom=files_path + geometry_file, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or (dft_code == 'CP2K')): - if ((spin == None) or (spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up') or (spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down') or (spin == 'beta') or (spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else: - print("unknown spin, I'm going to sleep. Good Night") - exit() - -# print "DEBUG: eigEn.shape ", eigEn.shape -# print "DEBUG: coefs.shape ", coefs.shape -# print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ((scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([PS.dIdV(V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])]) - didv_b = True; WF_decay = 0.0; - # print "DEBUG: didv.shape ", didv.shape -elif ((scan_type == 'states') or (scan_type == 'STATES')): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([PS.dIdV(isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])]) - fst = False - else: - didv = np.append(didv, [PS.dIdV(isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])], axis=0) - # print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - # print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - # print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - # print "DEBUG: didv.shape ", didv.shape - # print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -# print "DEBUG: Voltages", Voltages -# print "DEBUG: namez", namez -# print "DEBUG: NoV", NoV -# print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - # print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/4N-coronene/PPSTM_simple_s.py b/tests/4N-coronene/PPSTM_simple_s.py deleted file mode 100755 index 34c2932..0000000 --- a/tests/4N-coronene/PPSTM_simple_s.py +++ /dev/null @@ -1,435 +0,0 @@ -#!/usr/bin/python3 -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 1 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -# scan_type: 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -scan_type = 'v-scan' -# tip_type: 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -tip_type = 'relaxed' -# V: voltage of !!!! V = Vmin for SCANs (Vscan, states) !!!! # -V = -0.5 -# V_max: max voltages for SCANs ; note: V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -V_max = +0.5 -# dV: voltage step , dV <= 0.1 V ; for Vscan and STM only# -dV = 0.1 -# eta: Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -eta = 0.1 -# WF_decay: Only for STM or Vscan: 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -WF_decay = 0.5 -# tip_orb: 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -tip_orb = 's' -# sample_orbs: orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -sample_orbs = 'sp' -# dft_code: 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -dft_code = 'fireball' -# geometry_file: E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -geometry_file = 'crazy_mol.xyz' -# pbc: (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -pbc = (0, 0) -# lvs: None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -lvs = None -# spin: None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -spin = None -# cp2k_name: Name used in CP2K calculations or GPAW calc # -cp2k_name = 'crazy_mol' -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [0.0, 20.0, 0.25] # [xmin, xmax, dx] # -y = [0.0, 15.0, 0.25] # [ymin, ymax, dy] # -# !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -z = [10.0, 12.0, 0.1] -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -# Q: charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -Q = 0.00 -# K: x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -K = 0.50 -# data_format: 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -data_format = 'npy' -# -# *****Output options ****** -# -# PNG: True / False -- plot "png" images (2D constant height) # -PNG = False -# WSXM: True / False -- write ".xyz" WSxM files (2D constant height) # -WSxM = False -XSF = True # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = True # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -# plot_atoms: True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -plot_atoms = True -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -# fermi: None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -fermi = None -# cut_min: cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_min = -2.5 -# cut_out: cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -cut_max = +2.5 -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import sys -import os -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import pyPPSTM.ReadSTM as RS -import pyPPSTM as PS -import numpy as np -import matplotlib -# Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -matplotlib.use('Agg') -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r')): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert(PNG or WSxM or XSF or NPY), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1., 0., 0., 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0., 0.5, 0.5, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5, 0.25, 0.25, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - # [s, px, py, pz, dz2, dxz, dyz ] - tc = [0.05, 0.475, 0.475, 0., 0., 0., 0.] -elif (tip_orb == '10spxy'): - tc = [0.10, 0.45, 0.45, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15, 0.5, 0.5, 0., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0., 0., 0., 1., 0., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0., 0., 0., 0., 1., 0., 0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0., 0., 0., 0., 0., 0.5, 0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit."); exit() - -# print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - # print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type == 'relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos = "Q%1.2fK%1.2f/" % (Q, K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( - path_pos+'PPpos', data_format=data_format) - extent = (lvec[0, 0], lvec[0, 0]+lvec[1, 0], - lvec[0, 1], lvec[0, 1]+lvec[2, 1]) - # print "DEBUG: extent", extent - print("PP postions imported") - dx = lvec[1, 0]/(nDim[2]-1); dy = lvec[2, 1] / \ - (nDim[1]-1); dz = lvec[3, 2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0, 0], lvec[0, 0]+lvec[1, 0], dx, lvec[0, 1], - lvec[0, 1]+lvec[2, 1], dy, lvec[0, 2], lvec[0, 2]+lvec[3, 2], dz) - # print "DEBUG: dx, dy, dz", dx, dy, dz - # print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0], x[1], y[0], y[1]) - tip_r = RS.mkSpaceGrid(x[0], x[1], x[2], y[0], - y[1], y[2], z[0], z[1], z[2]) - lvec = np.array([[x[0], y[0], z[0]], [x[1]-x[0], 0., 0.], - [0., y[1]-y[0], 0.], [0., 0., z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - # print "DEBUG: extent", extent - # print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or (dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or (dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0], lvs[0][1], 0.0], [lvs[1][0], lvs[1][1], 0.0], [ - 0.0, 0.0, 99.9]]) if len(lvs) == 2 else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0, 0)) or (pbc == (0., 0.))): - cell = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something.") - exit() - # print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or (dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name=files_path + 'phik_0001_', geom=files_path+geometry_file, lvs=cell, fermi=fermi, - orbs=sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs) - -elif ((dft_code == 'gpaw') or (dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all(name=files_path + cp2k_name + '.gpw', fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or (dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up') or (spin == 'alpha') or (spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down') or (spin == 'beta') or (spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else: - print("unknown spin, I'm going to sleep. Good Night") - exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name=files_path + name, geom=files_path + geometry_file, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name=files_path + name, geom=files_path + geometry_file, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or (dft_code == 'CP2K')): - if ((spin == None) or (spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, - pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up') or (spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down') or (spin == 'beta') or (spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name=files_path + cp2k_name, lvs=cell, fermi=fermi, orbs=sample_orbs, pbc=pbc, - cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else: - print("unknown spin, I'm going to sleep. Good Night") - exit() - -# print "DEBUG: eigEn.shape ", eigEn.shape -# print "DEBUG: coefs.shape ", coefs.shape -# print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ((scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([PS.dIdV(V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])]) - didv_b = True; WF_decay = 0.0; - # print "DEBUG: didv.shape ", didv.shape -elif ((scan_type == 'states') or (scan_type == 'STATES')): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([PS.dIdV(isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])]) - fst = False - else: - didv = np.append(didv, [PS.dIdV(isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, - s=tc[0], px=tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6])], axis=0) - # print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - # print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - # print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - # print "DEBUG: didv.shape ", didv.shape - # print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -# print "DEBUG: Voltages", Voltages -# print "DEBUG: namez", namez -# print "DEBUG: NoV", NoV -# print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - # print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/4N-coronene/PPdos_simple.py b/tests/4N-coronene/PPdos_simple.py index 443228b..8613a42 100755 --- a/tests/4N-coronene/PPdos_simple.py +++ b/tests/4N-coronene/PPdos_simple.py @@ -10,7 +10,7 @@ # # ***** System information: ***** # -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # +ppstm_path = '../../' # path (absolute or relative) to your PPSTM code # # # ***** Main informations ****** # diff --git a/tests/4N-coronene/SUM_Orb_Contrib.py b/tests/4N-coronene/SUM_Orb_Contrib.py index bc07b78..0f38e10 100755 --- a/tests/4N-coronene/SUM_Orb_Contrib.py +++ b/tests/4N-coronene/SUM_Orb_Contrib.py @@ -10,7 +10,7 @@ # # ***** System information: path (absolute or relative) to your PPSTM code ***** # -ppstm_path = './PPSTM/' +ppstm_path = '../../' # # ***** Main informations ****** # diff --git a/dIdV_coronene_OCL.py b/tests/4N-coronene/dIdV_coronene_OCL.py similarity index 98% rename from dIdV_coronene_OCL.py rename to tests/4N-coronene/dIdV_coronene_OCL.py index 4fad23c..d31fe52 100755 --- a/dIdV_coronene_OCL.py +++ b/tests/4N-coronene/dIdV_coronene_OCL.py @@ -3,7 +3,7 @@ import os import numpy as np import sys -sys.path.append('./') +sys.path.append('../../') import ppafm.io as io import pyPPSTM.ReadSTM as RS diff --git a/dIdV_test_4N-coronene.py b/tests/4N-coronene/dIdV_test_4N-coronene.py similarity index 99% rename from dIdV_test_4N-coronene.py rename to tests/4N-coronene/dIdV_test_4N-coronene.py index d0b0a44..684e109 100755 --- a/dIdV_test_4N-coronene.py +++ b/tests/4N-coronene/dIdV_test_4N-coronene.py @@ -4,6 +4,8 @@ import numpy as np import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/dIdV_test_4N-coronene_cp2k.py b/tests/4N-coronene/dIdV_test_4N-coronene_cp2k.py similarity index 99% rename from dIdV_test_4N-coronene_cp2k.py rename to tests/4N-coronene/dIdV_test_4N-coronene_cp2k.py index 7d6608a..145da66 100755 --- a/dIdV_test_4N-coronene_cp2k.py +++ b/tests/4N-coronene/dIdV_test_4N-coronene_cp2k.py @@ -4,6 +4,8 @@ import numpy as np import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/tests/4N-coronene/pxy-relaxed.toml b/tests/4N-coronene/pxy-relaxed.toml new file mode 100644 index 0000000..17d29c5 --- /dev/null +++ b/tests/4N-coronene/pxy-relaxed.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'relaxed' +scan_window = [[0, 0, 10], [15.9, 15.9, 11.9]] +scan_dim = [128, 128, 20] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 'pxy' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'fireball' +geometry_file = 'crazy_mol.xyz' +pbc = [0,0] +lvs = false +spin = false +cp2k_name = 'crazy_mol' +Q = 0.0 +K = 0.50 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = false +WSxM = false +NPY = true +XSF = true diff --git a/tests/4N-coronene/run_test.sh b/tests/4N-coronene/run_test.sh index e114257..40c88bc 100755 --- a/tests/4N-coronene/run_test.sh +++ b/tests/4N-coronene/run_test.sh @@ -15,11 +15,12 @@ echo "test for the PP-STM code:" ppafm-generate-ljff -i crazy_mol.xyz -f npy ppafm-relaxed-scan --pos -f npy ppafm-plot-results --pos --df --save_df -f npy -python3 PPSTM/dIdV_test_4N-coronene.py -python3 PPSTM/dIdV_test_4N-coronene_cp2k.py + +python3 dIdV_test_4N-coronene.py +python3 dIdV_test_4N-coronene_cp2k.py +python3 ../../ppstm_run.py s-relaxed-png.toml +python3 ../../ppstm_run.py pxy-relaxed.toml +python3 ../../ppstm_run.py s-relaxed.toml python3 PPdos_simple.py -python3 PPSTM_simple.py -python3 PPSTM_simple_pxy.py -python3 PPSTM_simple_s.py python3 SUM_Orb_Contrib.py echo "Now all things made, before submiting, please run clean.sh!" diff --git a/tests/4N-coronene/s-relaxed-png.toml b/tests/4N-coronene/s-relaxed-png.toml new file mode 100644 index 0000000..2a359d1 --- /dev/null +++ b/tests/4N-coronene/s-relaxed-png.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'relaxed' +scan_window = [[0, 0, 10], [15.9, 15.9, 11.9]] +scan_dim = [128, 128, 20] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'fireball' +geometry_file = 'crazy_mol.xyz' +pbc = [0,0] +lvs = false +spin = false +cp2k_name = 'crazy_mol' +Q = 0.0 +K = 0.50 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = true +XSF = false diff --git a/tests/4N-coronene/s-relaxed.toml b/tests/4N-coronene/s-relaxed.toml new file mode 100644 index 0000000..1cf15d5 --- /dev/null +++ b/tests/4N-coronene/s-relaxed.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'relaxed' +scan_window = [[0, 0, 10], [15.9, 15.9, 11.9]] +scan_dim = [128, 128, 20] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'fireball' +geometry_file = 'crazy_mol.xyz' +pbc = [0,0] +lvs = false +spin = false +cp2k_name = 'crazy_mol' +Q = 0.0 +K = 0.50 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = false +WSxM = false +NPY = true +XSF = true diff --git a/tests/CuPc/PPSTM b/tests/CuPc/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/CuPc/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/CuPc/PPSTM_simple.py b/tests/CuPc/PPSTM_simple.py deleted file mode 100755 index 805f78b..0000000 --- a/tests/CuPc/PPSTM_simple.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python3 -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 4 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -tip_type = 'fixed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.5 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'spd' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'cp2k' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'CuPc.xyz' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (1,1) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = [[22,0],[0,22]] # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = 'both' # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'CuPc' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [-20.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [-20.0, 20.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 4.0, 5.0, 1.0 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/CuPc/PPSTM_simple_aims_fixed_npy.py b/tests/CuPc/PPSTM_simple_aims_fixed_npy.py deleted file mode 100755 index 403caa3..0000000 --- a/tests/CuPc/PPSTM_simple_aims_fixed_npy.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/python3 -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 4 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -tip_type = 'fixed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.5 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'sp' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'aims' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'geometry.in' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (1,1) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = 'both' # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = None # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [-20.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [-20.0, 20.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 4.0, 5.0, 1.0 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = False # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = True # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - print("Ratin from reading:", Ratin) - print("Ratin from reading shape:", Ratin.shape) - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/CuPc/cupc-aims-fixed-npy.toml b/tests/CuPc/cupc-aims-fixed-npy.toml new file mode 100644 index 0000000..ad4f2b2 --- /dev/null +++ b/tests/CuPc/cupc-aims-fixed-npy.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'fixed' +scan_window = [[-20, -20, 4], [20, 20, 5]] +scan_dim = [160, 160, 2] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'aims' +geometry_file = 'geometry.in' +pbc = [1,1] +lvs = false +spin = 'both' +cp2k_name = 'crazy_mol' +Q = 0.0 +K = 0.50 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = false +WSxM = false +NPY = true +XSF = true diff --git a/tests/CuPc/cupc.toml b/tests/CuPc/cupc.toml new file mode 100644 index 0000000..ea25e90 --- /dev/null +++ b/tests/CuPc/cupc.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'fixed' +scan_window = [[-20, -20, 4], [20, 20, 5]] +scan_dim = [160, 160, 2] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'spd' + +[input] +path = './' +dft_code = 'cp2k' +geometry_file = 'CuPc.xyz' +pbc = [1, 1] +lvs = [[22,0], [0,22]] +spin = 'both' +cp2k_name = 'CuPc' +Q = 0.0 +K = 0.50 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/dIdV_test_CuPc.py b/tests/CuPc/dIdV_test_CuPc.py similarity index 99% rename from dIdV_test_CuPc.py rename to tests/CuPc/dIdV_test_CuPc.py index 4d90142..ecaecdd 100755 --- a/dIdV_test_CuPc.py +++ b/tests/CuPc/dIdV_test_CuPc.py @@ -4,6 +4,8 @@ import numpy as np #import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/dIdV_test_CuPc_cp2k.py b/tests/CuPc/dIdV_test_CuPc_cp2k.py similarity index 99% rename from dIdV_test_CuPc_cp2k.py rename to tests/CuPc/dIdV_test_CuPc_cp2k.py index a5b446b..b9d58b7 100755 --- a/dIdV_test_CuPc_cp2k.py +++ b/tests/CuPc/dIdV_test_CuPc_cp2k.py @@ -4,6 +4,8 @@ import numpy as np #import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/tests/CuPc/run_test.sh b/tests/CuPc/run_test.sh index 1f71c4e..f2e1cd3 100755 --- a/tests/CuPc/run_test.sh +++ b/tests/CuPc/run_test.sh @@ -10,10 +10,10 @@ echo $OMP_NUM_THREADS echo "Now the tests:" echo "test for the PP-STM code on the example of spin-polarized CuPc molecule, precalculated by FHI-AIMS & CP2K:" -python3 PPSTM/dIdV_test_CuPc.py -python3 PPSTM/dIdV_test_CuPc_cp2k.py +python3 dIdV_test_CuPc.py +python3 dIdV_test_CuPc_cp2k.py python3 PPdos_simple.py -python3 PPSTM_simple.py -python3 PPSTM_simple_aims_fixed_npy.py +python3 ../../ppstm_run.py cupc.toml +python3 ../../ppstm_run.py cupc-aims-fixed-npy.toml echo "Now all things made, before submiting pleas run clean.sh" diff --git a/IETS_test_FePc.py b/tests/FePc_Au/IETS_test_FePc.py similarity index 99% rename from IETS_test_FePc.py rename to tests/FePc_Au/IETS_test_FePc.py index 85a9229..8ffc428 100755 --- a/IETS_test_FePc.py +++ b/tests/FePc_Au/IETS_test_FePc.py @@ -4,6 +4,8 @@ import numpy as np import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM.GridUtils as GU import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/tests/FePc_Au/PPSTM b/tests/FePc_Au/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/FePc_Au/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/FePc_Au/PPSTM_simple.py b/tests/FePc_Au/PPSTM_simple.py deleted file mode 100755 index 6251ced..0000000 --- a/tests/FePc_Au/PPSTM_simple.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python3 -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 1 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -tip_type = 'relaxed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.5 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'spd' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'aims' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'geom-cube.in' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (0,0) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = 'both' # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'CuPc' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [-20.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [-20.0, 20.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 13.9, 14.9, 1.0 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = 57 # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/FePc_Au/PPdos_simple.py b/tests/FePc_Au/PPdos_simple.py index 0a6025b..401c5b0 100755 --- a/tests/FePc_Au/PPdos_simple.py +++ b/tests/FePc_Au/PPdos_simple.py @@ -10,7 +10,7 @@ # # ***** System information: ***** # -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # +ppstm_path = '../../' # path (absolute or relative) to your PPSTM code # # # ***** Main informations ****** # diff --git a/tests/FePc_Au/fepc.toml b/tests/FePc_Au/fepc.toml new file mode 100644 index 0000000..724af76 --- /dev/null +++ b/tests/FePc_Au/fepc.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'relaxed' +scan_window = [[-20, -20, 4], [20, 20, 5]] +scan_dim = [160, 160, 2] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'spd' + +[input] +path = './' +dft_code = 'aims' +geometry_file = 'geom-cube.in' +pbc = [0, 0] +lvs = false +spin = 'both' +cp2k_name = 'crazy_mol' +Q = 0.0 +K = 0.24 +data_format = 'npy' + +[advanced] +cut_atoms = 57 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/tests/FePc_Au/run_test.sh b/tests/FePc_Au/run_test.sh index 59b7461..d119d97 100755 --- a/tests/FePc_Au/run_test.sh +++ b/tests/FePc_Au/run_test.sh @@ -14,8 +14,8 @@ ppafm-generate-ljff -i geom-cube.in -f npy ppafm-relaxed-scan --pos -f npy --vib 3 ppafm-plot-results --pos --df --iets 16 0.0015 0.001 -f npy --WSxM --save_df -python3 PPSTM/IETS_test_FePc.py +python3 IETS_test_FePc.py python3 PPdos_simple.py -python3 PPSTM_simple.py +python3 ../../ppstm_run.py fepc.toml echo "Now all things made, before submiting, please run clean.sh!" diff --git a/tests/PTCDA_mol/PPSTM b/tests/PTCDA_mol/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/PTCDA_mol/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/PTCDA_mol/PPSTM_homo.py b/tests/PTCDA_mol/PPSTM_homo.py deleted file mode 100755 index 1e06ecf..0000000 --- a/tests/PTCDA_mol/PPSTM_homo.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 12 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'didv' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather; "states"="STATES" -- dIdV scancs at the eigenenergies, beware it still uses all other states for calculations # -tip_type = 'relaxed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.787647 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.787647+0.001 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.787647 # voltage step , dV <= 0.1 V # -eta = 0.001 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 'CO' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'sp' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'aims' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'geometry.in' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (0,0) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = None # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'crazy_mol' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [ 0.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [ 0.0, 15.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 10.0, 12.0, 0.1 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = -0.10 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'xsf' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = -0.309023 # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/PTCDA_mol/PPSTM_lumo.py b/tests/PTCDA_mol/PPSTM_lumo.py deleted file mode 100755 index b556af9..0000000 --- a/tests/PTCDA_mol/PPSTM_lumo.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 12 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'didv' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather; "states"="STATES" -- dIdV scancs at the eigenenergies, beware it still uses all other states for calculations # -tip_type = 'relaxed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = +0.787647 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.787647+0.001 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.787647 # voltage step , dV <= 0.1 V # -eta = 0.001 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 'CO' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'sp' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'aims' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'geometry.in' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (0,0) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = None # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'crazy_mol' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [ 0.0, 20.0, 0.25 ] # [xmin, xmax, dx] # -y = [ 0.0, 15.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 10.0, 12.0, 0.1 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = -0.10 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'xsf' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = None # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = -0.309023 # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/PTCDA_mol/ptcda-homo.toml b/tests/PTCDA_mol/ptcda-homo.toml new file mode 100644 index 0000000..85eadd5 --- /dev/null +++ b/tests/PTCDA_mol/ptcda-homo.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'dIdV' +tip_type = 'relaxed' +scan_window = [[0, 0, 10], [20, 15, 12]] +scan_dim = [80, 60, 20] +V = -0.787647 +V_max = +0.788647 +dV = 0.787647 +eta = 0.001 +tip_orb = 'CO' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'aims' +geometry_file = 'geometry.in' +pbc = [0, 0] +lvs = false +spin = false +cp2k_name = 'None' +Q = -0.10 +K = 0.24 +data_format = 'xsf' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = -0.309023 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/tests/PTCDA_mol/ptcda-lumo.toml b/tests/PTCDA_mol/ptcda-lumo.toml new file mode 100644 index 0000000..e99423e --- /dev/null +++ b/tests/PTCDA_mol/ptcda-lumo.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'dIdV' +tip_type = 'relaxed' +scan_window = [[0, 0, 10], [20, 15, 12]] +scan_dim = [80, 60, 20] +V = +0.787647 +V_max = +0.788647 +dV = 0.787647 +eta = 0.001 +tip_orb = 'CO' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'aims' +geometry_file = 'geometry.in' +pbc = [0, 0] +lvs = false +spin = false +cp2k_name = 'None' +Q = -0.10 +K = 0.24 +data_format = 'xsf' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = -0.309023 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/tests/PTCDA_mol/run_all.sh b/tests/PTCDA_mol/run_all.sh index 214e4d2..f88863d 100755 --- a/tests/PTCDA_mol/run_all.sh +++ b/tests/PTCDA_mol/run_all.sh @@ -16,5 +16,5 @@ ppafm-generate-elff -i cube_001_hartree_potential.cube ppafm-relaxed-scan --pos python3 xsf2xyz.py sed -i '2d' input_plot.xyz # the xyz reader in PPSTM does not like non-empty 2nd line of the xyz file # -python3 PPSTM_homo.py -python3 PPSTM_lumo.py +python3 ../../ppstm_run.py ptcda-homo.toml +python3 ../../ppstm_run.py ptcda-lumo.toml diff --git a/PDOS_test_Si_7x7.py b/tests/Si_7x7/PDOS_test_Si_7x7.py similarity index 99% rename from PDOS_test_Si_7x7.py rename to tests/Si_7x7/PDOS_test_Si_7x7.py index ca61857..ee506ca 100755 --- a/PDOS_test_Si_7x7.py +++ b/tests/Si_7x7/PDOS_test_Si_7x7.py @@ -5,6 +5,8 @@ #import ppafm.io as io #import pyPPSTM as PS +import sys +sys.path.append('../../') import pyPPSTM.ReadSTM as RS import pyPPSTM.PreSTMutils as SU diff --git a/tests/Si_7x7/PPSTM b/tests/Si_7x7/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/Si_7x7/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/Si_7x7/PPSTM_simple.py b/tests/Si_7x7/PPSTM_simple.py deleted file mode 100755 index f9bc927..0000000 --- a/tests/Si_7x7/PPSTM_simple.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 7 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'v-scan' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -tip_type = 'fixed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = -0.5 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.5 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) # -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 0.1 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'spd' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'fireball' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'input.xyz' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = (1.,1.) # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = 'input.lvs' # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = None # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'CuPc' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [ 0.0, 50.0, 0.25 ] # [xmin, xmax, dx] # -y = [-25.0, 25.0, 0.25 ] # [ymin, ymax, dy] # -z = [ 13.9, 14.9, 1.0 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = True # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = False # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = 18 # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.))): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - #print "DEBUG: cell.shape", cell.shape - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/Si_7x7/PPdos_simple.py b/tests/Si_7x7/PPdos_simple.py index 1da8524..9e66701 100755 --- a/tests/Si_7x7/PPdos_simple.py +++ b/tests/Si_7x7/PPdos_simple.py @@ -10,7 +10,7 @@ # # ***** System information: ***** # -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # +ppstm_path = '../../' # path (absolute or relative) to your PPSTM code # # # ***** Main informations ****** # diff --git a/STM_test_Si_7x7.py b/tests/Si_7x7/STM_test_Si_7x7.py similarity index 99% rename from STM_test_Si_7x7.py rename to tests/Si_7x7/STM_test_Si_7x7.py index 8a15aa6..7191fd7 100755 --- a/STM_test_Si_7x7.py +++ b/tests/Si_7x7/STM_test_Si_7x7.py @@ -4,6 +4,8 @@ import numpy as np #import ppafm.io as io # --- not needed at all for the rigid tip scans +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/dIdV_test_Si_7x7.py b/tests/Si_7x7/dIdV_test_Si_7x7.py similarity index 99% rename from dIdV_test_Si_7x7.py rename to tests/Si_7x7/dIdV_test_Si_7x7.py index 8d8a021..df6dd7f 100755 --- a/dIdV_test_Si_7x7.py +++ b/tests/Si_7x7/dIdV_test_Si_7x7.py @@ -4,6 +4,8 @@ import numpy as np #import ppafm.io as io # --- not needed at all for the rigid tip scans +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/tests/Si_7x7/run_all_tests.sh b/tests/Si_7x7/run_all_tests.sh index 38d9f49..9ae7866 100755 --- a/tests/Si_7x7/run_all_tests.sh +++ b/tests/Si_7x7/run_all_tests.sh @@ -10,15 +10,15 @@ echo $OMP_NUM_THREADS echo "Now the tests:" echo "test for the PP-STM code ploting DOS of Si(111) 7x7 reconstruction:" -python3 PPSTM/PDOS_test_Si_7x7.py +python3 PDOS_test_Si_7x7.py echo "test for the PP-STM code on the example os Si(111) 7x7 reconstruction - single STM calc -- +- 0.5 V:" -python3 PPSTM/dIdV_test_Si_7x7.py +python3 dIdV_test_Si_7x7.py echo "Now all things made, before submiting please run clean.sh" echo "test for the PP-STM code on the example os Si(111) 7x7 reconstruction - full STM & dIdV Scan:" -python3 PPSTM/STM_test_Si_7x7.py +python3 STM_test_Si_7x7.py python3 PPdos_simple.py -python3 PPSTM_simple.py +python3 ../../ppstm_run.py si_7x7.toml echo "Now all things made, before submiting please run clean.sh" diff --git a/tests/Si_7x7/si_7x7.toml b/tests/Si_7x7/si_7x7.toml new file mode 100644 index 0000000..91ddbfd --- /dev/null +++ b/tests/Si_7x7/si_7x7.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'fixed' +scan_window = [[0, -25, 13.9], [50, 25, 14.9]] +scan_dim = [200, 200, 10] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'spd' + +[input] +path = './' +dft_code = 'fireball' +geometry_file = 'input.xyz' +pbc = [1.0, 1.0] +lvs = 'input.lvs' +spin = false +cp2k_name = 'None' +Q = -0.10 +K = 0.24 +data_format = 'xsf' + +[advanced] +cut_atoms = 18 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/tests/TOAT/PPSTM b/tests/TOAT/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/TOAT/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/TOAT/PPdos_simple.py b/tests/TOAT/PPdos_simple.py index 1288ecd..4d86d70 100755 --- a/tests/TOAT/PPdos_simple.py +++ b/tests/TOAT/PPdos_simple.py @@ -10,7 +10,7 @@ # # ***** System information: ***** # -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # +ppstm_path = '../../' # path (absolute or relative) to your PPSTM code # # # ***** Main informations ****** # diff --git a/dIdV_test_TOAT.py b/tests/TOAT/dIdV_test_TOAT.py similarity index 99% rename from dIdV_test_TOAT.py rename to tests/TOAT/dIdV_test_TOAT.py index 4ff971d..290eea6 100755 --- a/dIdV_test_TOAT.py +++ b/tests/TOAT/dIdV_test_TOAT.py @@ -4,6 +4,8 @@ import numpy as np import ppafm.io as io +import sys +sys.path.append('../../') import pyPPSTM as PS import pyPPSTM.ReadSTM as RS diff --git a/tests/TOAT/run_test.sh b/tests/TOAT/run_test.sh index 176ed0b..ecfa92e 100755 --- a/tests/TOAT/run_test.sh +++ b/tests/TOAT/run_test.sh @@ -12,9 +12,9 @@ echo "test for the PP-STM code:" ppafm-generate-ljff -i TOAT.xyz -f npy ppafm-relaxed-scan --pos -f npy ppafm-plot-results --pos --df --save_df -f npy -python3 PPSTM/dIdV_test_TOAT.py +python3 dIdV_test_TOAT.py python3 PPdos_simple.py -python3 PPSTM_simple.py +python3 ../../ppstm_run.py toat.toml echo "Now all things made, before submiting please run clean.sh" diff --git a/tests/TOAT/toat.toml b/tests/TOAT/toat.toml new file mode 100644 index 0000000..42f0a1e --- /dev/null +++ b/tests/TOAT/toat.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'v-scan' +tip_type = 'fixed' +scan_window = [[-3, -3, 12.7], [15, 15, 13.7]] +scan_dim = [180, 180, 10] +V = -0.5 +V_max = +0.5 +dV = 0.1 +eta = 0.1 +tip_orb = 's' +sample_orbs = 'sp' + +[input] +path = './' +dft_code = 'cp2k' +geometry_file = 'TOAT.xyz' +pbc = [0, 0] +lvs = false +spin = false +cp2k_name = 'TOAT' +Q = -0.10 +K = 0.24 +data_format = 'xsf' + +[advanced] +cut_atoms = 18 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = false diff --git a/tests/orbitals/PPSTM b/tests/orbitals/PPSTM deleted file mode 120000 index 6581736..0000000 --- a/tests/orbitals/PPSTM +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/tests/orbitals/PPSTM_simple.py b/tests/orbitals/PPSTM_simple.py deleted file mode 100755 index 234f103..0000000 --- a/tests/orbitals/PPSTM_simple.py +++ /dev/null @@ -1,395 +0,0 @@ -#!/usr/bin/python -# -########################################################################################################################## -# # -# What follows are options of the PP-STM (dIdV) code # -# # -########################################################################################################################## -# -# Note : This type of simulations works for solid slabs or molecules on slabs (substrate) ; for freestanding molecule it can give you nonsences -# -# ***** System information: ***** -# -ppstm_path = './PPSTM/' # path (absolute or relative) to your PPSTM code # -# -ncpu = 1 # number of cpu cores for OMP paralelization: ncpu = 1 -- serial compilation & calculations; iff ncpu > 1, then OMP paralel recompilation is used and C++ calculations are running on more cores # -# -# ***** Main informations ****** -# -scan_type = 'dIdV' # 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # -tip_type = 'fixed' # 'fixed'='f' -- for stiff/metal tip apexes ; 'relaxed'='r' -- for flexible tip apexes (precalculated by PP-AFM) . For this option you have to have "installed" PPAFM in your PPSTM directory # -V = +0.0 # !!!! V = Vmin for SCAN !!!! # -V_max = +0.0 # V = V_min >= -2.0 V ; V_max <= 2.0 V (othervise changes in the later code needed) 0 -dV = 0.1 # voltage step , dV <= 0.1 V # -eta = 10.0 # Lorentzian width of states in energy scale: typically 0.1; can be in range of 0.3-0.05 eV in some cases (low amount of layers ...) even up to 1.0 eV # -WF_decay = 0.5 # 0.0 <= WF_decay <= 1.0 ; How fast WorkFunction tunnelling barrier is changing with Voltage : (WF = WF_0 + V*WF_decay) -- 0.0 no change ; 1.0 - the same change as voltage # -tip_orb = 's' # 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # -sample_orbs = 'spd' # orbitals of the sample 'sp' (light atoms only, faster) or 'spd' (all atoms) # -dft_code = 'fireball' # 'fireball'='Fireball'='FIREBALL' ; 'aims'='AIMS'='FHI-AIMS' ; 'cp2k'='CP2K' ; 'gpaw'='GPAW' # -geometry_file = 'input_plot.xyz' # E.G. 'input.xyz' , 'input.bas' , 'geometry.in'; None for GPAW # -pbc = None # (0,0) = None = False -- only original geometry ; (0.5,0.5) -- 2x2 cell ; (1,1) -- 3x3 cell (around original) ; (2,2) -- 5x5 cell (around original) ... # -lvs = None # None ; [[ax,ay,0],[bx,by,0]],[0,0,cz]] or [[ax,ay],[bx,by]] ; 'input.lvs' -- files with specified cell ; in FHI-AIMS & GPAW allready specified with geometry # -spin = None # None=False ; for FHI-AIMS & CP2K: None -- spin-unpolarized/spin-restricted calc. ; 'both' , 'up'='alpha' or 'down" (last 3 are for spin-polarizes or spin-unrestricted calculations) # -cp2k_name = 'None' # Name used in CP2K calculations or GPAW calc # -# -# ***** Informations for x,y,z tip_type = 'fixed' ****** -# -x = [ -5.0, 15.0, 0.20 ] # [xmin, xmax, dx] # -y = [ -5.0, 15.0, 0.20 ] # [ymin, ymax, dy] # -z = [ -5.0, 5.0, 0.20 ] # !!!! z-starts from zero - normally zmin >= 3-4 Ang above heighest atoms !!!! [zmin, zmax, dz] ; for single height scan use : [z, z, 1.0] # -# -# ***** Informations for PP positions, tip_type = 'relaxed' ****** -# -Q = 0.00 # charge (PP-AFM) ; Ocharge PP-AFM complex_tip autumn 2018) ; [e] (monopole), [e*A] (dipole), [e*A^2] (quadrupole) # -K = 0.24 # x stiffness (PP-AFM master autumn 2018); klat (PP-AFM dev/OpenCl autumn 2018); Oklat (PP-AFM complex_tip autumn 2018) ; [N/m] # -data_format = 'npy' # 'xsf'='XSF' ; 'npy'='NPY' ; -- format in which PPpos are stored from PP-AFM run # -# -# *****Output options ****** -# -PNG = False # True / False -- plot "png" images (2D constant height) # -WSxM = False # True / False -- write ".xyz" WSxM files (2D constant height) # -XSF = True # True / False -- write ".xsf" files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -NPY = False # True / False -- write ".npy" numpy binary files with 3D stucks of data . For this option you have to have "installed" PPAFM in your PPSTM directory # -plot_atoms = True # True / False -- plot geometry (position of atoms into the PNG images and into the XSF files). You have to have your geometry, which you want to plot in input_plot.xyz. This doesn't change the name of the output files # -# -# ***** Advanced options ****** -# -cut_atoms = -1 # None = -1 -- All atoms of the sample contributes to tunelling ; 1 -- only 1st atom of the sample contributes to the tunelling ; 57 -- first 57 atoms of the sample contributes to the tunelling ; ... # -lower_atoms = [] # [] = None -- No atoms has lowered hopping ; be aware python numbering occurs here: [0] - means lowering of the 1st atom; [0,1,2,3] -- lowering of 1st 4 atoms ... # -lower_coefs = [] # [] = None -- No lowering of the hoppings ; [0.5] -- lowering of the 1st atom hopping to 0.5 ; [0.5,0.5,0.5,0.5] -- lowering of 1st 4 atoms to 0.5 ... # -# -# ***** More advanced options ****** -# -WorkFunction = 5.0 # 5.0 eV is standart # -fermi = None # None=0.0 -- no change to the Fermi Level ; -0.1 -- shifts the Fermi Level by 0.1 eV lower ... # -cut_min = -2.5 # cut out all orbitals lower than -2.5 eV bellow Rermi (should be: cut_min <= Vmin-2*eta) . taken to the Fermi Level # -cut_max = +2.5 # cut out all orbitals higher than -2.5 eV above Fermi (should be: cut_max >= Vmax+2*eta) . taken to the Fermi Level # -files_path = '' # where are files fron DFT code ; rather do not use this # -# -# -########################################################################################################################## -# # -# DO NOT TOUCH LATER CODE (unless you know what you are doing) # -# # -########################################################################################################################## - -print("Importing libraries") - -import os -import sys -sys.path.append(ppstm_path) - -if (ncpu > 1): - os.environ['OMP_NUM_THREADS'] = str(ncpu) - print('OMP_NUM_THREADS:', os.environ['OMP_NUM_THREADS']) - -import numpy as np -import pyPPSTM as PS -import pyPPSTM.ReadSTM as RS -import matplotlib -matplotlib.use('Agg') # Force matplotlib to not use any Xwindows backend. ## !!! important for working on clusters !!!! -import matplotlib.pyplot as plt -if (XSF or NPY or (tip_type == 'relaxed') or (tip_type == 'r' )): - print("For XSF or NPY outputs or tip_type = relaxed you have to have installed PPAFM in your PPSTM directory ") - import ppafm.io as io -if (plot_atoms): - import pyPPSTM.basUtils as Bu - import pyPPSTM.elements as elements - - -print("Libraries imported") - -# --- Initial check --- # - -assert( PNG or WSxM or XSF or NPY ), "No output set to be True; I'm not going to do anything if there is no output. I'm too lazy like a Gartfield. " - -# --- specification of tip orbitals --- # -# 's' ; 'pxy' -- px & py ; 'spxy' -- 50% s & 50% pxy ; '5spxy' -- 5% s & 95% pxy ; '10spxy' -- 10% s & 90% pxy ; 'CO' -- 13% s & 87% pxy (PRL 119, 166001 (2017)) ; 'pz' ; For sample_orbs = 'sp' , possible 'dz2' and 'dxzyz' -- dxz & dyz # - -if (tip_orb == 's'): - tc = [1.,0.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pxy'): - tc = [0.,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'spxy'): - tc = [0.5,0.25,0.25,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '5spxy'): - tc = [0.05,0.475,0.475,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == '10spxy'): - tc = [0.10,0.45,0.45,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'CO'): - tc = [0.15,0.5,0.5,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'pz'): - tc = [0.,0.,0.,1.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dz2'): - tc = [0.,0.,0.,0.,1.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'dxzyz'): - tc = [0.,0.,0.,0.,0.,0.5,0.5] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'px'): - tc = [0.,1.,0.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -elif (tip_orb == 'py'): - tc = [0.,0.,1.,0.,0.,0.,0.] # [s, px, py, pz, dz2, dxz, dyz ] -else: - print("Don't know what kind od tip you mean. I rather going to exit.") ; exit() - -#print "DEBUG: tc ", tc , " [s, px, py, pz, dz2, dxz, dyz ] " - -# --- Reading geometry for plotting (if necessary) --- # - -if (plot_atoms): - geom_plot, tmp1, tmp2 = Bu.loadAtoms('input_plot.xyz'); del tmp1, tmp2; - #print "DEBUG: geom_plot", geom_plot -else: - geom_plot = None - -# --- the grid on which the STM signal is calculated --- # - -if ((tip_type =='relaxed') or (tip_type == 'r')): - print("Importing positions of PP from the PP-AFM calculations. Path for the data:") - path_pos="Q%1.2fK%1.2f/" %(Q,K) - print(path_pos) - tip_r, lvec, nDim, atomic_info_or_head = io.load_vec_field( path_pos+'PPpos' ,data_format=data_format) - extent = (lvec[0,0],lvec[0,0]+lvec[1,0],lvec[0,1],lvec[0,1]+lvec[2,1]) - #print "DEBUG: extent", extent - print("PP postions imported") - dx=lvec[1,0]/(nDim[2]-1); dy=lvec[2,1]/(nDim[1]-1); dz=lvec[3,2]/(nDim[0]-1); - tip_r0 = RS.mkSpaceGrid(lvec[0,0],lvec[0,0]+lvec[1,0],dx,lvec[0,1],lvec[0,1]+lvec[2,1],dy,lvec[0,2],lvec[0,2]+lvec[3,2],dz) - #print "DEBUG: dx, dy, dz", dx, dy, dz - #print "DEBUG: tip_r.shape, tip_r0.shape", tip_r.shape, tip_r0.shape -else: - print("Priparing the scan grid for fixed scan") - extent = (x[0],x[1],y[0],y[1]) - tip_r = RS.mkSpaceGrid(x[0],x[1],x[2],y[0],y[1],y[2],z[0],z[1],z[2]) - lvec = np.array([[x[0],y[0],z[0]],[x[1]-x[0],0.,0.],[0.,y[1]-y[0],0.],[0.,0.,z[1]-z[0]]]) - atomic_info_or_head = (np.zeros((4,1)), np.zeros((4,3))) - #print "DEBUG: extent", extent - #print "DEBUG: lvec", lvec - tip_r0 = tip_r - print("scan grids prepared") - -# --- reading of the eigen-energies, the LCAO coefficients and geometry --- # - -print("Reading electronic & geometry structure files") - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL') or (dft_code == 'cp2k') or(dft_code == 'CP2K')): - print("DEBUG: lvs", lvs) - if isinstance(lvs, (list, tuple, np.ndarray)): - cell = np.array([[lvs[0][0],lvs[0][1],0.0],[lvs[1][0],lvs[1][1],0.0],[0.0,0.0,99.9]]) if (len(lvs) == 2) else lvs - elif isinstance(lvs, (str)): - cell = np.loadtxt(lvs) - elif ((pbc == (0,0)) or (pbc == (0.,0.)) or (pbc == None) or (pbc == False)): - cell = np.array([[0,0,0],[0,0,0],[0,0,0]]); pbc=(0,0); - else: - print("PBC required, but lattice vector not specified. What can I do with that? I rather go to eat something."); exit() - print("DEBUG: cell.shape", cell.shape) - -if ((dft_code == 'fireball') or(dft_code == 'Fireball') or (dft_code == 'FIREBALL')): - print("DEBUG: cell", cell) - print("DEBUG: pbc", pbc) - eigEn, coefs, Ratin = RS.read_FIREBALL_all(name = files_path + 'phik_0001_', geom=files_path+geometry_file, lvs = cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max,cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'gpaw') or(dft_code == 'GPAW')): - eigEn, coefs, Ratin = RS.read_GPAW_all( name = files_path + cp2k_name + '.gpw', fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - -elif ((dft_code == 'aims') or(dft_code == 'AIMS') or (dft_code == 'FHI-AIMS')): - if ((spin == None) or (spin == False)): - name = 'KS_eigenvectors.band_1.kpt_1.out' - elif ((spin == 'up')or(spin == 'alpha')or(spin == 'both')): - name = 'KS_eigenvectors_up.band_1.kpt_1.out' - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - eigEn, coefs, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - if (spin == 'both'): - eigEn1 = eigEn.copy(); coefs1 = coefs.copy(); del eigEn, coefs ; - name = 'KS_eigenvectors_dn.band_1.kpt_1.out' - eigEn2, coefs2, Ratin = RS.read_AIMS_all(name = files_path + name , geom= files_path + geometry_file, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - -elif ((dft_code == 'cp2k') or(dft_code == 'CP2K')): - if ((spin == None)or(spin == False)): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs); - elif ((spin == 'up')or(spin == 'alpha')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - elif (spin == 'both'): - eigEn1, coefs1, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='alpha'); - eigEn2, coefs2, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - eigEn = np.concatenate((eigEn1, eigEn2), axis=0) - coefs = np.concatenate((coefs1, coefs2), axis=0) - elif ((spin == 'down')or(spin == 'beta')or(spin == 'dn')): - eigEn, coefs, Ratin = RS.read_CP2K_all(name = files_path + cp2k_name , lvs=cell, fermi=fermi, orbs = sample_orbs, pbc=pbc, cut_min=cut_min, cut_max=cut_max, cut_at=cut_atoms, lower_atoms=lower_atoms, lower_coefs=lower_coefs, spin='beta'); - else : - print("unknown spin, I'm going to sleep. Good Night"); exit() - -#print "DEBUG: eigEn.shape ", eigEn.shape -#print "DEBUG: coefs.shape ", coefs.shape -#print "DEBUG: Ratin.shape ", Ratin.shape - -print("energies prepared, coeffecients read") - -# --- the Main calculations --- # -# 'didv'='dIdV''='didv-single' -- only dIdV for one voltage = V ; 'v-scan'='V-scan'='Voltage-scan' -- both STM & dIdV scan - V .. Vmax; 'STM'='STM-single' -- STM for one Voltage = V, use V-scan rather # - -didv_b = False -STM_b = False -states_b = False - -if ( (scan_type == 'didv') or (scan_type == 'dIdV') or (scan_type == 'didv-single')): - didv = np.array([ PS.dIdV( V, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - didv_b = True; WF_decay= 0.0; - #print "DEBUG: didv.shape ", didv.shape -elif ( (scan_type == 'states') or (scan_type == 'STATES') ): - states = np.sort(eigEn); mask = states >= V; states = states[mask]; del mask; - mask = states <= V_max; states = states[mask]; del mask; - fst = True - print("DEBUG: states:", states) - for isi in states: - if fst: - didv = np.array([ PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ]) - fst = False - else : - didv =np.append(didv, [PS.dIdV( isi, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6] ) ], axis =0) - #print "DEBUG: didv.shape ", didv.shape - didv_b = True; states_b = True; WF_decay= 0.0; - -elif ( (scan_type == 'STM') or (scan_type == 'STM-single') ): - nV = abs(V/dV)+1 - #print "DEBUG: V, nV:", V, nV - current = np.array([ PS.STM( V, nV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) ]) - STM_b = True - #print "DEBUG: current.shape ", current.shape -else: - current, didv = PS.MSTM( V, V_max, dV, WorkFunction, eta, eigEn, tip_r, Ratin, coefs, orbs=sample_orbs, s=tc[0], px =tc[1], py=tc[2], pz=tc[3], dz2=tc[4], dxz=tc[5], dyz=tc[6], WF_decay=WF_decay) - didv_b = True - STM_b = True - #print "DEBUG: didv.shape ", didv.shape - #print "DEBUG: current.shape ", current.shape - -# =========== Utils for plotting atoms ========================= - -def plotAtoms( atoms, atomSize=0.1, edge=True, ec='k', color='w' ): - plt.fig = plt.gcf() - es = atoms[0]; xs = atoms[1]; ys = atoms[2] - for i in range(len(xs)): - fc = '#%02x%02x%02x' % elements.ELEMENT_DICT[es[i]][7] #; print "DEBUG: fc", fc ; ##fc = '#FFFFFF' ## - if not edge: - ec=fc - circle=plt.Circle( ( xs[i], ys[i] ), atomSize, fc=fc, ec=ec ) - plt.fig.gca().add_artist(circle) - -def plotGeom( atoms=None, atomSize=0.1 ): - if atoms is not None: - plotAtoms( atoms, atomSize=atomSize ) - - -# --- plotting part here, plots all calculated signals --- # - -Voltages= np.arange(V,V_max+0.001,dV) if not states_b else states # this part is important for scans over slabs at different voltages -round_index = 2 if not states_b else 5 -print("Voltages", Voltages) -namez = [] -for V in Voltages: - namez.append(str(round(V,round_index))) - -NoV = len(didv) if didv_b else len(current) -NoH = len(didv[0]) if didv_b else len(current[0]) - -#print "DEBUG: Voltages", Voltages -#print "DEBUG: namez", namez -#print "DEBUG: NoV", NoV -#print "DEBUG: NoH", NoH - -if PNG : - print("We go to plotting ") - for vv in range(NoV): - for k in range(NoH): - #print "DEBUG: long name:::", namez[vv],';height:%03d;tip:' %k,tip_type,';',tip_orb - name_plot=namez[vv]+';height:'+str(k)+';tip:'+tip_type+';'+tip_orb - if didv_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(didv[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("dIdV:"+name_plot) - plt.savefig( 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - if STM_b : - # ploting part here: - plt.figure( figsize=(0.5 * lvec[1,0] , 0.5 * lvec[2,1] ) ) - plt.imshow(current[vv,k,:,:], origin='lower', extent=extent , cmap='gray') - plotGeom(atoms=geom_plot) - plt.xlabel(r' Tip_x $\AA$') - plt.ylabel(r' Tip_y $\AA$') - plt.title("STM:"+name_plot) - plt.savefig( 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.png' %k , bbox_inches='tight' ) - plt.close() - print("Everything plotted") -if WSxM : - print("writing WSxM files") - for vv in range(NoV): - for k in range(NoH): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=didv[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'_%03d.xyz' %k - tmp_curr=current[vv,k,:,:].flatten() - out_curr=np.zeros((len(tmp_curr),3)) - out_curr[:,0]=tip_r0[k,:,:,0].flatten() - out_curr[:,1]=tip_r0[k,:,:,1].flatten() - out_curr[:,2]=tmp_curr.copy() - f=open(name_file,'w') - print("WSxM file copyright Nanotec Electronica", file=f) - print("WSxM ASCII XYZ file; obtained from dIdV code by Krejci et al.", file=f) - print("X[A] Y[A] Z[A]", file=f) - print("", file=f) - np.savetxt(f, out_curr) - f.close() - # - print("WSxM files written") - -if XSF : - print("writing XSF files") - xsf_head = Bu.At2XSF(geom_plot) if plot_atoms else io.XSF_HEAD_DEFAULT - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, didv[vv], lvec, head=xsf_head ) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta)+'.xsf' - io.saveXSF(name_file, current[vv], lvec, head=xsf_head ) - print("XSF files written") - -if NPY : - print("writing npy binary files") - for vv in range(NoV): - if didv_b : - name_file = 'didv_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction-Voltages[vv]*WF_decay)+"_eta_"+str(eta) - io.saveNpy(name_file, didv[vv], lvec, atomic_info=atomic_info_or_head) - if STM_b : - name_file = 'STM_'+namez[vv]+"_tip_"+tip_type+"-"+tip_orb+"_WF_"+str(WorkFunction)+"_WF_decay_"+str(round(WF_decay,1))+"_eta_"+str(eta) - io.saveNpy(name_file, current[vv], lvec, atomic_info=atomic_info_or_head) - print("npy files written") - -# --- the end --- # - -print() -print() -print("Done") -print() - diff --git a/tests/orbitals/clean.sh b/tests/orbitals/clean.sh new file mode 100755 index 0000000..c4631f2 --- /dev/null +++ b/tests/orbitals/clean.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +echo "Removing not neccessary folders and *.npy files" +rm -r ./Q0.00K0.24 +rm *.npy +rm *.npz +#echo "Removing calculated Figures" +rm *.png +echo "Removing outputs of PPSTM_simple, if any" +rm STM_*.png +rm didv_*tip_*WF_*eta_*.xsf +rm STM_*tip_*WF_*eta_*.xsf +rm didv_*tip_*WF_*eta_*.xyz +rm STM_*tip_*WF_*eta_*.xyz +rm PDOS_*.png +echo "Done, bye bye" + + diff --git a/tests/orbitals/orbitals.toml b/tests/orbitals/orbitals.toml new file mode 100644 index 0000000..6249a91 --- /dev/null +++ b/tests/orbitals/orbitals.toml @@ -0,0 +1,43 @@ +title = "Default configuration" + + +[scan] +scan_type = 'dIdV' +tip_type = 'fixed' +scan_window = [[-5, -5, -5], [15, 15, 5]] +scan_dim = [100, 100, 50] +V = +0.0 +V_max = +0.0 +dV = 0.1 +eta = 10.0 +tip_orb = 's' +sample_orbs = 'spd' + +[input] +path = './' +dft_code = 'fireball' +geometry_file = 'input_plot.xyz' +pbc = [0, 0] +lvs = false +spin = false +cp2k_name = 'None' +Q = 0.0 +K = 0.24 +data_format = 'npy' + +[advanced] +cut_atoms = -1 +lower_atoms = [] +lower_coefs = [] +work_function = 5.0 +work_function_decay = 0.5 +fermi = 0.0 +cut_min = -2.5 +cut_max = 2.5 + +[output] +plot_atoms = true +PNG = true +WSxM = false +NPY = false +XSF = true diff --git a/tests/orbitals/run_test.sh b/tests/orbitals/run_test.sh new file mode 100755 index 0000000..20fddc7 --- /dev/null +++ b/tests/orbitals/run_test.sh @@ -0,0 +1,14 @@ +#!/bin/bash +OMP=0 # 0 = 'False' , 1 = 'True' +if [ $OMP -eq 1 ] +then + export OMP_NUM_THREADS=8 +fi + +echo "OMP_NUM_THREADS:" +echo $OMP_NUM_THREADS +echo "Now the tests:" + +python3 ../../ppstm_run.py orbitals.toml + +echo "Now all things made, before submiting, please run clean.sh!"