feat: r-space parallelization for nonorthogonal lattices (nproc_rgrid>1) - #1265
feat: r-space parallelization for nonorthogonal lattices (nproc_rgrid>1)#1265MZKC wants to merge 3 commits into
Conversation
|
Can one of the admins verify this patch? |
Allow nproc_rgrid>1 on nonorthogonal cells (previously hard-blocked by a guard in initialization.f90). The nonorthogonal kinetic operator builds the off-diagonal-metric cross derivatives by differentiating intermediate per-axis first-derivative fields (df/dx, df/dy). Under r-space domain decomposition those intermediates must have their halos exchanged; the serial code relied on the periodic index wrap and never did, which is why r-space parallelization was forbidden for nonorthogonal lattices. New nonorthogonal-only code paths; orthogonal stencils and serial (nproc_rgrid=1) nonorthogonal paths are untouched: - stencil.f90: zstencil_nonorth_rspace_pass1/pass2 (split of zstencil_nonorthogonal, math identical) storing df/dx, df/dy for an inter-pass halo exchange. - hamiltonian.f90: hpsi_nonorth_rspace (pass1 -> update_overlap(df/dx,df/dy) -> pass2), selected when (.not. stencil%if_orthogonal .and. info%if_divide_rspace). - preconditioning.f90 + conjugate_gradient.f90: zstencil_nonorthogonal_preconditioning_diag, a diagonal-metric CG preconditioner for the r-space-parallel case (cross term dropped; affects only CG convergence rate, not the converged state). - initialization.f90: drop the nonorthogonal+r-space stop guards. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…th r-space The nonorthogonal r-space path replicates all atoms on every r-space rank (info%nion_mg = nion), so comm_summation over icomm_r yields nproc_rgrid*nion and tripped the "Error2 in dividing atom in mg domain" guard before SCF could start. That check is meaningful only for the cuboid (domain-split) path; gate it on flag_cuboid. Found via primitive-Si nproc_rgrid=(1,1,2) validation (serial r1 converged Etot=-198.8545; rgrid r2 stopped here before reaching the kinetic path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pace (Ewald) The nonorthogonal path previously replicated all atoms on every r-space rank (info%nion_mg = nion). The Ewald ion-ion sums (total_energy.f90 / stress.f90 / force.f90) loop over info%ia_mg and reduce over icomm_r, so replication over-counted the real-space Ewald by nproc_rgrid (E_ewa_R and P_ewa_R = nproc_rgrid x serial; +3.5 meV in E_total and +0.1 GPa in P_total for primitive Si nr16, rgrid(1,1,2)). Partition the atoms round-robin over the r-space ranks instead, so each atom is owned by exactly one rank and the reduction yields the full sum (same principle as the cuboid domain-split path). Restore the per-rank atom-count sum check for both paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0f84562 to
6920a35
Compare
Re-validation on
|
| quantity | serial 1,1,1 |
r-space-parallel 1,1,2 |
difference |
|---|---|---|---|
| total energy (eV) | −199.2029957187 | −199.2029957195 | 8.1e-10 |
| eigenvalues, all 8 states (Ha) | ≤ 6e-10 | ||
| 1-particle energies (eV, 4 dp) | identical | identical | 0 |
| force on each atom (au) | ~2.62e-5 | ~2.62e-5 | ~4e-10 |
SCF iterations to threshold = 1e-9 |
32 | 35 | — |
Both occupied and empty states agree to ~1e-10 Ha; total energy and forces reproduce the serial result to sub-1e-9. This is consistent with the original Validation table and confirms the operator behaves identically on develop-2.0.0.
Scope note: the original table also compared stress (P_total), which depends on yn_out_stress / the stress-tensor work that is not present on develop-2.0.0 (it lives in feature/stress-tensor); stress is therefore out of scope for this base. The same applies to r2scan / yn_tau_nlcc, so this re-validation uses the LDA (PZ) path. The nonorthogonal r-space-parallel kinetic operator is XC-independent, so the LDA check exercises exactly the code this PR adds.
MZKC
left a comment
There was a problem hiding this comment.
Checked the two-pass kinetic operator against the serial zstencil_nonorthogonal and it is equivalent: pass1 builds the diagonal-metric Laplacian + lap0 + Bk*nabla and stores df/dx, df/dy; pass2 adds the off-diagonal cross terms as d/dz(df/dy), d/dz(df/dx), d/dy(df/dx), so only the FACE halos of wrk1/wrk2 are needed (no edge/corner ghosts), and the F(4/5/6) pairing, signs and 0.5 factor all match. The diagonal-metric preconditioner only changes CG convergence, not the converged state, and the round-robin atom split is a clean per-atom partition for the icomm_r-reduced Ewald sums. One performance/memory concern, inline.
| nspin=system%nspin | ||
| if_kAc = (yn_periodic=='y') | ||
|
|
||
| allocate(wrk1(mg%is_array(1):mg%ie_array(1),mg%is_array(2):mg%ie_array(2),mg%is_array(3):mg%ie_array(3) & |
There was a problem hiding this comment.
allocate(wrk1(mg%is_array(1):mg%ie_array(1),mg%is_array(2):mg%ie_array(2),mg%is_array(3):mg%ie_array(3) & ,nspin,io_s:io_e,ik_s:ik_e,im_s:im_e))
This allocates two full complex orbital-block work arrays (~2x the wavefunction-block size) on every hpsi call, and hpsi is in the CG / time-propagation hot path. The repeated allocate/deallocate adds allocator churn and a sizable transient memory spike per call. Consider persistent module/scratch workspace (allocated once, sized to the orbital block), or processing one (ispin,io,ik) tile at a time so only a single 3D df/dx, df/dy pair is live — the latter also shrinks the halo-exchange working set. Functionally correct as-is; this is about hot-path cost on large runs.
There was a problem hiding this comment.
Filed as #1269 - the per-call allocation of the work arrays is a performance follow-up, not blocking this PR; the two-pass kinetic math is correct (verified equivalent to the serial zstencil_nonorthogonal).
Summary
Enables real-space domain decomposition (
nproc_rgrid > 1) for nonorthogonal lattices, which was previously disabled by a guard ininitialization.f90. The changes are additive and limited to the nonorthogonal r-space-parallel path; orthogonal stencils and serial (nproc_rgrid = 1) nonorthogonal runs take the existing code path unchanged.Background
The nonorthogonal kinetic operator (
zstencil_nonorthogonal) forms the off-diagonal-metric cross derivatives by differentiating intermediate per-axis first-derivative fields (df/dx,df/dy) held in a work array. The serial path obtains the neighbors of that work array through the periodic index wrap; under r-space decomposition the work array's halo is not exchanged, which is why the case was guarded off. Access is in the face directions only, so the existing face halo is sufficient.Changes
stencil.f90—zstencil_nonorth_rspace_pass1/2: a two-pass split ofzstencil_nonorthogonal(algebraically equivalent) that exposesdf/dx,df/dyfor a halo exchange between the passes.hamiltonian.f90—hpsi_nonorth_rspace: pass1 →update_overlap_complex8(df/dx, df/dy) → pass2, selected when.not. stencil%if_orthogonal .and. info%if_divide_rspace. Reuses the wavefunctionsrg.preconditioning.f90+conjugate_gradient.f90—zstencil_nonorthogonal_preconditioning_diag: a diagonal-metric CG preconditioner for the r-space-parallel case (the cross term would require the same halo). This changes only the preconditioner, not the converged state; for strongly nonorthogonal cells a largerncgmay be needed for convergence.initialization.f90— round-robin atom partition over the r-space ranks. The Ewald ion-ion sums loop overinfo%ia_mgand reduce overicomm_r; with all atoms replicated on each rank the real-space Ewald was countednproc_rgridtimes. The partition assigns each atom to a single rank so the reduction yields the full sum. The guards are removed.Validation
Primitive Si (nonorthogonal FCC,
nr=16, Γ),nproc_rgrid=(1,1,1)vs(1,1,2),ncg=16:Built with the Fujitsu compiler (A64FX).
Notes
The branch is based on
feature/stress-tensor; the changes are independent of the stress / meta-GGA work and can be rebased ontodevelop-2.0.0. The new routines are CPU/OpenMP only (no GPU/OpenACC path).🤖 Generated with Claude Code