@@ -862,6 +862,63 @@ void xf_destroy_AT(dyn_variables& dyn_var, double threshold){
862
862
} // traj
863
863
}
864
864
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
+
865
922
void xf_create_AT (dyn_variables& dyn_var, double threshold){
866
923
/* *
867
924
\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){
899
956
900
957
}
901
958
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
+
902
972
void shxf (dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn_control_params& prms){
903
973
/* *
904
974
\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
988
1058
if (alpha < 0.0 ){ alpha = 0.0 ;
989
1059
if (prms.project_out_aux == 1 ){
990
1060
project_out (*dyn_var.ampl_adi , traj, i);
991
- xf_init_AT (dyn_var, traj, i );
1061
+ xf_init_AT (dyn_var, traj, - 1 );
992
1062
cout << " Project out a classically forbidden state " << i << " on traj " << traj <<endl;
993
- continue ;
1063
+ break ;
994
1064
}
995
1065
}
996
1066
@@ -1042,19 +1112,6 @@ void shxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn
1042
1112
1043
1113
}
1044
1114
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
-
1058
1115
void mqcxf (dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dyn_control_params& prms){
1059
1116
/* *
1060
1117
\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
1065
1122
int nadi = dyn_var.nadi ;
1066
1123
int ndof = dyn_var.ndof ;
1067
1124
1068
- xf_destroy_AT (dyn_var, prms.coherence_threshold );
1125
+ xf_destroy_AT (dyn_var, ham, prms.coherence_threshold );
1069
1126
1070
1127
xf_create_AT (dyn_var, prms.coherence_threshold );
1071
1128
@@ -1093,7 +1150,6 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
1093
1150
} // traj
1094
1151
1095
1152
// Propagate auxiliary momenta
1096
- CMATRIX coeff_tmp = *dyn_var.ampl_adi ;
1097
1153
CMATRIX coeff (nadi, 1 );
1098
1154
1099
1155
for (int traj=0 ; traj<ntraj; traj++){
@@ -1117,7 +1173,7 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
1117
1173
}
1118
1174
1119
1175
vector<int > _id (2 , 0 ); _id[1 ] = traj;
1120
- coeff = coeff_tmp. col (traj);
1176
+ coeff = dyn_var. ampl_adi -> col (traj);
1121
1177
double Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
1122
1178
1123
1179
double alpha;
@@ -1131,18 +1187,18 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
1131
1187
else {
1132
1188
p_aux_temp = p_aux_old.row (i).T ();
1133
1189
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();
1134
1191
}
1135
1192
1136
1193
if (alpha < 0.0 ){ alpha = 0.0 ;
1137
1194
if (prms.project_out_aux == 1 ){
1138
1195
project_out (*dyn_var.ampl_adi , traj, i);
1139
- xf_init_AT (dyn_var, traj, i );
1196
+ xf_init_AT (dyn_var, traj, - 1 );
1140
1197
cout << " Project out a classically forbidden state " << i << " on traj " << traj <<endl;
1141
1198
1142
1199
// rescaling velocity
1143
1200
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);
1146
1202
Epot = ham.Ehrenfest_energy_adi (coeff, _id).real ();
1147
1203
1148
1204
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
1151
1207
dyn_var.p ->set (idof, traj, dyn_var.p ->get (idof, traj) * sqrt (alpha));
1152
1208
}
1153
1209
1154
- continue ;
1210
+ break ;
1155
1211
}
1156
1212
}
1157
1213
@@ -1165,21 +1221,31 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
1165
1221
double temp = 0.0 ;
1166
1222
for (int idof=0 ; idof<ndof; idof++){temp += p_aux_old.get (i, idof)*p_aux.get (i,idof);}
1167
1223
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];
1170
1227
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
+ }
1174
1242
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++){
1180
1244
dyn_var.p ->set (idof, traj, dyn_var.p ->get (idof, traj) * sqrt (alpha));
1181
1245
}
1182
1246
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;
1183
1249
break ;
1184
1250
}
1185
1251
}
@@ -1188,51 +1254,28 @@ void mqcxf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& ham_prev, dy
1188
1254
}// i
1189
1255
}// traj
1190
1256
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 ();
1222
1265
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
1236
1279
}
1237
1280
1238
1281
void 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
1248
1291
RHO = T * C * C.H () * T.H ();
1249
1292
1250
1293
// Compute quantum momenta
1251
- dyn_var. p_quant -> set (- 1 , traj, 0.0 ) ;
1294
+ int a = dyn_var. act_states [traj] ;
1252
1295
1296
+ dyn_var.p_quant ->set (-1 , traj, 0.0 );
1253
1297
for (int i=0 ; i<nst; i++){
1254
1298
if (is_mixed[i]==1 ){
1255
1299
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)));
1258
1303
}
1259
1304
}
1260
1305
}
@@ -1307,8 +1352,6 @@ void update_forces_xf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& h
1307
1352
MATRIX p_real (ndof, 1 );
1308
1353
p_real = dyn_var.p ->col (traj);
1309
1354
double Ekin = compute_kinetic_energy (p_real, invM);
1310
-
1311
- C = Coeff.col (traj);
1312
1355
1313
1356
// Compute F for each dof
1314
1357
for (int idof=0 ; idof<ndof; idof++){
@@ -1327,7 +1370,7 @@ void update_forces_xf(dyn_variables& dyn_var, nHamiltonian& ham, nHamiltonian& h
1327
1370
// Original form of the decoherence force
1328
1371
for (int idof=0 ; idof<ndof; idof++){
1329
1372
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);
1331
1374
dyn_var.f_xf ->add (idof, traj, -2.0 *invM.get (jdof,0 )*dyn_var.p_quant ->get (jdof, traj)*
1332
1375
(dyn_var.VP ->get (jdof, traj)*dyn_var.VP ->get (idof, traj) - temp.get (0 ,0 ).real () ) );
1333
1376
}
@@ -1380,15 +1423,16 @@ void propagate_half_xf(dyn_variables& dyn_var, nHamiltonian& Ham, dyn_control_pa
1380
1423
// ================= Basis re-expansion ===================
1381
1424
CMATRIX P (nadi, nadi);
1382
1425
CMATRIX T (*dyn_var.proj_adi [itraj]); T.load_identity ();
1383
- CMATRIX T_new (nadi, nadi);
1384
1426
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(); }
1392
1436
1393
1437
// Generate the half-time exponential operator
1394
1438
CMATRIX Hxf_old (nadi, nadi);
0 commit comments