Skip to content

Commit 9569b5e

Browse files
authored
ion_cor
1 parent f7e3770 commit 9569b5e

5 files changed

Lines changed: 217 additions & 93 deletions

File tree

source/source_estate/module_pot/H_Hartree_pw.cpp

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -116,40 +116,39 @@ ModuleBase::matrix H_Hartree_pw::v_hartree(const UnitCell &cell,
116116
for (int ir = 0; ir < rho_basis->nrxx; ir++)
117117
v(is, ir) = Porter[ir].real();
118118
}
119-
if (do_parabolic)
120119
if (use_parabolic)
121120
{
122121
ParabolicCorrection pc;
123-
// int dir = PARAM.inp.dim_corr_dir;
124-
125-
// 1. 修正 Spin 1 (Up) 或 Total
126-
// 注意:这里传入完整的 rho 和 nspin,模块内部会自动处理密度求和
127-
pc.apply_correction(
122+
123+
// 1. 调用 apply_correction (同时获取离子修正能)
124+
double e_ion = pc.apply_correction(
128125
GlobalC::unitcell,
129126
rho_basis,
130-
&v(0, 0), // 修改第一列势场
131-
rho, // 传入完整的 rho 指针 (const double* const*)
132-
nspin, // 传入 nspin
127+
&v(0, 0), // 势场指针
128+
rho, // 密度指针 (const double* const*)
129+
nspin, // 自旋
133130
GlobalV::nelec,
134131
dir
135132
);
136133

137-
// 2. 如果是 Spin 2 (Down),必须施加同样的修正
138-
// 因为 Hartree 势对 Up 和 Down 电子是一样的
134+
// 2. 将离子修正能加到 Hartree 能量中
135+
// 这样总能量就正确了
136+
H_Hartree_pw::hartree_energy += e_ion;
137+
138+
// 3. (可选) 日志输出
139+
if (GlobalV::RANK_IN_POOL == 0) {
140+
std::cout << " Parabolic Correction Applied. E_ion_corr = " << e_ion << " Ry" << std::endl;
141+
}
142+
143+
// 4. 处理 nspin=2 的第二列势场 (能量只需加一次,所以这里不加)
139144
if (nspin == 2) {
140145
pc.apply_correction(
141-
GlobalC::unitcell,
142-
rho_basis,
143-
&v(1, 0), // 修改第二列势场
144-
rho, // 依然传入同样的 rho,计算出的偶极矩是一样的
145-
nspin,
146-
GlobalV::nelec,
147-
dir
146+
GlobalC::unitcell, rho_basis, &v(1, 0),
147+
rho, nspin, GlobalV::nelec, dir
148148
);
149149
}
150150
}
151-
// 对于 nspin=4,通常只处理 v(0, :),因为它是 H_scalar
152-
}
151+
153152
ModuleBase::timer::tick("H_Hartree_pw", "v_hartree");
154153
return v;
155154
} // end subroutine v_h

source/source_hamilt/module_ewald/H_Ewald_pw.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,7 @@ double H_Ewald_pw::compute_ewald(const UnitCell& cell,
168168
// 修改累加公式:加上 term_mt
169169
ewaldg += fact * std::abs(rhon) * std::abs(rhon) * (term_std + term_mt);
170170

171-
/* 原代码参考:
172-
ewaldg += fact * std::abs(rhon) * std::abs(rhon)
173-
* exp(- rho_basis->gg[ig] * cell.tpiba2 / alpha / 4.0 ) / rho_basis->gg[ig] / cell.tpiba2;
174-
*/
175171

176-
177-
ewaldg += fact * std::abs(rhon) * std::abs(rhon)
178-
* exp(- rho_basis->gg[ig] * cell.tpiba2 / alpha / 4.0 ) / rho_basis->gg[ig] / cell.tpiba2;
179172
}
180173

181174
ewaldg = ModuleBase::FOUR_PI / cell.omega * ewaldg;

source/source_hamilt/module_poisson/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
set( sources
55
mt_poisson.cpp
6-
parabolic.cpp
6+
parabolic_correction.cpp
77
)
88

99
add_library(hamilt_poisson OBJECT ${sources})

source/source_hamilt/module_poisson/parabolic_correction.cpp

Lines changed: 133 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
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
// ---------------------------------------------------------
1417
double 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+
// ---------------------------------------------------------
130132
double 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

139141
double 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-
// ---------------------------------------------------------
176175
double 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

Comments
 (0)