Skip to content

Commit c8f6cee

Browse files
authored
improve
1 parent a0992c7 commit c8f6cee

3 files changed

Lines changed: 93 additions & 11 deletions

File tree

source/source_hamilt/module_surchem/cal_vel.cpp

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77
#include <algorithm>
88
#include <iostream>
9+
#include "source_base/global_function.h"
910

1011
// --- 物理常数 ---
1112
const double KB_au = 3.1668114e-6; // Boltzmann constant in Hartree/K
@@ -31,7 +32,7 @@ void surchem::cal_smpbe_physics(const int nrxx,
3132

3233
// Packing fraction theta = c_bulk / c_max
3334
double theta = c_bulk_au * pow(a_ion * Ang2Bohr, 3);
34-
35+
#pragma omp parallel for schedule(static)
3536
for (int ir = 0; ir < nrxx; ir++)
3637
{
3738
// 在介电常数接近 1 的区域(真空/板层内部),强制无离子
@@ -47,8 +48,10 @@ void surchem::cal_smpbe_physics(const int nrxx,
4748
if(u > 20.0) u = 20.0;
4849
if(u < -20.0) u = -20.0;
4950

50-
double sinh_u = sinh(u);
51-
double cosh_u = cosh(u);
51+
double exp_u = std::exp(u);
52+
double exp_neg_u = 1.0 / exp_u;
53+
double sinh_u = 0.5 * (exp_u - exp_neg_u);
54+
double cosh_u = 0.5 * (exp_u + exp_neg_u);
5255

5356
// SMPBE Formula: Lattice-Gas Model
5457
double denom = 1.0 + theta * (cosh_u - 1.0);
@@ -87,7 +90,7 @@ void cal_dielectric_saturation(const int nrxx,
8790
double p_mol_au = (PARAM.inp.p_mol < 0.01) ? 1.85 * 0.39343 : PARAM.inp.p_mol * 0.39343;
8891
// Mol density: 1/Ang^3 -> 1/Bohr^3
8992
double n_mol_au = (PARAM.inp.n_mol < 1e-4) ? 0.0333 * pow(0.52917721, 3) : PARAM.inp.n_mol;
90-
93+
#pragma omp parallel for schedule(static)
9194
for(int i=0; i<nrxx; ++i) {
9295
if(shape_func[i] < 1e-6) {
9396
epsilon_out[i] = 1.0;
@@ -205,7 +208,55 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
205208

206209
// 1. Prepare Data
207210
rho_basis->recip2real(TOTN, TOTN_real);
211+
const double switch_threshold = 0.01;
212+
213+
// 获取用户设定的求解模式 (2 或 3)
214+
int target_imp_sol = PARAM.inp.imp_sol; // 或者 INPUT.imp_sol
215+
int actual_run_mode = target_imp_sol; // 实际运行的模式
216+
217+
// 计算局部的 DRHO
218+
double local_drho = 0.0;
208219

220+
// 检查历史密度是否存在且大小匹配
221+
if(this->rho_history.size() == rho_basis->npw)
222+
{
223+
for(int i=0; i<rho_basis->npw; ++i)
224+
{
225+
// 简单的误差度量:所有 G 分量的模之和 (或者你可以做 FFT 后在实空间积分)
226+
// 这里为了快,直接在倒空间估算
227+
local_drho += std::abs(ps_totn[i] - this->rho_history[i]);
228+
}
229+
// 归一化 (可选,视 ps_totn 的量级而定,通常 ps_totn 是 1/Omega 量级)
230+
// 也可以简单地看绝对值变化
231+
}
232+
else
233+
{
234+
// 如果是第一步 (没有历史),强制认为误差很大,或者直接跑线性
235+
local_drho = 100.0;
236+
this->rho_history.resize(rho_basis->npw);
237+
}
238+
239+
// 保存当前密度到历史 (供下一步用)
240+
for(int i=0; i<rho_basis->npw; ++i) {
241+
this->rho_history[i] = ps_totn[i];
242+
}
243+
244+
// [决策时刻]
245+
if (local_drho > switch_threshold)
246+
{
247+
// 误差太大,降级为线性模型 (跑得快,稳)
248+
if (GlobalV::MY_RANK == 0) {
249+
std::cout << " [SURCHEM] Large DRHO (" << local_drho
250+
<< " > " << switch_threshold
251+
<< "), downgrading to Linear Model (imp_sol=1)." << std::endl;
252+
}
253+
actual_run_mode = 1;
254+
}
255+
else
256+
{
257+
// 误差小,开启完全非线性迭代
258+
actual_run_mode = target_imp_sol;
259+
}
209260
// B_elec = -4pi * rho_elec(G)
210261
std::complex<double> *B_elec = new std::complex<double>[rho_basis->npw];
211262
for (int ig = 0; ig < rho_basis->npw; ig++)
@@ -230,6 +281,17 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
230281
// 3. Setup Variables for Solver
231282
std::complex<double> *Sol_phi = new std::complex<double>[rho_basis->npw];
232283
std::complex<double> *Sol_phi0 = new std::complex<double>[rho_basis->npw];
284+
if (this->phi_history.size() == rho_basis->npw) {
285+
// 有缓存:拷贝作为初猜
286+
for(int i=0; i<rho_basis->npw; ++i) {
287+
Sol_phi[i] = this->phi_history[i];
288+
}
289+
} else {
290+
// 无缓存或大小不匹配:重置为0
291+
ModuleBase::GlobalFunc::ZEROS(Sol_phi, rho_basis->npw);
292+
// 调整大小以备后用
293+
this->phi_history.resize(rho_basis->npw, std::complex<double>(0,0));
294+
}
233295
ModuleBase::GlobalFunc::ZEROS(Sol_phi, rho_basis->npw);
234296

235297
double* rho_ion_R = new double[rho_basis->nrxx];
@@ -240,10 +302,14 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
240302
int ncgsol = 0;
241303

242304
// Mode Determination
243-
int mode = PARAM.inp.imp_sol;
305+
// int mode = PARAM.inp.imp_sol;
306+
int mode = actual_run_mode
244307
bool is_nonlinear = (mode >= 2); // imp_sol = 2 or 3
245308
bool use_dielectric_sat = (mode == 3); // imp_sol = 3 only
246309

310+
if (GlobalV::MY_RANK == 0 && mode != target_imp_sol) {
311+
std::cout << " [SURCHEM] DRHO Check Triggered: Running in Linear Mode (imp_sol=1) temporarily." << std::endl;
312+
}
247313
// =========================================================================
248314
// Nonlinear Loop (VASPsol++) OR Linear Solver (VASPsol)
249315
// =========================================================================
@@ -279,6 +345,7 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
279345
// Linearized Eq: (L - eps*k^2) * dphi = Residual
280346
// Equivalent to solving: (L - eps*k^2) * phi_new = B_elec + B_ion(phi_old) - eps*k^2*phi_old
281347
// RHS in Real Space:
348+
#pragma omp parallel for schedule(static)
282349
for(int i=0; i<rho_basis->nrxx; ++i) {
283350
phi_R_tmp[i] = -4.0 * ModuleBase::PI * rho_ion_R[i]
284351
- epsilon[i] * kappa2_R[i] * phi_R_tmp[i];
@@ -299,8 +366,11 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
299366
diff += std::abs(phi_new[ig] - Sol_phi[ig]);
300367
Sol_phi[ig] = alpha * phi_new[ig] + (1.0 - alpha) * Sol_phi[ig];
301368
}
302-
303-
if(diff < 1e-5 * rho_basis->npw) break;
369+
if (GlobalV::MY_RANK == 0) {
370+
std::cout << "ITER " << iter << " Imp_Sol=" << mode
371+
<< " Diff=" << diff << " Ael=" << this->Ael << std::endl;
372+
}
373+
if(diff < 1e-9 * rho_basis->npw) break;
304374
}
305375

306376
delete[] phi_R_tmp;
@@ -333,6 +403,14 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
333403
delete[] k_dummy;
334404
}
335405

406+
if(this->phi_history.size() != rho_basis->npw) {
407+
this->phi_history.resize(rho_basis->npw);
408+
}
409+
// 保存当前收敛的解,供下一步 SCF 使用
410+
for(int i=0; i<rho_basis->npw; ++i) {
411+
this->phi_history[i] = Sol_phi[i];
412+
}
413+
336414
// 3. Calculate Vel and Ael
337415
double *tmp_Vel = new double[rho_basis->nrxx];
338416
ModuleBase::GlobalFunc::ZEROS(tmp_Vel, rho_basis->nrxx);
@@ -361,7 +439,7 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
361439
this->Ael -= (term_elec + term_ion);
362440
}
363441
Parallel_Reduce::reduce_pool(this->Ael);
364-
this->Ael *= cell.omega / rho_basis->nxyz * 0.5; // Linear Response Factor
442+
this->Ael *= cell.omega / rho_basis->nxyz; // Linear Response Factor
365443

366444
// 4. Calculate Non-electrostatic Potential (eps_pot)
367445
// NOTE: For imp_sol=3, we use the shape-based epsilon gradient for the force term
@@ -407,4 +485,4 @@ ModuleBase::matrix surchem::cal_vel(const UnitCell& cell,
407485

408486
ModuleBase::timer::tick("surchem", "cal_vel");
409487
return Vel;
410-
}
488+
}

source/source_hamilt/module_surchem/minimize_cg.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ void surchem::Leps2(const UnitCell& ucell,
193193
ModuleBase::Vector3<double> *grad_phi = new ModuleBase::Vector3<double>[rho_basis->nrxx];
194194

195195
XC_Functional::grad_rho(phi, grad_phi, rho_basis, ucell.tpiba);
196-
196+
#pragma omp parallel for schedule(static)
197197
for (int ir = 0; ir < rho_basis->nrxx; ir++)
198198
{
199199
grad_phi[ir].x *= epsilon[ir];
@@ -232,7 +232,7 @@ void surchem::Leps2(const UnitCell& ucell,
232232
{
233233
double* phi_real = new double[rho_basis->nrxx];
234234
rho_basis->recip2real(phi, phi_real);
235-
235+
#pragma omp parallel for schedule(static)
236236
for(int ir = 0; ir < rho_basis->nrxx; ir++)
237237
{
238238
// L = div(eps grad) - eps * kappa^2

source/source_hamilt/module_surchem/surchem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "source_cell/unitcell.h"
1111
#include "source_pw/module_pwdft/parallel_grid.h"
1212
#include "source_pw/module_pwdft/structure_factor.h"
13+
#include <vector>
14+
#include <complex>
1315

1416
class surchem
1517
{
@@ -26,6 +28,8 @@ class surchem
2628

2729
static double Acav;
2830
static double Ael;
31+
std::vector<std::complex<double>> phi_history;
32+
std::vector<std::complex<double>> rho_history;
2933

3034
// get atom info
3135
atom_in GetAtom;

0 commit comments

Comments
 (0)