NEB modularization

The Nudged Elastic Band implementation was decomposed from a monolithic 1,225-line file into modular, testable components using the Strategy pattern.

Module structure

Module

Lines

Purpose

NudgedElasticBand.cpp

~530

Orchestration: image loop, convergence, CI activation

NEBTangent.cpp

~80

Tangent estimation strategies

NEBProjection.cpp

~80

Force projection strategies

NEBSpringForce.cpp

~140

Spring force strategies (constant, energy-weighted, OM)

NEBForceProjection.cpp

~120

Perpendicular force, CI force, zero-translation

NEBOcinebController.cpp

~180

OCINEB hybrid dimer controller

NEBObjectiveFunction.cpp

~60

Optimizer adapter

NEBSplineExtrema.cpp

~80

Cubic spline peak detection

NEBInitialPaths.cpp

~200

Path initialization (linear, IDPP, file)

Strategy pattern

Three interchangeable strategies are built at NEB construction time via factory functions:

Tangent strategies (NEBTangent.cpp)

  • Improved tangent (default): uses energy-weighted bisection at maxima/minima, standard interpolation elsewhere. Better behavior near transition states.

  • Old tangent: simple finite-difference tau = R[i+1] - R[i-1]. Retained for backward compatibility.

Projection strategies (NEBProjection.cpp)

  • Standard NEB: projects out parallel spring force, keeps perpendicular true force.

  • Elastic band: no projection (spring + true force).

  • Doubly-nudged elastic band (DNEB): adds perpendicular spring force component.

  • Onsager-Machlup: modifies spring constant per-image based on force magnitude.

Spring force strategies (NEBSpringForce.cpp)

  • Constant spring: uniform k for all images.

  • Energy-weighted: adjusts k based on image energy relative to endpoints. Higher k near the barrier, lower in basins.

  • Onsager-Machlup: adaptive k based on local curvature for minimum-action paths.

Climbing image and OCINEB

The climbing image (CI-NEB) modification activates after initial convergence: the highest-energy image climbs along the band to the exact saddle point.

OCINEB (Off-Path Climbing Image NEB) Goswami et al. [NEB_GGJonsson26] extends CI-NEB with Min-Mode Following (MMF) and hessian eigenmode alignment: once the climbing image stabilizes, a dimer search refines the saddle point. NEBOcinebController monitors CI stability and triggers a MinModeSaddleSearch when the angular tolerance is met.

Eigenmode methods

The eigenmode estimation (for dimer/Lanczos) uses std::variant instead of an abstract base class:

using EigenmodeStrategy = std::variant<DimerStrategy, ImprovedDimerStrategy,
                                        LanczosStrategy, GPRDimerStrategy>;

The variant removes virtual dispatch overhead and gives value semantics. It is constructed by buildEigenmodeStrategy() based on configuration.

Solid-state band

solid_state extends the band coordinate with the lower triangle of the cell. SolidStateNEB builds the joint displacement, the Jacobian, and the Cartesian step delta_h = h F_cell / J. projectSolidState applies the tangent and the spring in that metric. OCINEB and zoom are refused because their walks do not carry the cell.

Parallel force evaluation

With [Main] parallel = true, NEB evaluates image forces on a pool of at most std::thread::hardware_concurrency() threads (forEachImage in NudgedElasticBand.cpp); an nvc++ build with -Dstdpar uses std::for_each(std::execution::par) instead. The first exception from any image is rethrown once every thread has joined. The Potential::isThreadSafe() virtual method controls parallelism: Python-based potentials (ASE, CatLearn) return false and fall back to serial evaluation.