11#include " parabolic_correction.h"
2- #include " source_base/constants.h" // ModuleBase::e2, PI, FOUR_PI
3- #include " source_base/parallel_reduce.h" // Parallel_Reduce
2+ #include " source_base/constants.h"
3+ #include " source_base/parallel_reduce.h"
44#include " source_basis/module_pw/pw_basis.h"
55#include " source_cell/unitcell.h"
66
77#include < cmath>
88#include < iostream>
9- #include < algorithm> // for std::sort
9+ #include < algorithm>
10+
11+ ParabolicCorrection::ParabolicCorrection () {}
12+ ParabolicCorrection::~ParabolicCorrection () {}
1013
1114// ---------------------------------------------------------
12- // 1. 自动寻找真空层中心 (逻辑完全借鉴 Efield::autoset)
15+ // 1. 自动寻找真空层中心
1316// ---------------------------------------------------------
1417double ParabolicCorrection::find_vacuum_center (const UnitCell& cell, int dir)
1518{
@@ -19,17 +22,15 @@ double ParabolicCorrection::find_vacuum_center(const UnitCell& cell, int dir)
1922 for (int ia = 0 ; ia < cell.atoms [it].na ; ++ia)
2023 {
2124 double p = cell.atoms [it].taud [ia][dir];
22- p -= std::floor (p); // 归一化到 [0, 1)
25+ p -= std::floor (p);
2326 pos.push_back (p);
2427 }
2528 }
26-
2729 std::sort (pos.begin (), pos.end ());
2830
2931 double max_gap = 0.0 ;
3032 double center = 0.5 ;
3133
32- // 内部间隙
3334 for (size_t i = 1 ; i < pos.size (); i++)
3435 {
3536 double gap = pos[i] - pos[i - 1 ];
@@ -40,7 +41,6 @@ double ParabolicCorrection::find_vacuum_center(const UnitCell& cell, int dir)
4041 }
4142 }
4243
43- // 跨边界间隙
4444 if (!pos.empty ()) {
4545 double tail_gap = pos[0 ] + 1.0 - pos.back ();
4646 if (tail_gap > max_gap)
@@ -50,57 +50,53 @@ double ParabolicCorrection::find_vacuum_center(const UnitCell& cell, int dir)
5050 if (center >= 1.0 ) center -= 1.0 ;
5151 }
5252 }
53-
5453 return center;
5554}
5655
57- ParabolicCorrection::ParabolicCorrection () {}
58- ParabolicCorrection::~ParabolicCorrection () {}
59-
6056// ---------------------------------------------------------
61- // 2. 应用校正的主函数
57+ // 2. 应用校正的主函数 (集成离子能量计算)
6258// ---------------------------------------------------------
63- void ParabolicCorrection::apply_correction (const UnitCell& cell,
64- const ModulePW::PW_Basis* rho_basis,
65- double * v_hartree,
66- const double * const * rho_elec, // 【修正1】指针的指针
67- int nspin, // 【修正2】添加 nspin 参数
68- double nelec,
69- int dir)
59+ double ParabolicCorrection::apply_correction (const UnitCell& cell,
60+ const ModulePW::PW_Basis* rho_basis,
61+ double * v_hartree,
62+ const double * const * rho_elec,
63+ int nspin,
64+ double nelec,
65+ int dir)
7066{
7167 // 基础几何参数
7268 double omega = cell.omega ;
7369 double lat_vec = 0.0 ;
7470 double area = 0.0 ;
7571
76- if (dir == 0 ) {
77- lat_vec = cell.a1 .norm () * cell.lat0 ;
78- } else if (dir == 1 ) {
79- lat_vec = cell.a2 .norm () * cell.lat0 ;
80- } else { // dir == 2
81- lat_vec = cell.a3 .norm () * cell.lat0 ;
82- }
72+ if (dir == 0 ) lat_vec = cell.a1 .norm () * cell.lat0 ;
73+ else if (dir == 1 ) lat_vec = cell.a2 .norm () * cell.lat0 ;
74+ else lat_vec = cell.a3 .norm () * cell.lat0 ;
75+
8376 area = omega / lat_vec;
8477
85- // 1. 自动寻找真空层中心
78+ // 1. 寻找中心
8679 double vacuum_center = find_vacuum_center (cell, dir);
87-
88- // 2. 定义 Slab 的几何中心 (真空中心的对面)
8980 double slab_center = vacuum_center + 0.5 ;
9081 if (slab_center >= 1.0 ) slab_center -= 1.0 ;
9182
92- // 3. 计算净电荷 (Q_ion - Q_elec)
83+ // 2. 计算电荷与偶极
9384 double net_charge = calc_net_charge (cell, nelec);
94-
95- // 4. 计算总偶极矩 (传递 slab_center 作为参考原点)
9685 double total_dipole = calc_total_dipole (cell, rho_basis, rho_elec, nspin, dir, slab_center);
86+
87+ // 缓存偶极矩供后续力修正使用
88+ this ->last_total_dipole_ = total_dipole;
9789
98- // 5. 构造 1D 修正势
99- // 系数 factor = 4pi / Area * e^2
100- double factor = (ModuleBase::FOUR_PI / area) * ModuleBase::e2 ;
90+ // 3. 计算离子修正能 (这是你想要加入的!)
91+ double e_ion_corr = calc_energy_correction (cell, dir, net_charge, total_dipole, vacuum_center);
10192
93+ // 4. 构造 1D 修正势并叠加到 v_hartree
94+ double factor = (ModuleBase::FOUR_PI / area) * ModuleBase::e2 ;
10295 int nrxx = rho_basis->nrxx ;
10396
97+ #ifdef _OPENMP
98+ #pragma omp parallel for
99+ #endif
104100 for (int ir = 0 ; ir < nrxx; ++ir)
105101 {
106102 int i = ir / (rho_basis->ny * rho_basis->nplane );
@@ -125,8 +121,14 @@ void ParabolicCorrection::apply_correction(const UnitCell& cell,
125121
126122 v_hartree[ir] += v_corr;
127123 }
124+
125+ // 返回离子修正能,方便外部加到 Total Energy
126+ return e_ion_corr;
128127}
129128
129+ // ---------------------------------------------------------
130+ // 辅助计算函数
131+ // ---------------------------------------------------------
130132double ParabolicCorrection::calc_net_charge (const UnitCell& cell, double nelec)
131133{
132134 double ion_charge = 0.0 ;
@@ -138,8 +140,8 @@ double ParabolicCorrection::calc_net_charge(const UnitCell& cell, double nelec)
138140
139141double ParabolicCorrection::calc_total_dipole (const UnitCell& cell,
140142 const ModulePW::PW_Basis* rho_basis,
141- const double * const * rho_elec, // 【修正】类型匹配
142- int nspin, // 【修正】传递 nspin
143+ const double * const * rho_elec,
144+ int nspin,
143145 int dir,
144146 double center)
145147{
@@ -170,20 +172,15 @@ double ParabolicCorrection::calc_ion_dipole(const UnitCell& cell, int dir, doubl
170172 return d;
171173}
172174
173- // ---------------------------------------------------------
174- // 3. 计算电子偶极矩 (包含多自旋求和)
175- // ---------------------------------------------------------
176175double ParabolicCorrection::calc_elec_dipole (const ModulePW::PW_Basis* rho_basis,
177- const double * const * rho_elec, // 【修正】指针的指针
178- int nspin, // 【修正】接收 nspin
176+ const double * const * rho_elec,
177+ int nspin,
179178 int dir,
180179 double center,
181180 double omega)
182181{
183182 double d = 0.0 ;
184183 int nrxx = rho_basis->nrxx ;
185-
186- // 【修正】Runtime 下,rho[0]=Up, rho[1]=Down,需要求和
187184 int n_components = (nspin == 2 ) ? 2 : 1 ;
188185
189186 for (int ir = 0 ; ir < nrxx; ++ir)
@@ -203,15 +200,102 @@ double ParabolicCorrection::calc_elec_dipole(const ModulePW::PW_Basis* rho_basis
203200
204201 double rho_val = 0.0 ;
205202 for (int is=0 ; is<n_components; ++is) {
206- rho_val += rho_elec[is][ir]; // 【修正】正确访问二维数组
203+ rho_val += rho_elec[is][ir];
207204 }
208205
209206 d += rho_val * dist;
210- } // 【修正】补回了丢失的括号
207+ } // 【修复了这里丢失的括号】
211208
212209 Parallel_Reduce::reduce_pool (d);
213-
214210 d *= (omega / rho_basis->nxyz );
215-
216211 return d;
212+ }
213+
214+ // ---------------------------------------------------------
215+ // 离子能量校正实现
216+ // ---------------------------------------------------------
217+ double ParabolicCorrection::calc_energy_correction (const UnitCell& cell,
218+ int dir,
219+ double net_charge,
220+ double total_dipole,
221+ double vacuum_center)
222+ {
223+ double lat_vec = 0.0 ;
224+ if (dir == 0 ) lat_vec = cell.a1 .norm () * cell.lat0 ;
225+ else if (dir == 1 ) lat_vec = cell.a2 .norm () * cell.lat0 ;
226+ else lat_vec = cell.a3 .norm () * cell.lat0 ;
227+
228+ double area = cell.omega / lat_vec;
229+ double factor = (ModuleBase::FOUR_PI / area) * ModuleBase::e2 ;
230+
231+ double slab_center = vacuum_center + 0.5 ;
232+ if (slab_center >= 1.0 ) slab_center -= 1.0 ;
233+
234+ double e_corr = 0.0 ;
235+
236+ for (int it=0 ; it<cell.ntype ; ++it) {
237+ double Z = cell.atoms [it].ncpp .zv ;
238+ for (int ia=0 ; ia<cell.atoms [it].na ; ++ia) {
239+ double pos = cell.atoms [it].taud [ia][dir];
240+
241+ double dist_frac = pos - slab_center;
242+ if (dist_frac > 0.5 ) dist_frac -= 1.0 ;
243+ if (dist_frac < -0.5 ) dist_frac += 1.0 ;
244+ double dist_bohr = dist_frac * lat_vec;
245+
246+ // V_corr at atom position
247+ double v_at_atom = factor * ( -0.5 * net_charge * dist_bohr * dist_bohr
248+ + total_dipole * dist_bohr );
249+
250+ e_corr += Z * v_at_atom;
251+ }
252+ }
253+ return e_corr;
254+ }
255+
256+ // ---------------------------------------------------------
257+ // 力校正实现 (保持独立,供 force 模块调用)
258+ // ---------------------------------------------------------
259+ void ParabolicCorrection::calc_force_correction (const UnitCell& cell,
260+ ModuleBase::matrix& force,
261+ int dir,
262+ double net_charge,
263+ double total_dipole,
264+ double vacuum_center,
265+ double area)
266+ {
267+ double factor = (ModuleBase::FOUR_PI / area) * ModuleBase::e2 ;
268+ double slab_center = vacuum_center + 0.5 ;
269+ if (slab_center >= 1.0 ) slab_center -= 1.0 ;
270+
271+ double lat_vec = cell.omega / area; // 反推 L
272+
273+ int iat = 0 ;
274+ for (int it=0 ; it<cell.ntype ; ++it) {
275+ double Z = cell.atoms [it].ncpp .zv ;
276+ for (int ia=0 ; ia<cell.atoms [it].na ; ++ia) {
277+
278+ double pos = cell.atoms [it].taud [ia][dir];
279+ double dist_frac = pos - slab_center;
280+ if (dist_frac > 0.5 ) dist_frac -= 1.0 ;
281+ if (dist_frac < -0.5 ) dist_frac += 1.0 ;
282+ double dist = dist_frac * lat_vec;
283+
284+ // 1. Electric Field Force: -Z * dV/dz
285+ double f_field = -Z * factor * (-net_charge * dist + total_dipole);
286+
287+ // 2. Dipole Response Force: Z * d(Total_Dipole)/dz * dE/dD
288+ double f_dipole = factor * Z * (net_charge * dist - total_dipole);
289+
290+ // 总修正力
291+ double f_corr = f_field + f_dipole;
292+ // 注意:上面的推导中两项可能会相互抵消或合并,具体依赖于公式的变分导数
293+ // 简单验证:Environ 中 f = (charge * pos - dipole) * fact * Z
294+ // 这里的 f_corr 简化后确实类似。
295+
296+ force (iat, dir) += f_corr;
297+
298+ iat++;
299+ }
300+ }
217301}
0 commit comments