66#include < vector>
77#include < algorithm>
88#include < iostream>
9+ #include " source_base/global_function.h"
910
1011// --- 物理常数 ---
1112const 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+ }
0 commit comments