1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
use std::sync::Arc;
use rest_tensors::{TensorOpt,RIFull, MatrixFull};
use rest_tensors::matrix_blas_lapack::{_dgemm_nn,_dgemm_tn};
use crate::molecule_io::Molecule;
use crate::scf_io::SCF;
use crate::utilities::TimeRecords;
#[derive(Clone)]
pub struct PT2 {
pub pt2_type: usize,
pub pt2_param: [f64;2],
pub pt2_energy: [f64;2]
}
impl PT2 {
pub fn new(mol: &Molecule) -> PT2 {
PT2 {
pt2_type: 0,
pt2_param:[1.0,1.0],
pt2_energy:[0.0,0.0]
}
}
}
pub fn xdh_calculations(scf_data: &mut SCF) -> anyhow::Result<f64> {
println!("=======================================");
println!("Now evaluate the PT2 correlation energy");
println!("=======================================");
let pt2_c = if scf_data.mol.spin_channel == 1 {
close_shell_pt2(&scf_data).unwrap()
} else {
open_shell_pt2(&scf_data).unwrap()
};
println!("{:?}",&pt2_c);
let x_energy = scf_data.evaluate_exact_exchange_ri_v();
let xc_energy_scf = scf_data.evaluate_xc_energy(0);
let xc_energy_xdh = scf_data.evaluate_xc_energy(1);
let hy_coeffi_scf = scf_data.mol.xc_data.dfa_hybrid_scf;
let hy_coeffi_xdh = if let Some(coeff) = scf_data.mol.xc_data.dfa_hybrid_pos {coeff} else {0.0};
let hy_coeffi_pt2 = if let Some(coeff) = &scf_data.mol.xc_data.dfa_paramr_adv {coeff.clone()} else {vec![0.0,0.0]};
let xdh_pt2_energy: f64 = pt2_c[1..3].iter().zip(hy_coeffi_pt2.iter()).map(|(e,c)| e*c).sum();
println!("Fifth-rung correlation energy : {:?} Ha", xdh_pt2_energy);
let total_energy = scf_data.scf_energy +
x_energy * (hy_coeffi_xdh-hy_coeffi_scf) +
xc_energy_xdh-xc_energy_scf +
xdh_pt2_energy;
println!("E[{:?}]=: {:?} Ha, Ex[HF]: {:?} Ha, Ec[PT2]: {:?} Ha", scf_data.mol.ctrl.xc, total_energy, x_energy, pt2_c[0]);
Ok(total_energy)
}
fn close_shell_pt2(scf_data: &SCF) -> anyhow::Result<[f64;3]> {
if let Some(riao)=&scf_data.ri3fn {
let mut e_mp2_ss = 0.0_f64;
let mut e_mp2_os = 0.0_f64;
let eigenvector = scf_data.eigenvectors.get(0).unwrap();
let eigenvalues = scf_data.eigenvalues.get(0).unwrap();
let homo = scf_data.homo.get(0).unwrap().clone();
let lumo = scf_data.lumo.get(0).unwrap().clone();
let num_basis = eigenvector.size.get(0).unwrap().clone();
let num_state = eigenvector.size.get(1).unwrap().clone();
let start_mo: usize = scf_data.mol.start_mo;
let num_occu = homo + 1;
let mut tmp_record = TimeRecords::new();
tmp_record.new_item("rimo", "the generation of three-center RI tensor for MO");
tmp_record.count_start("rimo");
let mut rimo = riao.ao2mo(eigenvector).unwrap();
tmp_record.count("rimo");
tmp_record.new_item("dgemm", "prepare four-center integrals from RI-MO");
tmp_record.new_item("get2d", "get the ERI values");
for i_state in start_mo..num_occu {
let i_state_eigen = eigenvalues.get(i_state).unwrap();
for j_state in i_state..num_occu {
let mut e_mp2_term_ss = 0.0_f64;
let mut e_mp2_term_os = 0.0_f64;
let j_state_eigen = eigenvalues.get(j_state).unwrap();
let ij_state_eigen = i_state_eigen + j_state_eigen;
tmp_record.count_start("dgemm");
let ri_i = rimo.get_reducing_matrix(i_state).unwrap();
let ri_j = rimo.get_reducing_matrix(j_state).unwrap();
let eri_virt = _dgemm_tn(&ri_i,&ri_j);
tmp_record.count("dgemm");
for i_virt in lumo..num_state {
let i_virt_eigen = eigenvalues.get(i_virt).unwrap();
for j_virt in lumo..num_state {
let j_virt_eigen = eigenvalues.get(j_virt).unwrap();
let ij_virt_eigen = i_virt_eigen + j_virt_eigen;
let mut double_gap = ij_virt_eigen - ij_state_eigen;
if double_gap.abs()<=10E-6 {
println!("Warning: too close to degeneracy")
};
tmp_record.count_start("get2d");
let e_mp2_a = eri_virt.get2d([i_virt,j_virt]).unwrap();
let e_mp2_b = eri_virt.get2d([j_virt,i_virt]).unwrap();
tmp_record.count("get2d");
e_mp2_term_ss += (e_mp2_a - e_mp2_b) * e_mp2_a / double_gap;
e_mp2_term_os += e_mp2_a * e_mp2_a / double_gap;
}
}
if i_state != j_state {
e_mp2_term_ss *= 2.0;
e_mp2_term_os *= 2.0;
}
e_mp2_ss -= e_mp2_term_ss;
e_mp2_os -= e_mp2_term_os;
}
}
tmp_record.report_all();
return(Ok([e_mp2_ss+e_mp2_os,e_mp2_os,e_mp2_ss]));
} else {
panic!("ri3fn should be initialized for RI-PT2 calculations")
};
}
fn open_shell_pt2(scf_data: &SCF) -> anyhow::Result<[f64;3]> {
if let Some(riao)=&scf_data.ri3fn {
let start_mo: usize = scf_data.mol.start_mo;
let mut e_mp2_ss = 0.0_f64;
let mut e_mp2_os = 0.0_f64;
let num_basis = scf_data.mol.num_basis;
let num_state = scf_data.mol.num_state;
let spin_channel = scf_data.mol.spin_channel;
let i_spin_pair: [(usize,usize);3] = [(0,0),(0,1),(1,1)];
for (i_spin_1,i_spin_2) in i_spin_pair {
if i_spin_1 == i_spin_2 {
let i_spin = i_spin_1;
let eigenvector = scf_data.eigenvectors.get(i_spin).unwrap();
let eigenvalues = scf_data.eigenvalues.get(i_spin).unwrap();
let homo = scf_data.homo.get(i_spin).unwrap().clone();
let lumo = scf_data.lumo.get(i_spin).unwrap().clone();
let num_occu = homo + 1;
let mut rimo = riao.ao2mo(eigenvector).unwrap();
for i_state in start_mo..num_occu {
let i_state_eigen = eigenvalues.get(i_state).unwrap();
for j_state in i_state+1..num_occu {
let mut e_mp2_term_ss = 0.0_f64;
let j_state_eigen = eigenvalues.get(j_state).unwrap();
let ij_state_eigen = i_state_eigen + j_state_eigen;
let ri_i = rimo.get_reducing_matrix(i_state).unwrap();
let ri_j = rimo.get_reducing_matrix(j_state).unwrap();
let eri_virt = _dgemm_tn(&ri_i,&ri_j);
for i_virt in lumo..num_state {
let i_virt_eigen = eigenvalues.get(i_virt).unwrap();
for j_virt in i_virt+1..num_state {
let j_virt_eigen = eigenvalues.get(j_virt).unwrap();
let ij_virt_eigen = i_virt_eigen + j_virt_eigen;
let mut double_gap = ij_virt_eigen - ij_state_eigen;
if double_gap.abs()<=10E-6 {
println!("Warning: too close to degeneracy")
};
let e_mp2_a = eri_virt.get2d([i_virt,j_virt]).unwrap();
let e_mp2_b = eri_virt.get2d([j_virt,i_virt]).unwrap();
e_mp2_term_ss += (e_mp2_a - e_mp2_b).powf(2.0) / double_gap;
}
}
e_mp2_ss -= e_mp2_term_ss;
}
}
} else {
let eigenvector_1 = scf_data.eigenvectors.get(i_spin_1).unwrap();
let eigenvalues_1 = scf_data.eigenvalues.get(i_spin_1).unwrap();
let homo_1 = scf_data.homo.get(i_spin_1).unwrap().clone();
let lumo_1 = scf_data.lumo.get(i_spin_1).unwrap().clone();
let num_occu_1 = homo_1 + 1;
let mut rimo_1 = riao.ao2mo_v01(eigenvector_1).unwrap();
let eigenvector_2 = scf_data.eigenvectors.get(i_spin_2).unwrap();
let eigenvalues_2 = scf_data.eigenvalues.get(i_spin_2).unwrap();
let homo_2 = scf_data.homo.get(i_spin_2).unwrap().clone();
let lumo_2 = scf_data.lumo.get(i_spin_2).unwrap().clone();
let num_occu_2 = homo_2 + 1;
let mut rimo_2 = riao.ao2mo_v01(eigenvector_2).unwrap();
for i_state in start_mo..num_occu_1 {
let i_state_eigen = eigenvalues_1.get(i_state).unwrap();
let ri_i = rimo_1.get_reducing_matrix(i_state).unwrap();
for j_state in start_mo..num_occu_2 {
let mut e_mp2_term_os = 0.0_f64;
let j_state_eigen = eigenvalues_2.get(j_state).unwrap();
let ri_j = rimo_2.get_reducing_matrix(j_state).unwrap();
let ij_state_eigen = i_state_eigen + j_state_eigen;
let eri_virt = _dgemm_tn(&ri_i,&ri_j);
for i_virt in lumo_1..num_state {
let i_virt_eigen = eigenvalues_1.get(i_virt).unwrap();
for j_virt in lumo_2..num_state {
let j_virt_eigen = eigenvalues_2.get(j_virt).unwrap();
let ij_virt_eigen = i_virt_eigen + j_virt_eigen;
let mut double_gap = ij_virt_eigen - ij_state_eigen;
if double_gap.abs()<=10E-6 {
println!("Warning: too close to degeneracy")
};
let e_mp2_a = eri_virt.get2d([i_virt,j_virt]).unwrap();
e_mp2_term_os += e_mp2_a * e_mp2_a / double_gap;
}
}
e_mp2_os -= e_mp2_term_os;
}
}
}
}
return(Ok([e_mp2_ss+e_mp2_os,e_mp2_os,e_mp2_ss]));
} else {
panic!("ri3fn should be initialized for RI-PT2 calculations")
};
}