void Wfcgrid::update_propagator_2D(double dt,double m0){ /** \brief Update real-space propagators for 2D grid \param[in] dt Integration time \param[in] m0 Mass of the particle (effective DOF) working in atomic units: hbar = 1 */ int nst, nst1; MATRIX* diaH; diaH = new MATRIX(nstates,nstates); MATRIX* adiH; adiH = new MATRIX(nstates,nstates); MATRIX* S; S = new MATRIX(nstates, nstates); S->Init_Unit_Matrix(1.0); MATRIX* C; C = new MATRIX(nstates, nstates); *C = 0.0; MATRIX* si; si = new MATRIX(nstates, nstates); *si = 0.0; // cos(-dt*E), where E is adiabatic Ham. MATRIX* cs; cs = new MATRIX(nstates, nstates); *cs = 0.0; // sin(-dt*E), where E is adiabatic Ham. // For each 2D grid point for(int nx=0;nx<Nx;nx++){ for(int ny=0;ny<Ny;ny++){ // Get diabatic Hamiltonian (in real form) for(nst=0;nst<nstates;nst++){ for(nst1=0;nst1<nstates;nst1++){ diaH->M[nst*nstates+nst1] = H[nst][nst1].M[nx*Ny+ny].real(); } } // Transformation to adiabatic basis solve_eigen(nstates, diaH, S, adiH, C); // diaH * C = S * C * adiH // Now compute sin and cos matrixes: diagonal *cs = 0.0; *si = 0.0; for(int nst=0;nst<nstates;nst++){ cs->M[nst*nstates+nst] = std::cos(-dt*adiH->M[nst*nstates+nst]); si->M[nst*nstates+nst] = std::sin(-dt*adiH->M[nst*nstates+nst]); } // Transform cs and si according to matrix C: *cs = (*C) * (*cs) * ((*C).T()); *si = (*C) * (*si) * ((*C).T()); // Finally construct complex exp(-i*dt*H) matrix from real cs and si matrices for(nst=0;nst<nstates;nst++){ for(nst1=0;nst1<nstates;nst1++){ expH[nst][nst1].M[nx*Ny+ny] = complex<double>(cs->M[nst*nstates+nst1], si->M[nst*nstates+nst1]); // exp(-i*H*dt) } }//for nst }// for ny }// for nx delete S; delete C; delete diaH; delete adiH; delete cs; delete si; }// update_propagator_2D
void Hamiltonian_Extern::compute_adiabatic(){ /** This function "computes" adiabatic PESs (energies and derivatives) and derivative couplings Here, we have 2 options: - adiabatic Hamiltonian and its derivatives are bound - we simply use them ("adiabatic_opt==0") - diabatic Hamiltonian and its derivatives are bound (bud we use "adiabatic_opt ==1" ) - - we need to perfrom diabatic -> adiabatic transformation, like in the Hamiltonian_Model case To distinguish these two cases, we use additional parameter - "adiabatic_opt" */ if(adiabatic_opt==0){ // Everything is done already - don't do anything special, other than check the bindings if(status_adi == 0){ // only compute this is the result if not up to date // setup ham_adi, d1ham_adi, and d2ham_adi matrices, so below we will basically // check regarding the status of bindings if(bs_ham_adi == 0){ cout<<"Error in Hamiltonian_Extern::compute_adiabatic (with option adiabatic_opt == 0)\n"; cout<<"Adiabatic Hamiltonian has not been bound to the Hamiltonian_Extern object\n"; cout<<"use \"bind_ham_adi\" function\n"; exit(0); } if(bs_d1ham_adi == 0){ cout<<"Error in Hamiltonian_Extern::compute_adiabatic (with option adiabatic_opt == 0)\n"; cout<<"Derivatives of adiabatic Hamiltonian have not been bound to the Hamiltonian_Extern object\n"; cout<<"use \"bind_d1ham_dia\" function\n"; exit(0); } // Now it is ok, so far we don't care about d2ham_dia matrices!!! // Set status flag status_adi = 1; }// status_dia == 0 }// adiabatic_opt == 0 else if(adiabatic_opt==1){ compute_diabatic(); if(status_adi == 0){ MATRIX* S; S = new MATRIX(nelec, nelec); S->Init_Unit_Matrix(1.0); MATRIX* C; C = new MATRIX(nelec, nelec); *C = 0.0; // Transformation to adiabatic basis solve_eigen(nelec, ham_dia, S, ham_adi, C); // H_dia * C = S * C * H_adi // Now compute the derivative couplings (off-diagonal, multiplied by energy difference) and adiabatic gradients (diagonal) for(int n=0;n<nnucl;n++){ *d1ham_adi[n] = (*C).T() * (*d1ham_dia[n]) * (*C); }// for n delete S; delete C; // Set status flag status_adi = 1; }// status_adi == 0 }// adiabatic_opt == 1 }