def plot_exciton_spectrum(en, T, M, broadening=0.005, units="nm"): """ plot absorption and circular dichroism spectra on top of each other Parameters ---------- en: numpy array with shape (Nst), excitation energies in Hartree T : numpy array with shape (3,Nst), electric transition dipoles M : numpy array with shape (3,Nst), magnetic transition dipoles """ # oscillator strengths and rotational strength nst = len(en) f = np.zeros(nst) R = np.zeros(nst) angleEM = np.zeros(nst) for i in range(0, nst): f[i] = 2.0/3.0 * en[i] * np.dot(T[:,i].conjugate(), T[:,i]) # Im{ T_(0->i) * M[i->0] } R[i] = np.dot(T[:,i], M[:,i]) import matplotlib.pyplot as plt from DFTB.Analyse.absorption_spectrum import broadened_spectrum, convert_energy ens, ab_spec = broadened_spectrum(en, f, broadening) ens, cd_spec = broadened_spectrum(en, R, broadening) ax_cd = plt.subplot(211) ax_ab = plt.subplot(212, sharex = ax_cd) # convert energies from Hartree to nm ens = convert_energy(ens, "Hartree", units) fs = 18.0 # fontsize ax_cd.set_xlabel("Energy / %s" % units, fontsize=fs) # circular dichroism spectrum ax_cd.plot(ens, cd_spec) ax_cd.set_ylabel("Rotational Strength / arb. units", fontsize=fs) # absorption spectrum ax_ab.plot(ens, ab_spec) ax_cd.set_ylabel("Oscillator Strength / arb. units", fontsize=fs) plt.show()
def plotDOS(self): self.figDOS.clf() ax = self.figDOS.add_subplot(111) units = self.energyUnits.itemText(self.energyUnits.currentIndex()) broadening = abs(float(self.broadening.text())) ax.set_title("Density of States (DOS)") ax.set_xlabel("Kohn-Sham Energy / %s" % units, fontsize=15) ax.set_ylabel("DOS / arbitrary units", fontsize=15) ens = self.tddftb.dftb2.getKSEnergies() dos = 1.0 * np.ones(ens.shape) # stick spectrum ens_out = convert_energy(ens, "Hartree", units) ax.vlines(ens_out, np.zeros(ens_out.shape), dos, lw=2, color="black", picker=5) # selected states are highlighted selected = self.tableMOs.selectionModel().selectedRows() for s in selected: i = s.row() ax.vlines(ens_out[i], [0.0], dos[i], lw=3, color="green") ax.text(ens_out[i], dos[i], "%s %s" % (i + 1, self.mo_names[i])) def onpick(event): self.tableMOs.setCurrentCell(event.ind[0], 0) self.figDOS.canvas.mpl_connect('pick_event', onpick) if broadening > 0.0: ens_broadened, spec = broadened_spectrum(ens, dos, broadening) ens_broadened_out = convert_energy(ens_broadened, "Hartree", units) scale = spec.max() / dos.max() / 1.1 x, y = ens_broadened_out, spec / scale ax.plot(x, y, lw=1, color="blue") x_occ = x[x <= ens_out[self.H**O]] y_occ = y[x <= ens_out[self.H**O]] x_virt = x[x >= ens_out[self.LUMO]] y_virt = y[x >= ens_out[self.LUMO]] ax.fill_between(x_occ, 0, y_occ, alpha=0.5, color="blue") ax.fill_between(x_virt, 0, y_virt, alpha=0.5, color="red") ax.annotate('', xy=(ens_out[self.H**O], 1.1), xycoords='data', xytext=(ens_out[self.LUMO], 1.1), textcoords='data', arrowprops={'arrowstyle': '<->'}) ax.annotate( 'gap = %4.3f' % (ens_out[self.LUMO] - ens_out[self.H**O]), xy=((ens_out[self.H**O] + ens_out[self.LUMO]) / 2.0, 1.1), xycoords='data', xytext=(0, 5), textcoords='offset points') self.canvasDOS.draw() self.showMullikenCharges() if len(selected) > 0: i = selected[0].row() self.moLabel.setText("Molecular Orbital: %s %s" % (i + 1, self.mo_names[i])) if i in self.mo_cubes: mo_cube = self.mo_cubes[i] self.molecularOrbitalViewer.setCubes([mo_cube]) else: print("No cube for molecular orbital %d" % (i + 1))
def plotSpectrum(self): self.figSpectrum.clf() ax = self.figSpectrum.add_subplot(111) units = self.energyUnits.itemText(self.energyUnits.currentIndex()) broadening = abs(float(self.broadening.text())) ax.set_title("Absorption Spectrum") ax.set_xlabel("Excitation Energy / %s" % units, fontsize=15) ax.set_ylabel("Oscillator strength", fontsize=15) ens = self.tddftb.Omega osz = self.tddftb.oscillator_strength # stick spectrum ens_out = convert_energy(ens, "Hartree", units) ax.vlines(ens_out, np.zeros(ens_out.shape), osz, lw=2, color="black", picker=5) # selected states are highlighted selected = self.tableStates.selectionModel().selectedRows() for s in selected: I = s.row() ax.vlines(ens_out[I], [0.0], osz[I], lw=3, color="green") ax.text( ens_out[I], osz[I], "%s (%s$_{%d}$)" % (self.tddftb.Irreps[I], self.tddftb.multiplicity, I + 1)) def onpick(event): self.tableStates.setCurrentCell(event.ind[0], 0) self.figSpectrum.canvas.mpl_connect('pick_event', onpick) if broadening > 0.0: ens_broadened, spec = broadened_spectrum(ens, osz, broadening) ens_broadened_out = convert_energy(ens_broadened, "Hartree", units) scale = spec.max() / osz.max() / 1.1 ax.plot(ens_broadened_out, spec / scale, lw=1, color="blue") self.canvasSpectrum.draw() if len(selected) > 0: I = selected[0].row() self.tdenseLabel.setText( "Excited State: %s (%s%d)" % (self.tddftb.Irreps[I], self.tddftb.multiplicity, I + 1)) self.showPartialCharges(I) if I in self.tdense_cubes: tdense_cube = self.tdense_cubes[I] self.transitionDensityViewer.setCubes([tdense_cube]) difdense_cube = self.difdense_cubes[I] self.differenceDensityViewer.setCubes([difdense_cube]) else: print( "No cube for transition and difference density of state %d" % (I + 1)) # transition densities in occ-virt plane self.plotExcitationCoefficients2D(I) self.canvasExvec.draw()