def v_integral(t1, t2, centroid=None, Snuc=None): """Returns potential coupling matrix element between two trajectories.""" # evaluate just the nuclear component (for re-use) if Snuc is None: Snuc = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) states = np.sort(np.array([t1.state, t2.state])) v_total = complex(0., 0.) # roll through terms in the hamiltonian for i in range(glbl.pes.ham.nterms): if np.array_equal(states, glbl.pes.ham.stalbl[i, :] - 1): # adiabatic states in diabatic basis -- cross terms between orthogonal # diabatic states are zero [s1, s2] = glbl.pes.ham.stalbl[i, :] - 1 v_term = complex(1., 0.) * glbl.pes.ham.coe[i] for q in range(len(glbl.pes.ham.order[i])): qi = glbl.pes.ham.mode[i][q] v_term *= nuclear.prim_v_integral(glbl.pes.ham.order[i][q], t1.widths()[qi], t1.x()[qi], t1.p()[qi], t2.widths()[qi], t2.x()[qi], t2.p()[qi]) v_total += v_term return v_total * Snuc
def traj_overlap(traj1, traj2, nuc_only=False): """ Returns < Psi | Psi' >, the overlap integral of two trajectories""" if traj1.state != traj2.state and not nuc_only: return 0j else: return gauss.overlap(traj1.phase(), traj1.widths(), traj1.x(), traj1.p(), traj2.phase(), traj2.widths(), traj2.x(), traj2.p())
def traj_overlap(traj1, traj2, centroid, nuc_only=False): """ Returns < Psi | Psi' >, the overlap integral of two trajectories""" nuc_ovrlp = nuclear.overlap(traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) if nuc_only: return nuc_ovrlp else: return nuc_ovrlp * elec_overlap(traj1, traj2, centroid)
def s_integral(t1, t2, nuc_only=False, Snuc=None): """ Returns < Psi | Psi' >, the overlap of the nuclear component of the wave function only""" if t1.state != t2.state and not nuc_only: return complex(0., 0.) else: if Snuc is None: return nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) else: return Snuc
def ke_integral(t1, t2, Snuc=None): """Returns kinetic energy integral over trajectories.""" if t1.state != t2.state: return complex(0., 0.) else: if Snuc is None: Snuc = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) ke = nuclear.deld2x(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) return -sum(ke * glbl.pes.kecoeff)
def ke_integral(traj1, traj2, centroid=None, Snuc=None): """Returns kinetic energy integral over trajectories.""" # evaluate just the nuclear component (for re-use) if Snuc is None: Snuc = nuclear.overlap(traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) # overlap of electronic functions Selec = elec_overlap(traj1, traj2) # < chi | del^2 / dx^2 | chi'> ke = nuclear.deld2x(Snuc,traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) return -sum( ke * vibronic.kecoeff) * Selec
def sdot_integral(t1, t2, Snuc=None): """Returns the matrix element <Psi_1 | d/dt | Psi_2>.""" if t1.state != t2.state: return complex(0., 0.) else: if Snuc is None: Snuc = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) t1_dx_t2 = nuclear.deldx(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) t1_dp_t2 = nuclear.deldp(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) sdot = (np.dot(t2.velocity(), t1_dx_t2) + np.dot(t2.force(), t1_dp_t2) + 1.j * t2.phase_dot() * Snuc) return sdot
def v_integral(t1, t2, centroid=None, Snuc=None): """Returns potential coupling matrix element between two trajectories.""" # if we are passed a single trajectory, this is a diagonal # matrix element -- simply return potential energy of trajectory if t1.label == t2.label: # Adiabatic energy v = t1.energy(t1.state) # DBOC if glbl.interface['coupling_order'] == 3: v += t1.scalar_coup(t1.state, t2.state) return v if Snuc is None: Snuc = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) # Snuc = nuclear.overlap(t1,t2) # off-diagonal matrix element, between trajectories on the same # state (this also requires the centroid be present) elif t1.state == t2.state: # Adiabatic energy v = centroid.energy(t1.state) * Snuc # DBOC if glbl.interface['coupling_order'] == 3: v += centroid.scalar_coup(t1.state, t2.state) * Snuc return v # [necessarily] off-diagonal matrix element between trajectories # on different electronic states elif t1.state != t2.state: # Derivative coupling fij = centroid.derivative(t1.state, t2.state) v = 2. * np.vdot( fij, glbl.pes.kecoeff * nuclear.deldx(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p())) # nuclear.deldx(t1, t2, S=Snuc)) # Scalar coupling if glbl.interface['coupling_order'] > 1: v += centroid.scalar_coup(t1.state, t2.state) * Snuc return v else: print('ERROR in v_integral -- argument disagreement') return 0j
def sdot_integral(t1, t2, Snuc=None, e_only=False, nuc_only=False): """Returns the matrix element <Psi_1 | d/dt | Psi_2>.""" if t1.state != t2.state: return 0j else: if Snuc is None: Snuc = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) deldx = nuclear.deldx(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) deldp = nuclear.deldp(Snuc, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) sdot = (np.dot(deldx, t2.velocity()) + np.dot(deldp, t2.force()) + 1j * t2.phase_dot() * Snuc) return sdot
def v_integral(traj1, traj2, centroid=None, Snuc=None): """Returns potential coupling matrix element between two trajectories.""" # evaluate just the nuclear component (for re-use) if Snuc is None: Snuc = nuclear.overlap(traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) dx_1 = traj1.x() - centroid.x() dx_2 = traj2.x() - centroid.x() dp = traj1.p() - traj2.p() if traj1.tid == traj2.tid: vint = Snuc * (traj1.energy(traj1.state) + 0.5*np.dot(centroid.derivative(traj1.state,traj1.state), dx_1 + dx_2 - 1j*dp)) else: ave_ener = 0.5 * (centroid.energy(traj1.state) + centroid.energy(traj2.state)) dif_ener = 0.5 * (centroid.energy(traj1.state) - centroid.energy(traj2.state)) vint = Snuc * np.dot(centroid.derivative(traj1.state,traj2.state), ave_ener * dx_2 - ave_ener * dx_1 + 1j * dif_ener * dp) return vint
def sdot_integral(traj1, traj2, centroid=None, Snuc=None, e_only=False, nuc_only=False): """Returns the matrix element <Psi_1 | d/dt | Psi_2>.""" if Snuc is None: Snuc = nuclear.overlap(traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) # overlap of electronic functions Selec = elec_overlap(traj1, traj2, centroid) # < chi | d / dx | chi'> deldx = nuclear.deldx(Snuc,traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) # < chi | d / dp | chi'> deldp = nuclear.deldp(Snuc,traj1.phase(),traj1.widths(),traj1.x(),traj1.p(), traj2.phase(),traj2.widths(),traj2.x(),traj2.p()) # the nuclear contribution to the sdot matrix sdot = ( np.dot(traj2.velocity(), deldx) + np.dot(traj2.force(), deldp) + 1j * traj2.phase_dot() * Snuc) * Selec # time-derivative of the electronic component return sdot
def v_integral(t1, t2, centroid=None, Snuc=None): """Returns potential coupling matrix element between two trajectories. If we are passed a single trajectory, this is a diagonal matrix element -- simply return potential energy of trajectory. """ if Snuc is None: Sij = nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p()) else: Sij = Snuc Sji = Sij.conjugate() if glbl.propagate['integral_order'] > 2: raise ValueError( 'Integral_order > 2 not implemented for bra_ket_averaged') if t1.state == t2.state: state = t1.state # Adiabatic energy vij = t1.energy(state) * Sij vji = t2.energy(state) * Sji if glbl.propagate['integral_order'] > 0: o1_ij = nuclear.ordr1_vec(t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) o1_ji = nuclear.ordr1_vec(t2.widths(), t2.x(), t2.p(), t1.widths(), t1.x(), t1.p()) vij += np.dot(o1_ij - t1.x() * Sij, t1.derivative(state, state)) vji += np.dot(o1_ji - t2.x() * Sji, t2.derivative(state, state)) if glbl.propagate['integral_order'] > 1: xcen = (t1.widths() * t1.x() + t2.widths() * t2.x()) / (t1.widths() + t2.widths()) o2_ij = nuclear.ordr2_vec(t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p()) o2_ji = nuclear.ordr2_vec(t2.widths(), t2.x(), t2.p(), t1.widths(), t1.x(), t1.p()) for k in range(t1.dim): vij += 0.5 * o2_ij[k] * t1.hessian(state)[k, k] vji += 0.5 * o2_ji[k] * t2.hessian(state)[k, k] for l in range(k): vij += 0.5 * ( (2. * o1_ij[k] * o1_ij[l] - xcen[k] * o1_ij[l] - xcen[l] * o1_ij[k] - o1_ij[k] * t1.x()[l] - o1_ij[l] * t1.x()[k] + (t1.x()[k] * xcen[l] + t1.x()[l] * xcen[k]) * Sij) * t1.hessian(state)[k, l]) vji += 0.5 * ( (2. * o1_ji[k] * o1_ji[l] - xcen[k] * o1_ji[l] - xcen[l] * o1_ji[k] - o1_ji[k] * t2.x()[l] - o1_ji[l] * t2.x()[k] + (t2.x()[k] * xcen[l] + t2.x()[l] * xcen[k]) * Sji) * t2.hessian(state)[k, l]) # [necessarily] off-diagonal matrix element between trajectories # on different electronic states else: # Derivative coupling fij = t1.derivative(t1.state, t2.state) vij = 2. * np.vdot( t1.derivative(t1.state, t2.state), glbl.pes.kecoeff * nuclear.deldx(Sij, t1.widths(), t1.x(), t1.p(), t2.widths(), t2.x(), t2.p())) vji = 2. * np.vdot( t2.derivative(t2.state, t1.state), glbl.pes.kecoeff * nuclear.deldx(Sji, t2.widths(), t2.x(), t2.p(), t1.widths(), t1.x(), t1.p())) return 0.5 * (vij + vji.conjugate())
def nuc_overlap(t1, t2): """ Returns < Chi | Chi' >, the nuclear overlap integral of two trajectories""" return nuclear.overlap(t1.phase(), t1.widths(), t1.x(), t1.p(), t2.phase(), t2.widths(), t2.x(), t2.p())