Skip to content

Feature: periodic self-consistent continuum solvation (SCCS) Step2: SCCS with PCC 0D/2D - #8194

Open
LKFEIYI wants to merge 3 commits into
deepmodeling:developfrom
LKFEIYI:codex/sccs-pcc-1-coupling
Open

LKFEIYI wants to merge 3 commits into
deepmodeling:developfrom
LKFEIYI:codex/sccs-pcc-1-coupling

Conversation

@LKFEIYI

@LKFEIYI LKFEIYI commented Oct 21, 2026 •

Copy link
Copy Markdown

Reminder

  • I have read AGENTS.md and docs/developers_guide/agent_governance.md.
  • I have linked an issue or explained why this PR does not need one.
  • I have added adequate unit tests and/or case tests, or explained why not.
  • I have listed the exact verification commands run and their results.
  • I have described user-visible behavior changes, including INPUT parameter changes.
  • I have explained core-module impact for ESolver, HSolver, ElecState, Hamilt, Operator, Psi, or other source/ changes.
  • I have requested any needed governance exception below.

Linked Issue

Third part of #8052. It follows #8075 (PCC) and #8162 (SCCS Step 1: periodic SCCS).

Remaining follow-up PRs, each stacked on the previous one: lowpass and full cavity → SCF integration → solvent-aware cavity.

What's changed?

imp_sol 2 can now be combined with assume_isolated pcc_0d and pcc_2d (O. Andreussi and N. Marzari, Phys. Rev. B 90, 245101 (2014)). This removes the cell-size dependence of charged solvated systems: molecules (pcc_0d) and slabs (pcc_2d, open along pcc_2d_axis). Neutral periodic SCCS from Step 1 is unchanged.

Deliberate difference from Environ (inherited from #8075): for a charged slab, pcc_2d uses the monopole constant −πQL/(3A), whereas Environ uses −πQ/(3L).

  • Cavity derivatives: two paths. sccs_cav_deriv builds grad s and lapl s for the dielectric coefficient.

    • Periodic cells keep Step 1's chain derivatives, as Environ deriv_method chain: grad s = s′ grad n and lapl s = s′ lapl n + s″ |grad n|², from FFT derivatives of the density n.
    • With PCC the switching function s itself is differentiated on the FFT grid, as Environ deriv_method fft, because the chain coefficient is not converged at the cavity edge.

    The PCC cases are therefore compared with QE in fft mode below. Periodic results are unchanged from Step 1. CavityPoint gains d2solute_drho2 for the chain path, which is checked against finite differences.

Validation against QE 7.6 + Environ 3.1.1

Case ΔG ABACUS (eV) ΔG QE (eV) ΔΔG (meV)
H2O, PCC2D −0.29933 −0.29932 −0.00
H3O⁺, PCC0D −4.67264 −4.67271 +0.07
H3O⁺, PCC2D, 20 × 20 × 20 bohr (A = L²) −2.07807 −2.07821 +0.14
H3O⁺, PCC2D, 12 × 20 × 12 bohr −0.37602 −1.62666 +1250.6 (monopole constant, see above)
  • Cavity surface and volume agree to 0.01–0.02 bohr² and bohr³.
  • The electrostatic term E_sol_el + E_pcc agrees with QE's "electrostatic embedding" to ≤ 1.2 meV.
  • Solvation forces (solvent − vacuum) agree to 1.1e-4 eV/Å for neutral H2O with PCC2D. For H3O⁺ with PCC they differ by 3–5e-2 eV/Å; there QE's own analytic forces miss its finite differences by 4–6e-2 eV/Å. The lowpass filter in the next PR addresses force accuracy with PCC.

How the comparison was run. (reply to ABACUS-PR-BOT)

  • Each case directory has an ABACUS INPUT/STRU/KPT and a QE pw.in + environ.in.

  • One script runs them with OMP_NUM_THREADS=1:

    • ABACUS: mpirun -np 8 abacus_std_para > run.log
    • QE: mpirun -np 8 pw.x -environ -in pw.in > run.log
  • analyze.py takes ΔG from !FINAL_ETOT_IS (ABACUS) and ! total energy (QE). It reads the surface and volume from the SCCS_CAVITY line and from environ.debug, and the forces from TOTAL-FORCE and "Forces acting on atoms".

  • Executables:

    • ABACUS: the stacked SCCS branch (v3.11.0-beta10), GCC 11, OpenMPI 5.0.10, FFTW 3.3.11, OpenBLAS 0.3.33, ELPA, LibXC 7.1.2.
    • QE 7.6 + Environ 3.1.1.

    The ABACUS energies were reproduced bit-for-bit. Since then the code has only been renamed and switched to the ModuleBase SI constants, which moves the solvation energies by about 2×10⁻⁸ eV.
    Deferred checks: there are no charged integration cases (CI time; charged energies are validated in the table above). Force accuracy with PCC is addressed by the lowpass filter in the next PR.

@ABACUS-PR-BOT ABACUS-PR-BOT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static review of 0c2c11d. No builds or ABACUS runtime tests were run; CI diagnostics were unavailable.

Non-blocking: Please add the exact build/test/comparison commands, executable identity/configuration, MPI ranks and observed outcomes behind the validation table, noting which force/convergence checks remain deferred. Also state the generated INPUT-documentation workflow and whether documentation-generation/CLI checks were run.

Comment thread source/source_io/module_parameter/read_inp_model.cpp
Comment thread source/source_hamilt/module_sccs/sccs_parameters.h Outdated
LKFEIYI and others added 2 commits October 21, 2026 17:28
Address ABACUS-PR-BOT review of SCCS step 2: no declaration in the
header uses std::vector yet.
const double net_charge = ionic_charge - electron_count;
if (config.cavity.epsilon_bulk <= 1.0 || std::abs(net_charge) <= 1e-6) { return std::string(); }
const bool periodic = config.boundary == ModuleSccs::Boundary::Periodic;
if (!periodic || config.cavity.epsilon_bulk <= 1.0 || std::abs(net_charge) <= 1e-6) { return std::string(); }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the 1e-6 seems to be a magic number

}
if (std::abs(electron_error) > 1e-6)
// With PCC the PCC component reports the same mismatch.
if (config_.boundary == ModuleSccs::Boundary::Periodic && std::abs(electron_error) > 1e-6)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, the 1e-6 seems to be a magic number

{
const bool orthogonal = unitcell::make_orthogonal_cell(cell.latvec, cell.lat0, 1e-10, geometry);
const bool cubic = orthogonal && make_pcc_0d_parameters(geometry, 1e-10, parameters);
if (!cubic) { ModuleBase::WARNING_QUIT("pcc_0d_geometry", "PCC 0D requires an equal-edge cubic cell"); }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not write one-liner code here. To keep the structure as clear as possible, put each brace on its own line.

ModuleSccs::gauss_ion_rho(atoms, basis, tpiba,
ModuleSccs::gaussian_ion_spread, ions);
std::vector<double> solute_charge(basis.nrxx);
for (int ir = 0; ir < basis.nrxx; ++ir) { solute_charge[ir] = ions[ir] - density[ir]; }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not write one-liner code here. To keep the structure as clear as possible, put each brace on its own line.

normal = cell.normal;
parameters = elecstate::make_pcc_2d_parameters(cell);
ModulePW::grid_positions(basis, lattice, length, positions);
for (auto& position : positions)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to avoid using auto if possible

double integrate_product(const std::vector<double>& left, const std::vector<double>& right) const
{
double value = 0.0;
for (int ir = 0; ir < basis.nrxx; ++ir) { value += left[ir] * right[ir]; }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not write one-liner code here. To keep the structure as clear as possible, put each brace on its own line.

TEST_F(SccsPcc2dCoulombTest, ChargedPlanarModeMatchesAnalyticGauge)
{
const double density_mean = 1e-3;
const double amplitude = 2e-4;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number, maybe adding some notes for this value?

@mohanchen mohanchen added Feature Discussed The features will be discussed first but will not be implemented soon Refactor Refactor ABACUS codes Tests/Examples Issues/PR related to unit tests and integrate tests labels Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Discussed The features will be discussed first but will not be implemented soon Refactor Refactor ABACUS codes Tests/Examples Issues/PR related to unit tests and integrate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants