def test_dipole_prepared_continuum(): """ see G. Fronzoni, M. Stener, S. Furlan, P. Decleva Chemical Physics 273 (2001) 117-133 """ from DFTB.LR_TDDFTB import LR_TDDFTB from DFTB import XYZ from DFTB.Scattering import slako_tables_scattering # BOUND ORBITAL = H**O atomlist = XYZ.read_xyz("./water.xyz")[0] tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options = {"nstates": 1} tddftb.getEnergies(**options) valorbs, radial_val = load_pseudo_atoms(atomlist) H**O, LUMO = tddftb.dftb2.getFrontierOrbitals() bound_orbs = tddftb.dftb2.getKSCoefficients() # polarization direction of E-field epol = np.array([0.0, 1.0, 0.0]) # according to Koopman's theorem the electron is ionized from the H**O mo_indx = range(0, len(bound_orbs)) nmo = len(mo_indx) for imo in range(0, nmo): mo_bound = bound_orbs[:, mo_indx[imo]] # CONTINUUM ORBITALS at energy E for E in slako_tables_scattering.energies: bs = AtomicScatteringBasisSet(atomlist, E) SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf) # projection of dipoles onto polarization direction Dipole_projected = np.zeros((Dipole.shape[0], Dipole.shape[1])) for xyz in [0, 1, 2]: Dipole_projected += Dipole[:, :, xyz] * epol[xyz] # unnormalized coefficients of dipole-prepared continuum orbitals mo_scatt = np.dot(mo_bound, Dipole_projected) nrm2 = np.dot(mo_scatt, mo_scatt) # normalized coefficients mo_scatt /= np.sqrt(nrm2) Cube.orbital2grid(atomlist, bs.bfs, mo_scatt, \ filename="/tmp/scattering_orbital_%d_to_%s.cube" % (imo, str(E).replace(".", "p")), dbuff=25.0) delattr(Cube.orbital_amplitude, "cached_grid")
def test_averaged_asymptotic_density(): from DFTB.LR_TDDFTB import LR_TDDFTB from DFTB import XYZ from DFTB.Scattering import slako_tables_scattering from DFTB.Scattering import PAD # BOUND ORBITAL = H**O atomlist = XYZ.read_xyz("./water.xyz")[0] tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options = {"nstates": 1} tddftb.getEnergies(**options) valorbs, radial_val = load_pseudo_atoms(atomlist) H**O, LUMO = tddftb.dftb2.getFrontierOrbitals() bound_orbs = tddftb.dftb2.getKSCoefficients() # polarization direction of E-field epol = np.array([0.0, 0.0, 1.0]) # according to Koopman's theorem the electron is ionized from the H**O mo_indx = range(0, len(bound_orbs)) nmo = len(mo_indx) for imo in range(0, nmo): print "IMO = %s" % imo import time time.sleep(1) mo_bound = bound_orbs[:, mo_indx[imo]] # CONTINUUM ORBITALS at energy E for E in slako_tables_scattering.energies[-2:-1]: bs = AtomicScatteringBasisSet(atomlist, E) SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf) PAD.averaged_asymptotic_density(mo_bound, Dipole, bs, 20.0, E)
def averaged_pad_scan(xyz_file, dyson_file, selected_orbitals, npts_euler, npts_theta, nskip, inter_atomic, sphere_radius): molecule_name = os.path.basename(xyz_file).replace(".xyz", "") atomlist = XYZ.read_xyz(xyz_file)[-1] # shift molecule to center of mass print "shift molecule to center of mass" pos = XYZ.atomlist2vector(atomlist) masses = AtomicData.atomlist2masses(atomlist) pos_com = MolCo.shift_to_com(pos, masses) atomlist = XYZ.vector2atomlist(pos_com, atomlist) # compute molecular orbitals with DFTB tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options={"nstates": 1} try: tddftb.getEnergies(**options) except DFTB.Solver.ExcitedStatesNotConverged: pass valorbs, radial_val = load_pseudo_atoms(atomlist) if dyson_file == None: print "tight-binding Kohn-Sham orbitals are taken as Dyson orbitals" H**O, LUMO = tddftb.dftb2.getFrontierOrbitals() bound_orbs = tddftb.dftb2.getKSCoefficients() if selected_orbitals == None: # all orbitals selected_orbitals = range(0,bound_orbs.shape[1]) else: selected_orbitals = eval(selected_orbitals, {}, {"H**O": H**O+1, "LUMO": LUMO+1}) print "Indeces of selected orbitals (counting from 1): %s" % selected_orbitals orbital_names = ["orb_%s" % o for o in selected_orbitals] selected_orbitals = np.array(selected_orbitals, dtype=int)-1 # counting from 0 dyson_orbs = bound_orbs[:,selected_orbitals] ionization_energies = -tddftb.dftb2.getKSEnergies()[selected_orbitals] else: print "coeffients for Dyson orbitals are read from '%s'" % dyson_file orbital_names, ionization_energies, dyson_orbs = load_dyson_orbitals(dyson_file) ionization_energies = np.array(ionization_energies) / AtomicData.hartree_to_eV print "" print "*******************************************" print "* PHOTOELECTRON ANGULAR DISTRIBUTIONS *" print "*******************************************" print "" # determine the radius of the sphere where the angular distribution is calculated. It should be # much larger than the extent of the molecule (xmin,xmax),(ymin,ymax),(zmin,zmax) = Cube.get_bbox(atomlist, dbuff=0.0) dx,dy,dz = xmax-xmin,ymax-ymin,zmax-zmin Rmax = max([dx,dy,dz]) + sphere_radius Npts = max(int(Rmax),1) * 50 print "Radius of sphere around molecule, Rmax = %s bohr" % Rmax print "Points on radial grid, Npts = %d" % Npts nr_dyson_orbs = len(orbital_names) # compute PADs for all selected orbitals for iorb in range(0, nr_dyson_orbs): print "computing photoangular distribution for orbital %s" % orbital_names[iorb] data_file = "betas_" + molecule_name + "_" + orbital_names[iorb] + ".dat" pad_data = [] print " SCAN" nskip = max(1, nskip) # save table fh = open(data_file, "w") print " Writing table with betas to %s" % data_file print>>fh, "# ionization from orbital %s IE = %6.3f eV" % (orbital_names[iorb], ionization_energies[iorb]*AtomicData.hartree_to_eV) print>>fh, "# inter_atomic: %s npts_euler: %s npts_theta: %s rmax: %s" % (inter_atomic, npts_euler, npts_theta, Rmax) print>>fh, "# PKE/eV sigma beta1 beta2 beta3 beta4" for i,E in enumerate(slako_tables_scattering.energies): if i % nskip != 0: continue print " PKE = %6.6f Hartree (%4.4f eV)" % (E, E*AtomicData.hartree_to_eV) k = np.sqrt(2*E) wavelength = 2.0 * np.pi/k bs_free = AtomicScatteringBasisSet(atomlist, E, rmin=0.0, rmax=Rmax+2*wavelength, Npts=Npts) SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf, inter_atomic=inter_atomic).real orientation_averaging = PAD.OrientationAveraging_small_memory(Dipole, bs_free, Rmax, E, npts_euler=npts_euler, npts_theta=npts_theta) pad,betasE = orientation_averaging.averaged_pad(dyson_orbs[:,iorb]) pad_data.append( [E*AtomicData.hartree_to_eV] + list(betasE) ) # save PAD for this energy print>>fh, "%10.6f %10.6e %+10.6e %+10.6f %+10.6e %+10.6e" % tuple(pad_data[-1]) fh.flush() fh.close()
def test_photoangular_distribution(): from DFTB.LR_TDDFTB import LR_TDDFTB from DFTB import XYZ from DFTB.Scattering import slako_tables_scattering # BOUND ORBITAL = H**O atomlist = XYZ.read_xyz("./h2.xyz")[0] tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options = {"nstates": 1} tddftb.getEnergies(**options) valorbs, radial_val = load_pseudo_atoms(atomlist) H**O, LUMO = tddftb.dftb2.getFrontierOrbitals() bound_orbs = tddftb.dftb2.getKSCoefficients() # according to Koopman's theorem the electron is ionized from the H**O mo_indx = range(0, len(bound_orbs)) nmo = len(mo_indx) energies = [[] for i in range(0, nmo)] sigmas = [[] for i in range(0, nmo)] betas = [[] for i in range(0, nmo)] tdip2s = [[] for i in range(0, nmo)] for imo in range(0, nmo): mo_bound = bound_orbs[:, mo_indx[imo]] # CONTINUUM ORBITALS at energy E for E in slako_tables_scattering.energies: SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) S_bb, H0_bb = tddftb.dftb2._constructH0andS() S_bf, H0_bf = ScatteringHamiltonianMatrix(atomlist, valorbs, SKT_bf) # invS_bb = la.inv(S_bb) # (H-E*S)^t . Id . (H-E*S) HmE2 = np.dot(H0_bf.conjugate().transpose(), np.dot(invS_bb, H0_bf)) \ - E * np.dot( S_bf.conjugate().transpose(), np.dot(invS_bb, H0_bf)) \ - E * np.dot(H0_bf.conjugate().transpose(), np.dot(invS_bb, S_bf)) \ + E**2 * np.dot(S_bf.conjugate().transpose(), np.dot(invS_bb, S_bf)) # scat_lambdas, scat_orbs = sla.eigh(HmE2) print "PKE = %s" % E print "lambdas = %s" % scat_lambdas # photoangular distribution averaged over isotropically oriented ensemble of molecules Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf) sigma = 0.0 beta = 0.0 tdip2 = 0.0 olap = 0.0 for i in range(0, len(scat_lambdas)): if abs(scat_lambdas[i]) > 1.0e-10: print "%d lambda = %s" % (i, scat_lambdas[i]) mo_scatt = scat_orbs[:, i] sigma_i, beta_i = angular_distribution( atomlist, valorbs, mo_bound, mo_scatt, Dipole) sigma += sigma_i beta += sigma_i * beta_i tdip_i = np.zeros(3, dtype=complex) for xyz in range(0, 3): tdip_i[xyz] += np.dot( mo_bound, np.dot(Dipole[:, :, xyz], mo_scatt)) tdip2 += np.sum(abs(tdip_i)**2) print "tdip2 = %s" % tdip2 beta /= sigma #### #sigma_test, beta_test = angular_distribution_old2(atomlist, valorbs, mo_bound, mo_scatt, Dipole) #assert abs(sigma-sigma_test) < 1.0e-10 #assert abs(beta-beta_test) < 1.0e-10 #### print "E= %s sigma=%s beta= %s" % (E, sigma, beta) energies[imo].append(E) sigmas[imo].append(sigma.real) betas[imo].append(beta.real) tdip2s[imo].append(tdip2) energies = np.array(energies) sigmas = np.array(sigmas) betas = np.array(betas) from matplotlib import pyplot as plt # total cross section plt.xlabel("PKE / eV") plt.ylabel("total photoionization cross section $\sigma$") for imo in range(0, nmo): plt.plot(energies[imo] * 27.211, sigmas[imo], lw=2) #plt.plot(energies[imo]*27.211, tdip2s[imo], lw=2, ls="-.") plt.show() # anisotropy plt.cla() plt.ylim((-1.0, 2.0)) plt.xlabel("PKE / eV") plt.ylabel("anisotropy $\\beta_2$") for imo in range(0, nmo): plt.plot(energies[imo] * 27.211, betas[imo], lw=2, label="%d" % imo) plt.legend() plt.show() return energies, sigmas, betas
def test_scattering_orbitals(): from DFTB.LR_TDDFTB import LR_TDDFTB from DFTB import XYZ atomlist = XYZ.read_xyz("h2.xyz")[0] tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options = {"nstates": 1} tddftb.getEnergies(**options) valorbs, radial_val = load_pseudo_atoms(atomlist) E = 5.0 / 27.211 bs = AtomicScatteringBasisSet(atomlist, E) print bs.bfs SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) S_bb, H0_bb = tddftb.dftb2._constructH0andS() S_bf, H0_bf = ScatteringHamiltonianMatrix(atomlist, valorbs, SKT_bf) # invS_bb = la.inv(S_bb) # (H-E*S)^t . Id . (H-E*S) HmE2 = np.dot(H0_bf.conjugate().transpose(), np.dot(invS_bb, H0_bf)) \ - E * np.dot( S_bf.conjugate().transpose(), np.dot(invS_bb, H0_bf)) \ - E * np.dot(H0_bf.conjugate().transpose(), np.dot(invS_bb, S_bf)) \ + E**2 * np.dot(S_bf.conjugate().transpose(), np.dot(invS_bb, S_bf)) Scont = continuum_flux(atomlist, SKT_bf) S2 = np.dot(S_bf.conjugate().transpose(), np.dot(la.inv(S_bb), S_bf)) """ # H2 = np.dot(H0_bf.transpose(), np.dot(la.inv(S_bb), H0_bf)) S2 = np.dot( S_bf.transpose(), np.dot(la.inv(S_bb), S_bf)) print "H2" print H2 print "S2" print S2 scat_orbe2, scat_orbs = sla.eig(H2) #, S2) print "PKE = %s" % E print "Energies^2 = %s" % scat_orbe2 scat_orbe = np.sqrt(scat_orbe2) sort_indx = np.argsort(scat_orbe) scat_orbe = scat_orbe[sort_indx] scat_orbs = scat_orbs[:,sort_indx] print "Energies of scattering orbitals: %s" % scat_orbe orbE = np.argmin(abs(scat_orbe-E)) """ assert np.sum(abs(HmE2.conjugate().transpose() - HmE2)) < 1.0e-10 assert np.sum(abs(S2.conjugate().transpose() - S2)) < 1.0e-10 lambdas, scat_orbs = sla.eigh(HmE2) print "lambdas = %s" % lambdas from DFTB.Scattering import PAD for i in range(0, len(lambdas)): if abs(lambdas[i]) > 1.0e-8: print "%d lambda = %s" % (i, lambdas[i]) ### def wavefunction(grid, dV): # evaluate orbital amp = Cube.orbital_amplitude(grid, bs.bfs, scat_orbs[:, i], cache=False) return amp PAD.asymptotic_density(wavefunction, 20, E) ### for (flm, l, m) in classify_lm(bs, scat_orbs[:, i]): if abs(flm).max() > 1.0e-4: print " %s %s %s" % (l, m, abs(flm)) Cube.orbital2grid(atomlist, bs.bfs, scat_orbs[:,i], \ filename="/tmp/scattering_orbital_%d.cube" % i, dbuff=25.0) delattr(Cube.orbital_amplitude, "cached_grid")
#test_dipole_prepared_continuum() test_averaged_asymptotic_density() #test_photoangular_distribution() exit(-1) #atomlist = [(8,(0,0,0))] atomlist = [(1, (0, 0, 0)), (1, (0, 0, 3.0))] energies = [] sigmas = [] betas = [] for E in np.linspace(0.001, 5.0 / 27.211, 20): SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) #print SKT valorbs, radial_val = load_pseudo_atoms(atomlist) Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf) #print Dipole mos_bound = np.array([1.0, 1.0]) #mos_bound = np.array([1.0,-1.0]) mos_bound /= la.norm(mos_bound) mos_scatt = np.array([0.0, 1.0, 1.0, 1.0] + [0.0, 1.0, 1.0, 1.0]) #mos_scatt = np.array([0.0, 1.0,1.0,1.0] + [0.0, 1.0,1.0,1.0]) mos_scatt /= la.norm(mos_scatt) #sigma, beta = angular_distribution_old(atomlist, valorbs, mos_bound, mos_scatt, Dipole) #print "OLD E= %s sigma=%s beta= %s" % (E,sigma, beta) sigma, beta = angular_distribution(atomlist, valorbs, mos_bound, mos_scatt, Dipole)
def atomic_pz_orbital(Z, data_file): atomlist = [(Z, (0.0, 0.0, 0.0))] # compute molecular orbitals with DFTB print "compute molecular orbitals with tight-binding DFT" tddftb = LR_TDDFTB(atomlist) tddftb.setGeometry(atomlist, charge=0) options = {"nstates": 1} try: tddftb.getEnergies(**options) except DFTB.Solver.ExcitedStatesNotConverged: pass valorbs, radial_val = load_pseudo_atoms(atomlist) bound_orbs = tddftb.dftb2.getKSCoefficients() # order of orbitals s, py,pz,px, dxy,dyz,dz2,dzx,dx2y2, so the pz-orbital has index 2 mo_bound = bound_orbs[:, 2] tdipole_data = [] for iE, E in enumerate(slako_tables_scattering.energies): print "PKE = %s" % E try: SKT_bf, SKT_ff = load_slako_scattering(atomlist, E) except ImportError: break Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf).real # dipole between bound orbital and the continuum AO basis orbitals dipole_bf = np.tensordot(mo_bound, Dipole, axes=(0, 0)) tdip_pz_to_s = dipole_bf[0, 2] # points along z-axis tdip_pz_to_dyz = dipole_bf[5, 1] # points along y-axis tdip_pz_to_dz2 = dipole_bf[6, 2] # points along z-axis tdip_pz_to_dzx = dipole_bf[7, 0] # points along x-axis tdipole_data.append( [E * AtomicData.hartree_to_eV] + [tdip_pz_to_s, tdip_pz_to_dyz, tdip_pz_to_dz2, tdip_pz_to_dzx]) #### # determine the radius of the sphere where the angular distribution is calculated. It should be # much larger than the extent of the molecule (xmin, xmax), (ymin, ymax), (zmin, zmax) = Cube.get_bbox(atomlist, dbuff=0.0) dx, dy, dz = xmax - xmin, ymax - ymin, zmax - zmin Rmax = max([dx, dy, dz]) + 500.0 print "Radius of sphere around molecule, Rmax = %s bohr" % Rmax k = np.sqrt(2 * E) wavelength = 2.0 * np.pi / k print "wavelength = %s" % wavelength valorbsE, radial_valE = load_pseudo_atoms_scattering(atomlist, E, rmin=0.0, rmax=Rmax + 2 * wavelength, Npts=90000) # Plot radial wavefunctions import matplotlib.pyplot as plt plt.ion() r = np.linspace(0.0, Rmax + 2 * wavelength, 5000) for i, (Zi, posi) in enumerate(atomlist): for indx, (ni, li, mi) in enumerate(valorbsE[Zi]): # only plot the dz2 continuum orbital if li == 2 and mi == 0 and (iE % 10 == 0): R_spl = radial_valE[Zi][indx] radial_orbital_wfn = R_spl(r) plt.plot(r, radial_orbital_wfn, label="Z=%s n=%s l=%s m=%s E=%s" % (Zi, ni, li, mi, E)) plt.plot(r, np.sin(k * r) / r, ls="-.") #plt.plot(r, np.sin(k*r + 1.0/k * np.log(2*k*r))/r, ls="--", lw=2) plt.plot(r, np.array([ float(mpmath.coulombf(li, -1.0 / k, k * rx)) / rx for rx in r ]), ls="--", lw=2, label="CoulombF l=%s E=%s" % (li, E)) plt.draw() #### # save table fh = open(data_file, "w") print >> fh, "# PKE/eV pz->s pz->dyz pz->dz2 pz->dzx" np.savetxt(fh, tdipole_data) fh.close() print "Wrote table with transition dipoles to %s" % data_file # show radial wavefunctions plt.ioff() plt.show()
def build_water_cluster(atomlist_template, orbital_names, phases): """ build a cluster orbital as a linear combination of monomer orbitals with the correct orientation. The position and orientation of the water molecules is taken from the template. Parameters: =========== atomlist_template: molecular geometry for cluster with n water molecules orbital_names: list of orbital names ('1b1', '3a1', '1b2' or '2a1') for each of the n water molecules phases: list of +1 or -1's for each orbital Returns: ======== water_cluster: molecular geometry of the cluster orb_cluster: cluster orbital, that is a linear combination of the monomer orbitals. """ # water geometry in bohr water_std = [(1, (0.0, 0.8459947982381987, -1.4473477675908173)), (8, (0.0, -0.21392561795490195, 0.0 )), (1, (0.0, 0.8459947982381987, 1.4473477675908173))] valorbs, radial_val = load_pseudo_atoms(water_std) # Orbitals for H2O monomer in standard orientation: # molecular plane = yz-plane, oxygen lies on the negative y-axis, H-H bond is parallel to z-axis # H1-1s O-2s O-2py O-2pz O-2px H2-1s monomer_orbitals = { "1b1": np.array([ 0.0000, 0.0000, 0.0000, 0.0000, 1.0000, 0.0000]), "3a1": np.array([ 0.7816,-0.6842, 0.6989, 0.0000, 0.0000, 0.7816]), "1b2": np.array([-0.7264, 0.0000, 0.0000, 0.9429, 0.0000, 0.7264]), "2a1": np.array([ 0.1730, 0.8662, 0.0393, 0.0000, 0.0000, 0.1730]) } # First the individual water molecules in the template are identified and their positions # and orientations are extracted. fragments = MolecularGraph.disconnected_fragments(atomlist_template) assert len(fragments) == len(orbital_names) == len(phases), "For each water fragment in the cluster you need to specify one fragment orbital ('1b1', '3a1', '1b2' or '2a1') and its phase" orb_cluster = [] # list of MO coefficients water_cluster = [] # list of atoms for i,water in enumerate(fragments): # the Euler angles (a,b,g) specify the orientation of the i-th water molecule water_std_i, (a,b,g), cm = MolCo.molecular_frame_transformation(water) print "WATER STANDARD" for (Zi,posi) in water_std: print " %s %8.6f %8.6f %8.6f" % (Zi, posi[0], posi[1], posi[2]) print "WATER STANDARD %d" % i for (Zi,posi) in water_std_i: print " %s %8.6f %8.6f %8.6f" % (Zi, posi[0], posi[1], posi[2]) # The desired orbital is placed on the i-th water molecule and is # rotated to match the orientation of the molecule. orb_monomer = monomer_orbitals[orbital_names[i]] # rotate orbital orb_monomer_rot = OrbitalRotations.rotate_orbitals(water_std, valorbs, orb_monomer, (a,b,g)) # add orbital with desired phase to cluster MOs orb_cluster += list(phases[i] * orb_monomer_rot) # rotate geometry water_rot = MolCo.transform_molecule(water_std, (a,b,g), cm) XYZ.write_xyz("/tmp/water_std.xyz", [water_std, water_rot]) water_cluster += water_rot # Assuming that the overlap between orbitals on different water molecules is negligible, # we can normalize the cluster orbital by dividing through sqrt(number of water molecules) n = np.sum(abs(np.array(phases))) # a phase of 0 indicates no orbital orb_cluster /= np.sqrt(n) return water_cluster, orb_cluster
def __init__(self, xyz_file, dyson_file=None): super(Main, self).__init__() self.settings = Settings({ "Continuum Orbital": { "Ionization transitions": [0, ["only intra-atomic", "inter-atomic"]] }, "Averaging": { "Euler angle grid points": 5, "polar angle grid points": 1000, "sphere radius Rmax": 300.0, }, "Scan": { "nr. points": 20 }, "Cube": { "extra space / bohr": 15.0, "points per bohr": 3.0 } }) # perform DFTB calculation # BOUND ORBITAL = H**O self.atomlist = XYZ.read_xyz(xyz_file)[0] # shift molecule to center of mass print "shift molecule to center of mass" pos = XYZ.atomlist2vector(self.atomlist) masses = AtomicData.atomlist2masses(self.atomlist) pos_com = MolCo.shift_to_com(pos, masses) self.atomlist = XYZ.vector2atomlist(pos_com, self.atomlist) self.tddftb = LR_TDDFTB(self.atomlist) self.tddftb.setGeometry(self.atomlist, charge=0) options = {"nstates": 1} try: self.tddftb.getEnergies(**options) except DFTB.Solver.ExcitedStatesNotConverged: pass self.valorbs, radial_val = load_pseudo_atoms(self.atomlist) if dyson_file == None: # Kohn-Sham orbitals are taken as Dyson orbitals self.H**O, self.LUMO = self.tddftb.dftb2.getFrontierOrbitals() self.bound_orbs = self.tddftb.dftb2.getKSCoefficients() self.orbe = self.tddftb.dftb2.getKSEnergies() orbital_names = [] norb = len(self.orbe) for o in range(0, norb): if o < self.H**O: name = "occup." elif o == self.H**O: name = "H**O" elif o == self.LUMO: name = "LUMO " else: name = "virtual" name = name + " " + str(o).rjust(4) + ( " %+10.3f eV" % (self.orbe[o] * 27.211)) orbital_names.append(name) initially_selected = self.H**O else: # load coefficients of Dyson orbitals from file names, ionization_energies, self.bound_orbs = load_dyson_orbitals( dyson_file) self.orbe = np.array(ionization_energies) / 27.211 orbital_names = [] norb = len(self.orbe) for o in range(0, norb): name = names[o] + " " + str(o).rjust(4) + ( " %4.2f eV" % (self.orbe[o] * 27.211)) orbital_names.append(name) initially_selected = 0 self.photo_kinetic_energy = slako_tables_scattering.energies[0] self.epol = np.array([15.0, 0.0, 0.0]) # Build Graphical User Interface main = QtGui.QWidget() mainLayout = QtGui.QHBoxLayout(main) # selectionFrame = QtGui.QFrame() selectionFrame.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred) mainLayout.addWidget(selectionFrame) selectionLayout = QtGui.QVBoxLayout(selectionFrame) # label = QtGui.QLabel(selectionFrame) label.setText("Select bound MO:") selectionLayout.addWidget(label) # bound orbitals self.orbitalSelection = QtGui.QListWidget(selectionFrame) self.orbitalSelection.itemSelectionChanged.connect( self.selectBoundOrbital) norb = len(self.orbe) self.orbital_dict = {} for o in range(0, norb): name = orbital_names[o] self.orbital_dict[name] = o item = QtGui.QListWidgetItem(name, self.orbitalSelection) if o == initially_selected: selected_orbital_item = item selectionLayout.addWidget(self.orbitalSelection) ### VIEWS center = QtGui.QWidget() mainLayout.addWidget(center) centerLayout = QtGui.QGridLayout(center) # boundFrame = QtGui.QFrame() centerLayout.addWidget(boundFrame, 1, 1) boundLayout = QtGui.QVBoxLayout(boundFrame) # "Bound Orbital" label = QtGui.QLabel(boundFrame) label.setText("Bound Orbital") boundLayout.addWidget(label) # self.boundOrbitalViewer = QCubeViewerWidget(boundFrame) boundLayout.addWidget(self.boundOrbitalViewer) # continuum orbital continuumFrame = QtGui.QFrame() centerLayout.addWidget(continuumFrame, 1, 2) continuumLayout = QtGui.QVBoxLayout(continuumFrame) # "Dipole-Prepared Continuum Orbital" label = QtGui.QLabel(continuumFrame) label.setText("Dipole-Prepared Continuum Orbital") continuumLayout.addWidget(label) self.continuumOrbitalViewer = QCubeViewerWidget(continuumFrame) continuumLayout.addWidget(self.continuumOrbitalViewer) self.efield_objects = [] self.efield_actors = [] self.selected = None # picker self.picker = self.continuumOrbitalViewer.visualization.scene.mayavi_scene.on_mouse_pick( self.picker_callback) self.picker.tolerance = 0.01 # PHOTO KINETIC ENERGY sliderFrame = QtGui.QFrame(continuumFrame) continuumLayout.addWidget(sliderFrame) sliderLayout = QtGui.QHBoxLayout(sliderFrame) # label self.pke_label = QtGui.QLabel() self.pke_label.setText("PKE: %6.4f eV" % (self.photo_kinetic_energy * 27.211)) sliderLayout.addWidget(self.pke_label) # Slider for changing the PKE self.pke_slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.pke_slider.setMinimum(0) self.pke_slider.setMaximum(len(slako_tables_scattering.energies) - 1) self.pke_slider.setValue(0) self.pke_slider.sliderReleased.connect(self.changePKE) self.pke_slider.valueChanged.connect(self.searchPKE) sliderLayout.addWidget(self.pke_slider) # # molecular frame photoangular distribution mfpadFrame = QtGui.QFrame() centerLayout.addWidget(mfpadFrame, 2, 1) mfpadLayout = QtGui.QVBoxLayout(mfpadFrame) mfpadLayout.addWidget(QtGui.QLabel("Molecular Frame PAD")) mfpadTabs = QtGui.QTabWidget() mfpadLayout.addWidget(mfpadTabs) # 2D map mfpadFrame2D = QtGui.QFrame() mfpadTabs.addTab(mfpadFrame2D, "2D") mfpadLayout2D = QtGui.QVBoxLayout(mfpadFrame2D) self.MFPADfig2D = Figure() self.MFPADCanvas2D = FigureCanvas(self.MFPADfig2D) mfpadLayout2D.addWidget(self.MFPADCanvas2D) self.MFPADCanvas2D.draw() NavigationToolbar(self.MFPADCanvas2D, mfpadFrame2D, coordinates=True) # 3D mfpadFrame3D = QtGui.QFrame() mfpadTabs.addTab(mfpadFrame3D, "3D") mfpadLayout3D = QtGui.QVBoxLayout(mfpadFrame3D) self.MFPADfig3D = Figure() self.MFPADCanvas3D = FigureCanvas(self.MFPADfig3D) mfpadLayout3D.addWidget(self.MFPADCanvas3D) self.MFPADCanvas3D.draw() NavigationToolbar(self.MFPADCanvas3D, mfpadFrame3D, coordinates=True) # orientation averaged photoangular distribution avgpadFrame = QtGui.QFrame() centerLayout.addWidget(avgpadFrame, 2, 2) avgpadLayout = QtGui.QVBoxLayout(avgpadFrame) self.activate_average = QtGui.QCheckBox("Orientation Averaged PAD") self.activate_average.setToolTip( "Check this box to start averaging of the molecular frame PADs over all orientations. This can take a while." ) self.activate_average.setCheckState(QtCore.Qt.Unchecked) self.activate_average.stateChanged.connect(self.activateAveragedPAD) avgpadLayout.addWidget(self.activate_average) avgpadTabs = QtGui.QTabWidget() avgpadLayout.addWidget(avgpadTabs) # 1D map avgpadFrame1D = QtGui.QFrame() avgpadTabs.addTab(avgpadFrame1D, "1D") avgpadLayout1D = QtGui.QVBoxLayout(avgpadFrame1D) self.AvgPADfig1D = Figure() self.AvgPADCanvas1D = FigureCanvas(self.AvgPADfig1D) avgpadLayout1D.addWidget(self.AvgPADCanvas1D) self.AvgPADCanvas1D.draw() NavigationToolbar(self.AvgPADCanvas1D, avgpadFrame1D, coordinates=True) # 2D map avgpadFrame2D = QtGui.QFrame() avgpadFrame2D.setToolTip( "The averaged PAD should have no phi-dependence anymore. A phi-dependence is a sign of incomplete averaging." ) avgpadTabs.addTab(avgpadFrame2D, "2D") avgpadLayout2D = QtGui.QVBoxLayout(avgpadFrame2D) self.AvgPADfig2D = Figure() self.AvgPADCanvas2D = FigureCanvas(self.AvgPADfig2D) avgpadLayout2D.addWidget(self.AvgPADCanvas2D) self.AvgPADCanvas2D.draw() NavigationToolbar(self.AvgPADCanvas2D, avgpadFrame2D, coordinates=True) # Table avgpadFrameTable = QtGui.QFrame() avgpadTabs.addTab(avgpadFrameTable, "Table") avgpadLayoutTable = QtGui.QVBoxLayout(avgpadFrameTable) self.avgpadTable = QtGui.QTableWidget(0, 6) self.avgpadTable.setToolTip( "Activate averaging and move the PKE slider above to add a new row with beta values. After collecting betas for different energies you can save the table or plot a curve beta(PKE) for the selected orbital." ) self.avgpadTable.setHorizontalHeaderLabels( ["PKE / eV", "sigma", "beta1", "beta2", "beta3", "beta4"]) avgpadLayoutTable.addWidget(self.avgpadTable) # Buttons buttonFrame = QtGui.QFrame() avgpadLayoutTable.addWidget(buttonFrame) buttonLayout = QtGui.QHBoxLayout(buttonFrame) deleteButton = QtGui.QPushButton("Delete") deleteButton.setToolTip("clear table") deleteButton.clicked.connect(self.deletePADTable) buttonLayout.addWidget(deleteButton) buttonLayout.addSpacing(3) scanButton = QtGui.QPushButton("Scan") scanButton.setToolTip( "fill table by scanning automatically through all PKE values") scanButton.clicked.connect(self.scanPADTable) buttonLayout.addWidget(scanButton) saveButton = QtGui.QPushButton("Save") saveButton.setToolTip("save table as a text file") saveButton.clicked.connect(self.savePADTable) buttonLayout.addWidget(saveButton) plotButton = QtGui.QPushButton("Plot") plotButton.setToolTip("plot beta2 column as a function of PKE") plotButton.clicked.connect(self.plotPADTable) buttonLayout.addWidget(plotButton) """ # DOCKS self.setDockOptions(QtGui.QMainWindow.AnimatedDocks | QtGui.QMainWindow.AllowNestedDocks) # selectionDock = QtGui.QDockWidget(self) selectionDock.setWidget(selectionFrame) selectionDock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable) self.addDockWidget(QtCore.Qt.DockWidgetArea(1), selectionDock) # boundDock = QtGui.QDockWidget(self) boundDock.setWidget(boundFrame) boundDock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable) boundDock.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) self.addDockWidget(QtCore.Qt.DockWidgetArea(2), boundDock) # continuumDock = QtGui.QDockWidget(self) continuumDock.setWidget(continuumFrame) continuumDock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable) continuumDock.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) self.addDockWidget(QtCore.Qt.DockWidgetArea(2), continuumDock) """ self.setCentralWidget(main) self.status_bar = QtGui.QStatusBar(main) self.setStatusBar(self.status_bar) self.default_message = "Click on the tip of the green arrow in the top right figure to change the orientation of the E-field" self.statusBar().showMessage(self.default_message) # Menu bar menubar = self.menuBar() exitAction = QtGui.QAction('&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit program') exitAction.triggered.connect(exit) fileMenu = menubar.addMenu('&File') fileMenu.addAction(exitAction) settingsMenu = menubar.addMenu('&Edit') settingsAction = QtGui.QAction('&Settings...', self) settingsAction.setStatusTip('Edit settings') settingsAction.triggered.connect(self.editSettings) settingsMenu.addAction(settingsAction) self.loadContinuum() # select H**O selected_orbital_item.setSelected(True)