@@ -862,6 +862,63 @@ void xf_destroy_AT(dyn_variables& dyn_var, double threshold){
862862 } // traj
863863}
864864
865+ void xf_destroy_AT (dyn_variables& dyn_var, nHamiltonian& ham, double threshold){
866+ /* *
867+ \brief When the electronic state recovers to an adiabatic state, destroy auxiliary trajectories
868+ Here, momentum rescaling is also performed.
869+ */
870+ int traj;
871+ int ntraj = dyn_var.ntraj ;
872+ int nadi = dyn_var.nadi ;
873+
874+ double upper_lim = 1.0 - threshold;
875+ double lower_lim = threshold;
876+
877+ for (int traj=0 ; traj<ntraj; traj++){
878+ vector<int >& is_mixed = dyn_var.is_mixed [traj];
879+ vector<int >& is_first = dyn_var.is_first [traj];
880+ CMATRIX& dm = *dyn_var.dm_adi [traj];
881+
882+ int is_recovered = 0 ;
883+
884+ for (int i=0 ; i<nadi; i++){
885+ double a_ii = dm.get (i,i).real ();
886+ if (is_mixed[i]==1 ){
887+ if (a_ii>upper_lim){
888+ is_recovered = 1 ;
889+
890+ // Before the collapse
891+ vector<int > _id (2 , 0 ); _id[1 ] = traj;
892+ CMATRIX coeff (nadi, 1 );
893+ coeff = dyn_var.ampl_adi ->col (traj);
894+ double Epot_old = ham.Ehrenfest_energy_adi (coeff, _id).real ();
895+
896+ collapse (*dyn_var.ampl_adi , traj, i, 0 );
897+
898+ // After the collapse
899+ coeff = dyn_var.ampl_adi ->col (traj);
900+ double Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
901+
902+ // Rescaling momenta for the energy conservation
903+ MATRIX p_real (dyn_var.ndof , 1 ); p_real = dyn_var.p ->col (traj);
904+ double alpha = compute_kinetic_energy (p_real, *dyn_var.iM ) + Epot_old - Epot;
905+
906+ if (alpha > 0.0 ){alpha /= compute_kinetic_energy (p_real, *dyn_var.iM );}
907+ else {alpha = 0.0 ;}
908+
909+ for (int idof=0 ; idof<dyn_var.ndof ; idof++){
910+ dyn_var.p ->set (idof, traj, dyn_var.p ->get (idof, traj) * sqrt (alpha));
911+ }
912+
913+ break ;
914+ }
915+ }
916+ } // i
917+
918+ if (is_recovered==1 ){xf_init_AT (dyn_var, traj, -1 );}
919+ } // traj
920+ }
921+
865922void xf_create_AT (dyn_variables& dyn_var, double threshold){
866923 /* *
867924 \brief When the electronic state is in a superposition between adiabatic states, create auxiliary trajectories
@@ -899,6 +956,19 @@ void xf_create_AT(dyn_variables& dyn_var, double threshold){
899956
900957}
901958
959+ void xf_hop_reset (dyn_variables& dyn_var, vector<int >& accepted_states, vector<int >& initial_states){
960+ int traj;
961+ int ntraj = dyn_var.ntraj ;
962+
963+ for (traj = 0 ; traj < ntraj; traj++){
964+ // When a hop occurs, destroy auxiliary trajectories
965+ if (accepted_states[traj] != initial_states[traj]){
966+ xf_init_AT (dyn_var, traj, -1 );
967+ cout << " destroy auxiliary trajectories of traj " << traj << " due to a hop" << endl;
968+ }
969+ }// traj
970+ }
971+
902972void shxf (dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn_control_params& prms){
903973 /* *
904974 \brief The generic framework of the SHXF (Surface Hopping based on eXact Factorization) method of
@@ -988,9 +1058,9 @@ void shxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn
9881058 if (alpha < 0.0 ){ alpha = 0.0 ;
9891059 if (prms.project_out_aux == 1 ){
9901060 project_out (*dyn_var.ampl_adi , traj, i);
991- xf_init_AT (dyn_var, traj, i );
1061+ xf_init_AT (dyn_var, traj, - 1 );
9921062 cout << " Project out a classically forbidden state " << i << " on traj " << traj <<endl;
993- continue ;
1063+ break ;
9941064 }
9951065 }
9961066
@@ -1042,19 +1112,6 @@ void shxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn
10421112
10431113}
10441114
1045- void shxf (dyn_variables& dyn_var, vector<int >& accepted_states, vector<int >& initial_states){
1046- int traj;
1047- int ntraj = dyn_var.ntraj ;
1048-
1049- for (traj = 0 ; traj < ntraj; traj++){
1050- // When a hop occurs, destroy auxiliary trajectories
1051- if (accepted_states[traj] != initial_states[traj]){
1052- xf_init_AT (dyn_var, traj, -1 );
1053- cout << " destroy auxiliary trajectories of traj " << traj << " due to a hop" << endl;
1054- }
1055- }// traj
1056- }
1057-
10581115void mqcxf (dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn_control_params& prms){
10591116 /* *
10601117 \brief The generic framework of the MQCXF (Mixed Quantum-Classical based on eXact Factorization) method of
@@ -1065,7 +1122,7 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
10651122 int nadi = dyn_var.nadi ;
10661123 int ndof = dyn_var.ndof ;
10671124
1068- xf_destroy_AT (dyn_var, prms.coherence_threshold );
1125+ xf_destroy_AT (dyn_var, ham, prms.coherence_threshold );
10691126
10701127 xf_create_AT (dyn_var, prms.coherence_threshold );
10711128
@@ -1093,7 +1150,6 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
10931150 } // traj
10941151
10951152 // Propagate auxiliary momenta
1096- CMATRIX coeff_tmp = *dyn_var.ampl_adi ;
10971153 CMATRIX coeff (nadi, 1 );
10981154
10991155 for (int traj=0 ; traj<ntraj; traj++){
@@ -1117,7 +1173,7 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
11171173 }
11181174
11191175 vector<int > _id (2 , 0 ); _id[1 ] = traj;
1120- coeff = coeff_tmp. col (traj);
1176+ coeff = dyn_var. ampl_adi -> col (traj);
11211177 double Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
11221178
11231179 double alpha;
@@ -1131,18 +1187,18 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
11311187 else {
11321188 p_aux_temp = p_aux_old.row (i).T ();
11331189 alpha = compute_kinetic_energy (p_aux_temp, invM) + ham_adi_prev.get (i,i).real () - ham_adi.get (i,i).real ();
1190+ // alpha = compute_kinetic_energy(p_real, invM) + Epot - ham_adi.get(i,i).real();
11341191 }
11351192
11361193 if (alpha < 0.0 ){ alpha = 0.0 ;
11371194 if (prms.project_out_aux == 1 ){
11381195 project_out (*dyn_var.ampl_adi , traj, i);
1139- xf_init_AT (dyn_var, traj, i );
1196+ xf_init_AT (dyn_var, traj, - 1 );
11401197 cout << " Project out a classically forbidden state " << i << " on traj " << traj <<endl;
11411198
11421199 // rescaling velocity
11431200 double Epot_old = Epot;
1144- coeff_tmp = *dyn_var.ampl_adi ;
1145- coeff = coeff_tmp.col (traj);
1201+ coeff = dyn_var.ampl_adi ->col (traj);
11461202 Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
11471203
11481204 alpha = compute_kinetic_energy (p_real, invM) + Epot_old - Epot;
@@ -1151,7 +1207,7 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
11511207 dyn_var.p ->set (idof, traj, dyn_var.p ->get (idof, traj) * sqrt (alpha));
11521208 }
11531209
1154- continue ;
1210+ break ;
11551211 }
11561212 }
11571213
@@ -1165,21 +1221,31 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
11651221 double temp = 0.0 ;
11661222 for (int idof=0 ; idof<ndof; idof++){temp += p_aux_old.get (i, idof)*p_aux.get (i,idof);}
11671223 if (temp<0.0 ){
1168- int a; complex <double > max_val;
1169- coeff.max_col_elt (0 , max_val, a);
1224+ double Epot_old = Epot;
1225+
1226+ int a = dyn_var.act_states [traj];
11701227 collapse (*dyn_var.ampl_adi , traj, a, 0 );
1171- xf_init_AT (dyn_var, traj, -1 );
1172- cout << " Collapse to the most probable state " << a << " with " << pow (fabs (max_val), 2 ) <<
1173- " at a classical turning point on traj " << traj <<endl;
1228+
1229+ // After the collapse
1230+ coeff = dyn_var.ampl_adi ->col (traj);
1231+ double Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
1232+
1233+ // Rescaling momenta for the energy conservation
1234+ p_real = dyn_var.p ->col (traj);
1235+ double alpha = compute_kinetic_energy (p_real, invM) + Epot_old - Epot;
1236+
1237+ if (alpha > 0.0 ){alpha /= compute_kinetic_energy (p_real, invM);}
1238+ else {
1239+ alpha = 0.0 ;
1240+ cout << " Energy is drifted due to a classically forbidden hop" << endl;
1241+ }
11741242
1175- // rescaling velocity
1176- alpha = compute_kinetic_energy (p_real, invM) + Epot - ham_adi.get (a,a).real ();
1177- if (alpha < 0.0 ){alpha = 0.0 ;}
1178- alpha /= compute_kinetic_energy (p_real, invM);
1179- for (int idof=0 ; idof<ndof; idof++){
1243+ for (int idof=0 ; idof<dyn_var.ndof ; idof++){
11801244 dyn_var.p ->set (idof, traj, dyn_var.p ->get (idof, traj) * sqrt (alpha));
11811245 }
11821246
1247+ xf_init_AT (dyn_var, traj, -1 );
1248+ cout << " Collapse to the active state " << a << " at a classical turning point on traj " << traj <<endl;
11831249 break ;
11841250 }
11851251 }
@@ -1188,51 +1254,28 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
11881254 }// i
11891255 }// traj
11901256
1191- // Propagate the spatial derivative of phases
1192- if (prms.use_xf_force ==0 ){
1193- for (int traj=0 ; traj<ntraj; traj++){
1194- vector<int >& is_mixed = dyn_var.is_mixed [traj];
1195- vector<int >& is_first = dyn_var.is_first [traj];
1196- MATRIX& p_aux = *dyn_var.p_aux [traj];
1197- MATRIX& p_aux_old = *dyn_var.p_aux_old [traj];
1198- MATRIX& nab_phase = *dyn_var.nab_phase [traj];
1199-
1200- for (int i=0 ; i<nadi; i++){
1201- if (is_mixed[i]==1 ){
1202- if (is_first[i]==1 ){
1203- nab_phase.set (i, -1 , 0.0 );
1204- }
1205- else {
1206- for (int idof=0 ; idof<ndof; idof++){
1207- nab_phase.add (i, idof, p_aux.get (i, idof) - p_aux_old.get (i, idof));
1208- }// idof
1209- }
1210- }
1211- }// i
1212- } // traj
1213- }
1214- else {
1215- for (int traj=0 ; traj<ntraj; traj++){
1216- vector<int >& is_mixed = dyn_var.is_mixed [traj];
1217- vector<int >& is_first = dyn_var.is_first [traj];
1218- MATRIX& nab_phase = *dyn_var.nab_phase [traj];
1219-
1220- CMATRIX E (nadi, nadi);
1221- E = ham.children [traj]->get_ham_adi ();
1257+ // Propagate the spatial derivative of phases; the E-based approximation is used
1258+ for (int traj=0 ; traj<ntraj; traj++){
1259+ vector<int >& is_mixed = dyn_var.is_mixed [traj];
1260+ vector<int >& is_first = dyn_var.is_first [traj];
1261+ MATRIX& nab_phase = *dyn_var.nab_phase [traj];
1262+
1263+ CMATRIX E (nadi, nadi);
1264+ E = ham.children [traj]->get_ham_adi ();
12221265
1223- MATRIX p_real (ndof, 1 );
1224- p_real = dyn_var.p ->col (traj);
1225- double Ekin = compute_kinetic_energy (p_real, invM);
1226-
1227- for ( int i= 0 ; i<nadi; i++){
1228- if (is_mixed[i]== 1 ){
1229- for ( int idof= 0 ; idof<ndof; idof++ ){
1230- nab_phase. set (i, idof, - 0.5 *E. get (i,i). real ()*dyn_var. p -> get ( idof,traj)/Ekin);
1231- } // idof
1232- }
1233- }// i
1234- } // traj
1235- }
1266+ MATRIX p_real (ndof, 1 );
1267+ p_real = dyn_var.p ->col (traj);
1268+ double Ekin = compute_kinetic_energy (p_real, invM);
1269+
1270+ double e = 1.0e-6 ; // masking for classical turning points
1271+ for ( int i= 0 ; i<nadi; i++ ){
1272+ if (is_mixed[i]== 1 ){
1273+ for ( int idof= 0 ; idof<ndof; idof++){
1274+ nab_phase. set (i, idof, - 0.5 *E. get (i,i). real ()*dyn_var. p -> get (idof,traj)/(Ekin + e));
1275+ }// idof
1276+ }
1277+ }// i
1278+ } // traj
12361279}
12371280
12381281void XF_correction (CMATRIX& Ham, dyn_variables& dyn_var, CMATRIX& C, double wp_width, CMATRIX& T, int traj){
@@ -1248,13 +1291,15 @@ void XF_correction(CMATRIX& Ham, dyn_variables& dyn_var, CMATRIX& C, double wp_w
12481291 RHO = T * C * C.H () * T.H ();
12491292
12501293 // Compute quantum momenta
1251- dyn_var. p_quant -> set (- 1 , traj, 0.0 ) ;
1294+ int a = dyn_var. act_states [traj] ;
12521295
1296+ dyn_var.p_quant ->set (-1 , traj, 0.0 );
12531297 for (int i=0 ; i<nst; i++){
12541298 if (is_mixed[i]==1 ){
12551299 for (int idof=0 ; idof<ndof; idof++){
1256- dyn_var.p_quant ->add (idof, traj, 0.5 / pow (wp_width, 2 ) * RHO.get (i,i).real ()
1257- *(dyn_var.q ->get (idof, traj) - dyn_var.q_aux [traj]->get (i, idof)));
1300+ dyn_var.p_quant ->add (idof, traj, 0.5 / pow (wp_width, 2.0 ) * RHO.get (i,i).real ()
1301+ *(dyn_var.q_aux [traj]->get (a, idof) - dyn_var.q_aux [traj]->get (i, idof)));
1302+ // *(dyn_var.q->get(idof, traj) - dyn_var.q_aux[traj]->get(i, idof)));
12581303 }
12591304 }
12601305 }
@@ -1307,8 +1352,6 @@ void update_forces_xf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& h
13071352 MATRIX p_real (ndof, 1 );
13081353 p_real = dyn_var.p ->col (traj);
13091354 double Ekin = compute_kinetic_energy (p_real, invM);
1310-
1311- C = Coeff.col (traj);
13121355
13131356 // Compute F for each dof
13141357 for (int idof=0 ; idof<ndof; idof++){
@@ -1327,7 +1370,7 @@ void update_forces_xf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& h
13271370 // Original form of the decoherence force
13281371 for (int idof=0 ; idof<ndof; idof++){
13291372 for (int jdof=0 ; jdof<ndof; jdof++){
1330- CMATRIX temp = (F[jdof]*C).H () * (F[idof]*C);
1373+ CMATRIX temp = (F[jdof]*C).H () * (F[idof]*C);
13311374 dyn_var.f_xf ->add (idof, traj, -2.0 *invM.get (jdof,0 )*dyn_var.p_quant ->get (jdof, traj)*
13321375 (dyn_var.VP ->get (jdof, traj)*dyn_var.VP ->get (idof, traj) - temp.get (0 ,0 ).real () ) );
13331376 }
@@ -1380,15 +1423,16 @@ void propagate_half_xf(dyn_variables& dyn_var, nHamiltonian& Ham, dyn_control_pa
13801423 // ================= Basis re-expansion ===================
13811424 CMATRIX P (nadi, nadi);
13821425 CMATRIX T (*dyn_var.proj_adi [itraj]); T.load_identity ();
1383- CMATRIX T_new (nadi, nadi);
13841426
1385- P = ham->get_time_overlap_adi (); // U_old.H() * U;
1386-
1387- // More consistent with the new derivations:
1388- libmeigen::FullPivLU_inverse (P, T_new);
1389- T_new = orthogonalized_T ( T_new );
1390-
1391- if (prms.assume_always_consistent ){ T_new.identity (); }
1427+ // Don't apply T, since hamiltonian elements were already transformed through the transform_all method
1428+ CMATRIX T_new (nadi, nadi); T_new.load_identity ();
1429+ // P = ham->get_time_overlap_adi(); // U_old.H() * U;
1430+ //
1431+ // // More consistent with the new derivations:
1432+ // libmeigen::FullPivLU_inverse(P, T_new);
1433+ // T_new = orthogonalized_T( T_new );
1434+ //
1435+ // if(prms.assume_always_consistent){ T_new.identity(); }
13921436
13931437 // Generate the half-time exponential operator
13941438 CMATRIX Hxf_old (nadi, nadi);
0 commit comments