Loading...
Searching...
No Matches
eonc Namespace Reference

RAII resource manager for the ARTn C library with global synchronization. More...

Namespaces

namespace  config
namespace  detail
namespace  dynlib
 Cross-platform dynamic library loading abstraction.
namespace  EpiCenters
namespace  geometry
namespace  helpers
namespace  io
namespace  log
namespace  neb
namespace  pairhess
namespace  params_ssot
namespace  pathintegral
namespace  pbc
namespace  piqtst
namespace  pot
namespace  Prefactor
namespace  rng
namespace  safemath
namespace  tunneling
namespace  xtsci_eindir

Classes

struct  ams_options_t
struct  artn_options_t
class  ARTnResource
class  ARTnSaddleSearch
 Saddle search method using the Activation-Relaxation Technique nouveau. More...
struct  ase_nwchem_options_t
struct  ase_orca_options_t
class  AtomicGPDimer
struct  basin_hopping_options_t
class  BasinHoppingJob
class  BasinHoppingSaddleSearch
struct  bgsd_options_t
class  BGSDObjectiveFunction
class  BiasedGradientSquaredDescent
class  BondBoost
 Functionality relying on the conjugate gradients algorithm. More...
struct  catlearn_options_t
class  CollectiveIDPPObjectiveFunction
class  ConjugateGradients
 Decleration of the Conjugate Gradients optimizer. More...
struct  constants_t
class  Davidson
 Davidson method for the lowest Hessian curvature mode (min-mode). More...
struct  davidson_options_t
struct  debug_options_t
struct  DecodedDiv
struct  dftd_options_t
class  Dimer
 Classic dimer method to find the lowest curvature mode. More...
struct  dimer_options_t
class  DimerModeLostException
class  DimerModeRestoredException
struct  DimerRotationResult
 Result of a non-classical dimer rotation backend (mode estimate only). More...
class  Dynamics
struct  dynamics_options_t
struct  DynamicsConfig
 Configuration extracted from Parameters for Dynamics. More...
class  DynamicsJob
class  DynamicsSaddleSearch
struct  expr_options_t
class  FiniteDifferenceJob
class  FIRE
class  ForceCallTimer
 RAII wrapper for tracking force calls over a scope. More...
class  FPEGuard
class  FPEHandler
class  GleThermostat
 Colored-noise (generalized Langevin) thermostat. More...
struct  global_optimization_options_t
class  GlobalOptimization
class  GlobalOptimizationJob
struct  gp_surrogate_options_t
struct  gpr_dimer_options_t
class  GPSurrogateJob
class  Hessian
struct  hessian_options_t
class  HessianJob
class  Hyperdynamics
struct  hyperdynamics_options_t
class  IARTnResource
class  IDPPObjectiveFunction
class  IIRAResource
class  ILammpsLoader
class  IMetatomicLoader
class  ImprovedDimer
struct  instanton_options_t
class  InstantonJob
 Ring-polymer instanton ([Instanton]): the tunnelling splitting between two minima beyond one-dimensional WKB (mode splitting), or the thermal rate through a saddle (mode rate): the ring below the crossover temperature, and the parabolic barrier factor times harmonic transition-state theory above it, written to instanton.con and results.dat. More...
class  IPluginLoader
class  IPotRegistry
struct  ira_options_t
class  IRACompare
 C++ wrapper for the IRA (Iterative Rotations and Assignments) library. More...
class  IRAResource
class  Job
 Declaration of job class. More...
struct  JobResultEnvelope
 In-memory JobResult scalars. More...
class  LammpsLoader
class  Lanczos
struct  lanczos_options_t
class  LBFGS
class  LORRotation
class  LowestEigenmode
 Base for eigenmode solvers. More...
struct  main_options_t
class  Matter
struct  metatomic_options_t
class  MetatomicDynPot
class  MetatomicLoader
class  MinimizationJob
class  MinModeObjectiveFunction
class  MinModeSaddleSearch
struct  monte_carlo_options_t
class  MonteCarlo
class  MonteCarloJob
struct  mopac_options_t
struct  neb_options_t
class  NEBObjectiveFunction
class  NudgedElasticBand
class  NudgedElasticBandJob
class  ObjectiveFunction
struct  oh_tst_options_t
class  OHTSTJob
class  Optimizer
struct  optimizer_options_t
struct  OptimizerConfig
 Declaration of the optimizer class. More...
struct  parallel_replica_options_t
class  ParallelReplicaJob
class  Parameters
struct  ParametersLoadAccess
 Write hole for INI/JSON loaders and nanobind property setters. More...
class  PluginLoader
class  PointJob
class  Potential
struct  potential_options_t
class  PotentialConstructionScope
 RAII: Potential default construction records on this registry instead of PotRegistry::get(). More...
class  PotRegistry
struct  prefactor_options_t
class  PrefactorJob
struct  process_search_options_t
class  ProcessSearchJob
 Declaration of the Process Search job. More...
class  Quickmin
struct  replica_exchange_options_t
class  ReplicaDynamicsJob
 Base class for replica dynamics jobs (TAD, SafeHyper). More...
class  ReplicaExchangeJob
struct  rgpot_options_t
class  Runtime
 Move-only composition root for process resources (dlopen loaders and the potential registry). More...
struct  saddle_search_options_t
class  SaddleSearchJob
 Declaration of the Saddle Search job. More...
class  SaddleSearchMethod
class  SafeHyperJob
struct  serve_options_t
struct  ServeEndpoint
 Configuration for a single serve endpoint. More...
struct  socket_nwchem_options_t
class  SteepestDescent
class  StructureComparisonJob
struct  StructureComparisonOptions
 Options for Matter::compare / distance. More...
class  SurrogatePotential
struct  tad_options_t
class  TADJob
class  TestJob
struct  thermostat_options_t
class  VesinNeighbors
 RAII wrapper around vesin_neighbors for Matter-style boxes (double[9] row-major 3×3 cell, same layout as Matter::cell). More...
struct  X86DivRegs
struct  xtb_options_t
class  XtsciOptimizer
 xtsci-optimize backend. More...
struct  zbl_options_t
class  ZBLRepulsiveIDPPObjective

Concepts

concept  ThreadSafeQueryable
 Duck-typed thread-safety query.

Typedefs

using EigenmodeStrategy = LowestEigenmode
 Type-erased eigenmode solver. Layout is the same with or without gprd.
using JobFactory
using structure_comparison_options_t = StructureComparisonOptions
using ForceCallback
 Callback type for potential energy/force evaluation.

Enumerations

enum class  PotType {
  UNKNOWN = 0 , EMT , EXT_POT , LJ ,
  LJCLUSTER , MORSE_PT , CUH2 , TIP4P ,
  TIP4P_PT , TIP4P_H , SPCE , EAM_AL ,
  EDIP , FEHE , LENOSKY_SI , SW_SI ,
  TERSOFF_SI , VASP , LAMMPS , MPI ,
  AMS , AMS_IO , GPR , CatLearn ,
  XTB , ASE_ORCA , ASE_POT , ASE_NWCHEM ,
  METATOMIC , ZBL , SocketNWChem , RGPOT ,
  DFTD3 , DFTD4 , EXPR , MOPAC
}
enum class  JobType {
  Unknown = 0 , Process_Search , Saddle_Search , Minimization ,
  Point , Parallel_Replica , Safe_Hyperdynamics , TAD ,
  Replica_Exchange , Basin_Hopping , Hessian , Finite_Difference ,
  Nudged_Elastic_Band , Dynamics , Prefactor , Global_Optimization ,
  Structure_Comparison , Monte_Carlo , Test , GP_Surrogate ,
  OH_TST , Instanton
}
enum class  OptType {
  Unknown = -1 , None = 0 , QM , CG ,
  LBFGS , FIRE , SD , XTSCI
}
enum class  NEBInit {
  LINEAR , IDPP , IDPP_COLLECTIVE , SIDPP ,
  SIDPP_ZBL , FILE
}
enum class  RunStatus { GOOD = 0 , FAIL_MAX_ITERATIONS , FAIL_POTENTIAL_FAILED }
enum class  DimerRotationBackend { Classical = 0 , Lanczos , Davidson , LOR }
enum class  FdScheme { OneSided , Central , Fourth }
 Real finite-difference scheme for the assembled Hessian and for Lanczos/Davidson Hessian-vector products. More...
enum class  PbcConvention { Legacy = 0 , MinimumImage = 1 }

Functions

int getBundleSize ()
std::vector< std::string > unbundle (int number)
void deleteUnbundledFiles (const std::vector< std::string > &unbundledFilenames)
void bundle (int number, const std::vector< std::string > &filenames, std::vector< std::string > *bundledFilenames)
void commandLine (int argc, char **argv)
std::shared_ptr< LowestEigenmode > buildEigenmodeStrategy (std::shared_ptr< Matter > matter, const Parameters &params, std::shared_ptr< Potential > pot)
double maxFreeAtomForceNorm (const double *forces, const double *fixed, long nAtoms)
 Max Euclidean norm over N x 3 row-major force rows.
template<typename Work>
void forEachImage (long n, Work &&work)
static DecodedDiv decode_div_insn (const unsigned char *code, bool long_mode)
static X86DivRegs x86_div_regs (void *scp)
static bool advance_integer_div (void *scp)
static void write_fault_rip (void *scp)
static void fpe_signal_handler (int sig, siginfo_t *sip, void *scp)
void enableFPE ()
void disableFPE ()
std::vector< int > greedyColorCutoffGraph (const std::vector< std::vector< int > > &adj)
 Greedy coloring of an undirected graph.
std::vector< int > colorMobileCutoffGraph (const Matter &matter, const VectorXi &atoms, double cutoff)
 Conflict graph on atoms: two mobile atoms share an edge when their closed cutoff neighborhoods intersect, then greedy-colored.
std::vector< double > cartesianMode (const Matter &matter, const VectorXi &atoms, const Eigen::Ref< const VectorXd > &mode)
 Cartesian displacement of every atom along one mass-weighted mode over the mobile degrees of freedom atoms: x = q / sqrt(m), unit norm, zero on atoms outside atoms.
bool writeNormalModes (Matter &matter, const VectorXi &atoms, const VectorXd &eigenvalues, const MatrixXd &modes, const std::string &path)
 Writes one frame of matter per mode to path, the mode as the displacements section and mode_eigenvalue (eV / (Angstrom^2 amu)), hbar_omega (eV, negative for an imaginary mode) and wavenumber (cm^-1, same sign) as frame metadata.
bool trivialModeCountIsPhysical (long removed, long fixedAtoms)
 Whether removed zero-frequency modes are what the structure's symmetries give: 6 for a free cluster (3 translations and 3 rotations), 5 for a linear one, 3 for a periodic cell, where rotations are no symmetry of the lattice, and none once any atom is fixed.
void forceJobRegistration ()
std::map< JobType, JobFactory > & jobTable ()
void registerJob (JobType type, JobFactory factory)
void evaluateTogether (Potential &pot, std::span< Matter *const > systems)
 Evaluates every system that needs a force update.
bool atomListMeansAll (const std::string &atomList)
 Whether atomList means "every free atom" (empty, "all", case-insensitive).
VectorXi freeAtomIndices (const Matter *matter)
 Free (unfixed) atom indices in ascending order.
VectorXi resolveMobileAtoms (const Matter *matter, const std::string &atomList)
 PHVA-class mobile set for FD Hessian and matrix-free Krylov (Lanczos / Davidson).
VectorXi resolveMobileAtoms (const Matter *matter, const VectorXi &candidates)
 Explicit candidate indices, intersected with free flags (order preserved, duplicates dropped).
VectorXd packMobileRows (const AtomMatrix &full, const VectorXi &mobile)
 Pack full (n_atoms,3) rows of mobile atoms into a 3*n_mobile vector.
void unpackMobileRows (const VectorXd &packed, const VectorXi &mobile, AtomMatrix &full)
 Write a 3*n_mobile vector into full AtomMatrix rows (other rows unchanged).
VectorXd mobileForces (Matter *matter, const VectorXi &mobile)
 Force components on mobile atoms after Matter has a valid force cache (calls getForces under the hood if needed via the non-const Matter API).
AtomMatrix minImageRemoveRigidDrift (const Matter &reference, AtomMatrix diff, Eigen::RowVector3d *totalDrift)
 Minimum-image a free-atom difference and remove rigid translation.
static EonMtaConfig config_from_params (const Parameters &params)
void serveMode (const Parameters &params, const std::string &host, uint16_t port)
 Start a single rgpot-compatible Cap'n Proto RPC server.
void serveMultiple (const std::vector< ServeEndpoint > &endpoints, const Parameters &params)
 Serve multiple potentials concurrently on different ports.
void serveReplicated (const Parameters &params, const std::string &host, uint16_t base_port, size_t replicas)
 Serve N replicas of the same potential across sequential ports.
void serveGateway (const Parameters &params, const std::string &host, uint16_t port, size_t pool_size)
 Start a gateway server backed by a pool of potential instances.
void serveFromConfig (const Parameters &params)
 Start serve mode from config-file parameters.
std::vector< ServeEndpoint > parseServeSpec (const std::string &spec)
 Parse a serve configuration string into endpoints.
void startRpcServer (ForceCallback callback, const std::string &host, uint16_t port)
 Start a blocking Cap'n Proto RPC server using a force callback.
void startPooledRpcServer (std::vector< ForceCallback > pool, const std::string &host, uint16_t port)
 Start a blocking Cap'n Proto RPC server backed by a pool of force callbacks dispatched round-robin.
constexpr bool usesAlternativeRotation (DimerRotationBackend backend) noexcept
std::optional< DimerRotationResult > runAlternativeRotation (DimerRotationBackend backend, const std::shared_ptr< Matter > &matter, const Parameters &params, const std::shared_ptr< Potential > &pot, const AtomMatrix &initialDirection, quill::Logger *log=nullptr)
 Run Lanczos, Davidson, or LOR.
AtomMatrix from_fortran_layout_vector (const std::vector< double > &flat_colmajor, int nat)
 Reconstruct AtomMatrix from a flat column-major vector (e.g.
void lattice_rows_to_fortran_box (const Matrix3d &cell, double *box)
 Pack an eOn cell for pARTn artn_step.
void eigenmodeCompute (LowestEigenmode &s, std::shared_ptr< Matter > matter, AtomMatrix direction)
double eigenmodeGetEigenvalue (LowestEigenmode &s)
AtomMatrix eigenmodeGetEigenvector (LowestEigenmode &s)
ImprovedDimer * asImprovedDimer (LowestEigenmode &s)
long eigenmodeTotalForceCalls (LowestEigenmode &s)
double eigenmodeStatsTorque (LowestEigenmode &s)
double eigenmodeStatsAngle (LowestEigenmode &s)
long eigenmodeStatsRotations (LowestEigenmode &s)
long eigenmodeTotalIterations (LowestEigenmode &s)
FdScheme parseFdScheme (std::string_view scheme)
template<class M>
M fdForceDerivative (FdScheme scheme, double dr, const M &f0, const M &fPlus, const M &fMinus, const M &fPlus2, const M &fMinus2)
 Derivative of a sampled force map along one real step of length dr.
template<class Eval>
VectorXd fdHessianVector (FdScheme scheme, double dr, const VectorXd &force0, Eval &&eval)
 Energy Hessian-vector product -dF.
constexpr std::uint32_t maskWindowsMxcsrForContinue (std::uint32_t mxcsr)
ARTnResource & get_artn_resource ()
 Global access to thread-safe ARTn resource.
IRAResource & get_ira_resource ()
 Global access to thread-safe IRA resource.
void ensure_interpreter ()
double pmfScanS (long plane, long nScan, double guideLen)
 Uniform PMF-scan coordinate.
template<class P>
requires ThreadSafeQueryable<P>
bool potIsThreadSafe (const P &p) noexcept
template<class P>
requires requires(const P &p) { { p.isSharedInstanceThreadSafe() } -> std::convertible_to<bool>; }
bool potAllowsSharedInstance (const P &p) noexcept
bool lammpsWorkerReaped (long got, long child, int err)
 True when waitpid has collected the child. EINTR is not a collection.
std::int64_t lammpsScreenCursor (std::int64_t pos, std::int64_t fileSize, bool restarted)
 Byte offset at which to keep copying a LAMMPS screen file.
std::vector< std::string > lammpsOpenArgs (bool logging, bool with_omp, const std::string &screen)
 LAMMPS argv.

Variables

static constexpr unsigned MXCSR_MASK_IM = 1u << 7
static constexpr unsigned MXCSR_MASK_ZM = 1u << 9
static constexpr unsigned MXCSR_MASK_OM = 1u << 10
constexpr std::uint32_t kWindowsMxcsrExceptionMasks = 0x1F80u
constexpr double kEvToWavenumber = 8065.543937349212
 1 eV in cm^-1, e / (h c) from the exact SI values.
constexpr double IM = 2147483647.0
constexpr double AM = 1.0 / IM
constexpr int NTAB = 32
constexpr int NDIV = 1 + (IM / NTAB)
constexpr double EPS = 1.2e-7
constexpr double RNMX = 1.0 - EPS
constexpr long IM1 = 2147483563
constexpr long IM2 = 2147483399
constexpr long IMM1 = IM1 - 1
constexpr long IA1 = 40014
constexpr long IA2 = 40692
constexpr long IQ1 = 53668
constexpr long IQ2 = 52774
constexpr long IR1 = 12211
constexpr long IR2 = 3791

Detailed Description

RAII resource manager for the ARTn C library with global synchronization.

Runtime loader for engine plugin shared libraries.

Runtime loader for the LAMMPS C library.

Contains all runtime parameters and results.

RAII resource manager for the IRA C library with global synchronization.

Uses dlopen (POSIX) or LoadLibrary (Windows) to load libartn at runtime. Implements global mutex to ensure thread-safety when multiple threads access the Fortran backend which has shared global state.

WARNING: Due to the non-thread-safe Fortran backend, all ARTn operations are serialized through a global mutex. Multiple threads calling ARTn simultaneously will execute sequentially, potentially creating a significant performance bottleneck in multi-threaded contexts. Consider process-level parallelism if true concurrent ARTn operations are required.

Uses dlopen (POSIX) or LoadLibrary (Windows) to load libira at runtime. Implements global mutex to ensure thread-safety when multiple threads access the Fortran backend which has shared global state.

WARNING: Due to the non-thread-safe Fortran backend, all IRA operations are serialized through a global mutex. Multiple threads calling IRA simultaneously will execute sequentially, potentially creating a significant performance bottleneck in multi-threaded contexts. Consider process-level parallelism if true concurrent IRA operations are required.

No functionality just bookkeeping.

Uses dlopen (POSIX) or LoadLibrary (Windows) to load liblammps at runtime rather than requiring it at compile time. This allows a single eOn binary to optionally use LAMMPS potentials if the library is installed.

Engines that ship as their own shared objects (the rgpot metatomic and xtb backends) are found by base name across a search path rather than by an absolute path, so a build, a wheel, and a conda prefix can each place them differently.

Uses dlopen (POSIX) or LoadLibrary (Windows) to load Fortran potential libraries at runtime. The search order is:

  1. Paths from the [Potential] potentials_path config key
  2. EON_POTENTIALS_PATH environment variable (';' on Windows, ':' elsewhere)
  3. Default system library search path (LD_LIBRARY_PATH, etc.)

Call add_config_paths() once at startup (before any potential constructor) to inject config-file paths into the singleton.

Typedef Documentation

◆ EigenmodeStrategy

Type-erased eigenmode solver. Layout is the same with or without gprd.

Definition at line 25 of file EigenmodeStrategy.h.

◆ ForceCallback

Initial value:
std::function<void(long nAtoms, const double *positions,
const int *atomicNrs, double *forces,
double *energy, const double *box)>

Callback type for potential energy/force evaluation.

Flat-array interface that avoids any AtomMatrix type dependency, preventing collisions between eOn's Eigen-based AtomMatrix and rgpot's custom AtomMatrix.

Parameters
nAtomsNumber of atoms.
positionsFlat array [x1,y1,z1, x2,y2,z2, ...] (nAtoms*3).
atomicNrsAtomic numbers [Z1, Z2, ...] (nAtoms).
forcesOutput forces [Fx1,Fy1,Fz1, ...] (nAtoms*3).
energyOutput energy (single double).
boxSimulation cell flat 3x3 row-major (9 doubles).

Definition at line 36 of file ServeRpcServer.h.

◆ JobFactory

Initial value:
std::function<std::unique_ptr<Job>(std::unique_ptr<Parameters>, Runtime &)>
Move-only composition root for process resources (dlopen loaders and the potential registry).
Definition Runtime.h:27

Definition at line 16 of file JobRegistry.h.

◆ structure_comparison_options_t

Enumeration Type Documentation

◆ DimerRotationBackend

enum class eonc::DimerRotationBackend
strong
Enumerator
Classical 
Lanczos 
Davidson 
LOR 

Definition at line 122 of file BaseStructures.h.

◆ FdScheme

enum class eonc::FdScheme
strong

Real finite-difference scheme for the assembled Hessian and for Lanczos/Davidson Hessian-vector products.

Complex-step is not a scheme: cutoffs and external potentials are not holomorphic.

Enumerator
OneSided 
Central 
Fourth 

Definition at line 25 of file FiniteDifference.h.

◆ JobType

enum class eonc::JobType
strong
Enumerator
Unknown 
Process_Search 
Saddle_Search 
Minimization 
Point 
Parallel_Replica 
Safe_Hyperdynamics 
TAD 
Replica_Exchange 
Basin_Hopping 
Hessian 
Finite_Difference 
Nudged_Elastic_Band 
Dynamics 
Prefactor 
Global_Optimization 
Structure_Comparison 
Monte_Carlo 
Test 
GP_Surrogate 
OH_TST 
Instanton 

Definition at line 77 of file BaseStructures.h.

77 {
78 // Only add to the end of this!!!
79 Unknown = 0,
83 Point,
86 TAD,
89 Hessian,
97 Test,
99 OH_TST,
101};

◆ NEBInit

enum class eonc::NEBInit
strong
Enumerator
LINEAR 
IDPP 
IDPP_COLLECTIVE 
SIDPP 
SIDPP_ZBL 
FILE 

Definition at line 115 of file BaseStructures.h.

◆ OptType

enum class eonc::OptType
strong
Enumerator
Unknown 
None 
QM 
CG 
LBFGS 
FIRE 
SD 
XTSCI 

Definition at line 103 of file BaseStructures.h.

103 {
104 // Only add to the end of this!!!
105 Unknown = -1, // an error case
106 None = 0,
107 QM,
108 CG,
109 LBFGS,
110 FIRE,
111 SD,
112 XTSCI
113};

◆ PbcConvention

enum class eonc::PbcConvention
strong
Enumerator
Legacy 
MinimumImage 

Definition at line 36 of file Matter.h.

36 {
37 Legacy = 0,
38 MinimumImage = 1,
39};

◆ PotType

enum class eonc::PotType
strong
Enumerator
UNKNOWN 
EMT 
EXT_POT 
LJ 
LJCLUSTER 
MORSE_PT 
CUH2 
TIP4P 
TIP4P_PT 
TIP4P_H 
SPCE 
EAM_AL 
EDIP 
FEHE 
LENOSKY_SI 
SW_SI 
TERSOFF_SI 
VASP 
LAMMPS 
MPI 
AMS 
AMS_IO 
GPR 
CatLearn 
XTB 
ASE_ORCA 
ASE_POT 
ASE_NWCHEM 
METATOMIC 
ZBL 
SocketNWChem 
RGPOT 
DFTD3 
DFTD4 
EXPR 
MOPAC 

Definition at line 36 of file BaseStructures.h.

36 {
37 // Only add to the end of this!!!
38 UNKNOWN = 0,
39 EMT,
40 EXT_POT,
41 LJ,
44 CUH2,
45 TIP4P,
47 TIP4P_H,
48 SPCE,
49 EAM_AL,
50 EDIP,
51 FEHE,
53 SW_SI,
55 VASP,
56 LAMMPS,
57 MPI,
58 // Add newer entries here
59 AMS,
60 AMS_IO,
61 GPR,
63 XTB,
65 ASE_POT,
68 ZBL,
70 RGPOT,
71 DFTD3,
72 DFTD4,
73 EXPR,
74 MOPAC
75};

◆ RunStatus

enum class eonc::RunStatus
strong
Enumerator
GOOD 
FAIL_MAX_ITERATIONS 
FAIL_POTENTIAL_FAILED 

Definition at line 117 of file BaseStructures.h.

Function Documentation

◆ advance_integer_div()

bool eonc::advance_integer_div ( void * scp)
static

Definition at line 249 of file fpe_handler.cpp.

249 {
250 X86DivRegs regs = x86_div_regs(scp);
251 if (regs.ip == nullptr || regs.ax == nullptr || regs.dx == nullptr) {
252 return false;
253 }
254 const auto *code = reinterpret_cast<const unsigned char *>(*regs.ip);
255 DecodedDiv div = decode_div_insn(code, sizeof(void *) == 8);
256 if (div.length == 0) {
257 return false;
258 }
259 if (div.width <= 2) {
260 *regs.ax &= ~uintptr_t{0xFFFFu};
261 if (div.width == 2) {
262 *regs.dx &= ~uintptr_t{0xFFFFu};
263 }
264 } else {
265 *regs.ax = 0;
266 *regs.dx = 0;
267 }
268 *regs.ip += static_cast<uintptr_t>(div.length);
269 return true;
270}
static X86DivRegs x86_div_regs(void *scp)
static DecodedDiv decode_div_insn(const unsigned char *code, bool long_mode)

◆ asImprovedDimer()

ImprovedDimer * eonc::asImprovedDimer ( LowestEigenmode & s)
inline

Definition at line 44 of file EigenmodeStrategy.h.

44 {
45 return dynamic_cast<ImprovedDimer *>(&s);
46}

◆ atomListMeansAll()

bool eonc::atomListMeansAll ( const std::string & atomList)

Whether atomList means "every free atom" (empty, "all", case-insensitive).

Definition at line 22 of file MobileAtoms.cpp.

22 {
23 if (atomList.empty()) {
24 return true;
25 }
26 // Trim and case-fold "all"
27 size_t b = 0;
28 while (b < atomList.size() &&
29 std::isspace(static_cast<unsigned char>(atomList[b]))) {
30 ++b;
31 }
32 size_t e = atomList.size();
33 while (e > b && std::isspace(static_cast<unsigned char>(atomList[e - 1]))) {
34 --e;
35 }
36 if (e <= b) {
37 return true;
38 }
39 if (e - b != 3) {
40 return false;
41 }
42 auto lower = [](char c) {
43 return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
44 };
45 return lower(atomList[b]) == 'a' && lower(atomList[b + 1]) == 'l' &&
46 lower(atomList[b + 2]) == 'l';
47}

◆ buildEigenmodeStrategy()

std::shared_ptr< LowestEigenmode > eonc::buildEigenmodeStrategy ( std::shared_ptr< Matter > matter,
const Parameters & params,
std::shared_ptr< Potential > pot )

Definition at line 28 of file EigenmodeStrategy.cpp.

29 {
32 if (params.dimer_options().improved) {
33 return std::make_shared<ImprovedDimer>(matter, params, pot);
34 }
35 return std::make_shared<Dimer>(matter, params, pot);
36 }
39 return std::make_shared<Lanczos>(matter, params, pot);
40 }
43 return std::make_shared<Davidson>(matter, params, pot);
44 }
47#ifdef WITH_GPRD
48 return std::make_shared<AtomicGPDimer>(matter, params, pot);
49#else
50 throw std::runtime_error(
51 "min_mode_method=gprdimer needs a -Dwith_gprd build with the private "
52 "gpr_optim repository checked out in subprojects/gpr_optim "
53 "(rsync -a ../gpr_optim/ subprojects/gpr_optim/, then reconfigure)");
54#endif
55 }
56 return std::make_shared<ImprovedDimer>(matter, params, pot);
57}
static const char MINMODE_GPRDIMER[]
static const char MINMODE_DIMER[]
static const char MINMODE_LANCZOS[]
static const char MINMODE_DAVIDSON[]
const dimer_options_t & dimer_options() const
const saddle_search_options_t & saddle_search_options() const

◆ bundle()

void eonc::bundle ( int number,
const std::vector< std::string > & filenames,
std::vector< std::string > * bundledFilenames )

Definition at line 180 of file Bundling.cpp.

181 {
182 for (const auto &filename : filenames) {
183 const auto [baseName, ext] = splitBundleExtension(filename);
184 const std::string newFilename =
185 std::format("{}_{}{}", baseName, number, ext);
186
187 try {
188 fs::rename(filename, newFilename);
189 bundledFilenames->push_back(newFilename);
190 } catch (const fs::filesystem_error &e) {
191 EONC_LOG_ERROR("bundle: cannot rename {} to {}: {}", filename,
192 newFilename, e.what());
193 }
194 }
195}
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:261

◆ cartesianMode()

std::vector< double > eonc::cartesianMode ( const Matter & matter,
const VectorXi & atoms,
const Eigen::Ref< const VectorXd > & mode )

Cartesian displacement of every atom along one mass-weighted mode over the mobile degrees of freedom atoms: x = q / sqrt(m), unit norm, zero on atoms outside atoms.

Row-major N x 3.

Definition at line 748 of file Hessian.cpp.

749 {
750 const long n = matter.numberOfAtoms();
751 std::vector<double> out(static_cast<size_t>(3 * n), 0.0);
752 if (mode.size() != 3 * atoms.size()) {
753 throw std::invalid_argument("cartesianMode: mode length is not 3 x atoms");
754 }
755 double norm2 = 0.0;
756 for (long j = 0; j < mode.size(); ++j) {
757 const long atom = atoms(j / 3);
758 const double mass = matter.getMass(atom);
759 if (!(mass > 0.0)) {
760 throw std::invalid_argument("cartesianMode: atom without a mass");
761 }
762 const double x = mode(j) / std::sqrt(mass);
763 out[static_cast<size_t>(3 * atom + j % 3)] = x;
764 norm2 += x * x;
765 }
766 if (norm2 > 0.0) {
767 const double scale = 1.0 / std::sqrt(norm2);
768 for (double &x : out) {
769 x *= scale;
770 }
771 }
772 return out;
773}
long int numberOfAtoms() const
Definition Matter.cpp:273
double getMass(long int atom) const
Definition Matter.cpp:478

◆ colorMobileCutoffGraph()

std::vector< int > eonc::colorMobileCutoffGraph ( const Matter & matter,
const VectorXi & atoms,
double cutoff )

Conflict graph on atoms: two mobile atoms share an edge when their closed cutoff neighborhoods intersect, then greedy-colored.

Empty when the neighbor list cannot be built.

Definition at line 266 of file Hessian.cpp.

267 {
268 return buildMobileColoring(matter, atoms, cutoff).color;
269}

◆ commandLine()

void eonc::commandLine ( int argc,
char ** argv )

Definition at line 93 of file CommandLine.cpp.

93 {
94 bool sflag = false, mflag = false, pflag = false, cflag = false;
95 double optConvergedForce = 0.001;
96 std::string potential;
97 std::string confile;
98 std::string confileout;
99 std::string optimizer("cg");
100
101#ifdef WITH_SERVE_MODE
102 std::optional<std::string> config_path;
103 std::optional<std::string> serve_spec;
104 // Empty until the matching flag is passed. A value here makes has_value()
105 // true, so -p alone takes the serve path and never reads a structure file.
106 std::optional<std::string> serve_host;
107 std::optional<uint16_t> serve_port;
108 std::optional<size_t> replicas;
109 std::optional<bool> gateway;
110#endif
111
112 auto params = Parameters{};
113
114 const char *progname = (argc ? argv[0] : "eonclient");
115
116 Argum::Parser parser;
117
118 parser.add(Argum::Option("--help", "-h")
119 .help("show this help message and exit")
120 .handler([&]() {
121 // Format help with color
122 auto helpText = parser.formatHelp(progname);
123 std::cout << colorizer.heading("eOn Client - Help")
124 << "\n\n";
125 std::cout << helpText;
126 std::exit(EXIT_SUCCESS);
127 }));
128
129 parser.add(Argum::Option("--version", "-v")
130 .help("Print version information")
131 .handler([&]() {
132 std::cout << VERSION_STRING << std::endl;
133 std::exit(EXIT_SUCCESS);
134 }));
135
136 parser.add(Argum::Option("--features")
137 .help("Print compile-time features")
138 .handler([&]() {
140 std::exit(EXIT_SUCCESS);
141 }));
142
143 parser.add(Argum::Option("--minimize", "-m")
144 .help("Minimization of inputConfile saves to outputConfile")
145 .handler([&]() { mflag = true; }));
146
147 parser.add(Argum::Option("--single", "-s")
148 .help("Single point energy of inputConfile")
149 .handler([&]() { sflag = true; }));
150
151 parser.add(Argum::Option("--compare", "-c")
152 .help("Compare structures of inputConfile to outputConfile")
153 .handler([&]() { cflag = true; }));
154
155 parser.add(
156 Argum::Option("--optimizer", "-o")
157 .argName("METHOD")
158 .help("Optimization method")
159 .handler([&](const std::string_view &value) { optimizer = value; }));
160
161 parser.add(Argum::Option("--force", "-f")
162 .argName("VALUE")
163 .help("Convergence force")
164 .handler([&](const std::string_view &value) {
165 optConvergedForce = Argum::parseFloatingPoint<double>(value);
166 }));
167
168 parser.add(
169 Argum::Option("--tolerance", "-t")
170 .argName("VALUE")
171 .help("Distance tolerance")
172 .handler([&](const std::string_view &value) {
174 .distance_difference = Argum::parseFloatingPoint<double>(value);
175 }));
176
177 parser.add(Argum::Option("--potential", "-p")
178 .argName("POTENTIAL")
179 .help("The potential (e.g. qsc, lj, eam_al)")
180 .handler([&](const std::string_view &value) {
181 pflag = true;
182 potential = value;
183 }));
184
185#ifdef WITH_SERVE_MODE
186 parser.add(
187 Argum::Option("--serve")
188 .argName("SPEC")
189 .help("Serve potential(s) over rgpot Cap'n Proto RPC. "
190 "Spec: 'potential:port' or 'pot1:port1,pot2:port2'")
191 .handler([&](const std::string_view &value) { serve_spec = value; }));
192
193 parser.add(
194 Argum::Option("--serve-host")
195 .argName("HOST")
196 .help("Host to bind RPC server(s) to")
197 .handler([&](const std::string_view &value) { serve_host = value; }));
198
199 parser.add(Argum::Option("--serve-port")
200 .argName("PORT")
201 .help("Port for single-potential serve mode (used with -p)")
202 .handler([&](const std::string_view &value) {
203 serve_port = Argum::parseIntegral<uint16_t>(value);
204 }));
205
206 parser.add(Argum::Option("--replicas")
207 .argName("N")
208 .help("Number of replicated server instances (used with -p)")
209 .handler([&](const std::string_view &value) {
210 replicas = Argum::parseIntegral<size_t>(value);
211 }));
212
213 parser.add(Argum::Option("--gateway")
214 .help("Run a single gateway port backed by N pool instances "
215 "(use with -p and --replicas)")
216 .handler([&]() { gateway = true; }));
217
218 parser.add(Argum::Option("--config")
219 .argName("FILE")
220 .help("Config file for potential parameters (INI format, "
221 "e.g. [Metatomic] model_path=model.pt)")
222 .handler([&](const std::string_view &value) {
223 config_path = value;
224 }));
225#endif
226
227 // One value each: the partitioner hands a greedy zeroOrMoreTimes positional
228 // every remaining argument, which leaves confileout empty and overwrites
229 // confile with the last one.
230 parser.add(
231 Argum::Positional("confile")
232 .help("Input structure file")
233 .occurs(Argum::zeroOrOneTime)
234 .handler([&](const std::string_view &value) { confile = value; }));
235
236 parser.add(
237 Argum::Positional("confileout")
238 .help("Output structure file (optional)")
239 .occurs(Argum::zeroOrOneTime)
240 .handler([&](const std::string_view &value) { confileout = value; }));
241
242 try {
243 parser.parse(argc, argv);
244 } catch (const Argum::ParsingException &ex) {
245 std::cerr << colorizer.error(ex.message()) << '\n';
246 std::cerr << colorizer.warning(parser.formatUsage(progname)) << '\n';
247 std::exit(EXIT_FAILURE);
248 }
249
250 if (sflag && mflag) {
251 std::cerr << colorizer.error(
252 "Cannot specify both minimization and single point\n");
253 std::exit(EXIT_FAILURE);
254 }
255
256 if (!pflag && (sflag || mflag)) {
257 std::cerr << colorizer.error("Must specify a potential\n");
258 std::exit(EXIT_FAILURE);
259 }
260
261 if (cflag && confileout.empty()) {
262 std::cerr << colorizer.error(
263 "Comparison needs two structure files: the input con file and the "
264 "one to compare it against\n");
265 std::cerr << colorizer.warning(parser.formatUsage(progname)) << '\n';
266 std::exit(EXIT_FAILURE);
267 }
268
269#ifdef WITH_SERVE_MODE
270 // Load config file if provided (for potential-specific parameters
271 // like model_path, device, length_unit, etc.)
272 if (config_path.has_value()) {
273 std::ifstream config_file(config_path.value());
274 if (!config_file.is_open()) {
275 std::cerr << colorizer.error("Cannot open config file: ")
276 << config_path.value() << '\n';
277 std::exit(EXIT_FAILURE);
278 }
279 params.load(config_path.value());
280 }
281
282 // Handle --serve mode (does not require a con file)
283 if (serve_spec.has_value()) {
284 auto endpoints = parseServeSpec(serve_spec.value());
285 if (endpoints.empty()) {
286 std::cerr << colorizer.error("No valid serve endpoints in spec: ")
287 << serve_spec.value() << '\n';
288 std::exit(EXIT_FAILURE);
289 }
290 serveMultiple(endpoints, params);
291 std::exit(EXIT_SUCCESS);
292 }
293
294 // Handle -p with serve flags (single potential serve mode).
295 // Defaults are applied below with value_or; has_value() is the flag.
296 if (pflag && !sflag && !mflag && !cflag &&
297 (serve_host.has_value() || serve_port.has_value() ||
298 replicas.has_value() || gateway.has_value())) {
299 for (auto &ch : potential) {
300 ch = std::tolower(static_cast<unsigned char>(ch));
301 }
303 magic_enum::enum_cast<PotType>(potential, magic_enum::case_insensitive)
304 .value_or(PotType::UNKNOWN);
305 auto host = serve_host.value_or("localhost");
306 auto port = serve_port.value_or(12345);
307 auto reps = replicas.value_or(1);
308 bool gw = gateway.value_or(false);
309
310 if (gw) {
311 serveGateway(params, host, port, reps);
312 } else if (reps > 1) {
313 serveReplicated(params, host, port, reps);
314 } else {
315 serveMode(params, host, port);
316 }
317 std::exit(EXIT_SUCCESS);
318 }
319
320 // Config-driven serve (no -p or --serve, just --config with [Serve])
321 if (!pflag && !sflag && !mflag && !cflag && config_path.has_value() &&
322 !serve_spec.has_value() &&
326 serveFromConfig(params);
327 std::exit(EXIT_SUCCESS);
328 }
329#endif
330
331 // Serve modes take no structure file and have already exited above.
332 if (confile.empty()) {
333 std::cerr << colorizer.error(
334 "At least one non-option argument is required: the con file\n");
335 std::cerr << colorizer.warning(parser.formatUsage(progname)) << '\n';
336 std::exit(EXIT_FAILURE);
337 }
338
339 if (!cflag) {
340 for (auto &ch : potential) {
341 ch = std::tolower(static_cast<unsigned char>(ch));
342 }
343 }
344
345 if (!cflag) {
347 magic_enum::enum_cast<PotType>(potential, magic_enum::case_insensitive)
348 .value_or(PotType::UNKNOWN);
349 }
350
351 if (!sflag) {
353 magic_enum::enum_cast<OptType>(optimizer, magic_enum::case_insensitive)
354 .value_or(OptType::CG);
356 optConvergedForce;
357 }
358
359 if (cflag) {
360 // Matter copies structure_comparison_options into its own structComp in
361 // the constructor, so the flag has to be set before the two below.
363 .check_rotation = true;
364 }
365
366 auto pot = eonc::helpers::makePotential(params);
367 auto matter = std::make_unique<Matter>(pot, params);
368 auto matter2 = std::make_unique<Matter>(pot, params);
369 if (!eonc::io::io_ok(matter->con2matter(confile))) {
370 std::cerr << "Failed to load " << confile << std::endl;
371 std::exit(EXIT_FAILURE);
372 }
373
374 if (sflag) {
375 singlePoint(std::move(matter));
376 } else if (mflag) {
377 minimize(std::move(matter), confileout);
378 } else if (cflag) {
379 if (!eonc::io::io_ok(matter2->con2matter(confileout))) {
380 std::cerr << "Failed to load " << confileout << std::endl;
381 std::exit(EXIT_FAILURE);
382 }
383 Matter probe(*matter);
384 if (probe.compare(*matter2, true)) {
385 std::cout << "Structures match\n";
386 } else {
387 std::cout << colorizer.error("Structures do not match\n");
388 }
389 }
390}
void printFeatures()
void minimize(std::unique_ptr< eonc::Matter > matter, const std::string &confileout)
void singlePoint(std::unique_ptr< eonc::Matter > matter)
std::shared_ptr< Potential > makePotential(const Parameters &params)
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38
std::vector< ServeEndpoint > parseServeSpec(const std::string &spec)
Parse a serve configuration string into endpoints.
void serveGateway(const Parameters &params, const std::string &host, uint16_t port, size_t pool_size)
Start a gateway server backed by a pool of potential instances.
void serveMode(const Parameters &params, const std::string &host, uint16_t port)
Start a single rgpot-compatible Cap'n Proto RPC server.
Definition ServeMode.cpp:58
void serveFromConfig(const Parameters &params)
Start serve mode from config-file parameters.
void serveMultiple(const std::vector< ServeEndpoint > &endpoints, const Parameters &base_params)
Serve multiple potentials concurrently on different ports.
Definition ServeMode.cpp:81
void serveReplicated(const Parameters &params, const std::string &host, uint16_t base_port, size_t replicas)
Serve N replicas of the same potential across sequential ports.
static structure_comparison_options_t & structure_comparison_options(Parameters &p)
static optimizer_options_t & optimizer_options(Parameters &p)
static serve_options_t & serve_options(Parameters &p)
static potential_options_t & potential_options(Parameters &p)

◆ config_from_params()

EonMtaConfig eonc::config_from_params ( const Parameters & params)
static

Definition at line 16 of file MetatomicDynPot.cpp.

16 {
17 const auto &o = params.metatomic_options();
18 EonMtaConfig c{};
19 c.model_path = o.model_path.c_str();
20 c.device = o.device.c_str();
21 c.length_unit = o.length_unit.c_str();
22 c.extensions_directory = o.extensions_directory.c_str();
23 c.check_consistency = o.check_consistency ? 1 : 0;
24 c.uncertainty_threshold = o.uncertainty_threshold;
25 c.energy_output = o.energy_output.c_str();
26 c.energy_uncertainty_output = o.energy_uncertainty_output.c_str();
27 c.force_output = o.force_output.c_str();
28 c.non_conservative = o.non_conservative ? 1 : 0;
29 c.random_rotation = o.random_rotation ? 1 : 0;
30 c.n_symmetry_rotations = o.n_symmetry_rotations;
31 c.deterministic = o.deterministic ? 1 : 0;
32 c.deterministic_strict = o.deterministic_strict ? 1 : 0;
33 c.variant_base = o.variant.base.c_str();
34 c.variant_energy = o.variant.energy.c_str();
35 c.variant_energy_uncertainty = o.variant.energy_uncertainty.c_str();
36 c.variant_force = o.variant.force.c_str();
37 return c;
38}
const metatomic_options_t & metatomic_options() const
Flat config for create (mirrors eonc::Parameters::metatomic_options_t).
const char * device
const char * extensions_directory
const char * variant_force
const char * model_path
const char * length_unit
long n_symmetry_rotations
const char * energy_output
const char * force_output
const char * variant_base
const char * energy_uncertainty_output
const char * variant_energy
const char * variant_energy_uncertainty
double uncertainty_threshold

◆ decode_div_insn()

DecodedDiv eonc::decode_div_insn ( const unsigned char * code,
bool long_mode )
static

Definition at line 120 of file fpe_handler.cpp.

120 {
121 DecodedDiv out{0, 0};
122 const unsigned char *p = code;
123 const unsigned char *limit = code + 15;
124 bool operand16 = false;
125 bool rex_w = false;
126 bool addr16 = false;
127 while (p < limit) {
128 unsigned char c = *p;
129 if (c == 0x66) {
130 operand16 = true;
131 ++p;
132 continue;
133 }
134 if (c == 0x67) {
135 if (!long_mode) {
136 addr16 = true;
137 }
138 ++p;
139 continue;
140 }
141 if (c == 0xF0 || c == 0xF2 || c == 0xF3 || c == 0x26 || c == 0x2E ||
142 c == 0x36 || c == 0x3E || c == 0x64 || c == 0x65) {
143 ++p;
144 continue;
145 }
146 if (long_mode && c >= 0x40 && c <= 0x4F) {
147 rex_w = (c & 0x08) != 0;
148 ++p;
149 continue;
150 }
151 break;
152 }
153 if (addr16 || p >= limit) {
154 return out;
155 }
156 unsigned char opcode = *p++;
157 if (opcode != 0xF6 && opcode != 0xF7) {
158 return out;
159 }
160 if (p >= limit) {
161 return out;
162 }
163 unsigned char modrm = *p++;
164 unsigned mod = modrm >> 6;
165 unsigned reg = (modrm >> 3) & 7u;
166 unsigned rm = modrm & 7u;
167 if (reg != 6u && reg != 7u) {
168 return out;
169 }
170 if (mod != 3u) {
171 bool have_sib = rm == 4u;
172 unsigned sib_base = 0;
173 if (have_sib) {
174 if (p >= limit) {
175 return out;
176 }
177 sib_base = static_cast<unsigned>(*p++ & 7u);
178 }
179 if ((mod == 0u && rm == 5u) || (have_sib && mod == 0u && sib_base == 5u) ||
180 mod == 2u) {
181 if (p + 4 > limit) {
182 return out;
183 }
184 p += 4;
185 } else if (mod == 1u) {
186 if (p + 1 > limit) {
187 return out;
188 }
189 ++p;
190 }
191 }
192 int length = static_cast<int>(p - code);
193 if (length < 2 || length > 15) {
194 return out;
195 }
196 out.length = length;
197 if (opcode == 0xF6) {
198 out.width = 1;
199 } else if (rex_w) {
200 out.width = 8;
201 } else if (operand16) {
202 out.width = 2;
203 } else {
204 out.width = 4;
205 }
206 return out;
207}

◆ deleteUnbundledFiles()

void eonc::deleteUnbundledFiles ( const std::vector< std::string > & unbundledFilenames)

Definition at line 145 of file Bundling.cpp.

145 {
146 for (const auto &filename : unbundledFilenames) {
147 std::error_code ec;
148 fs::remove(filename, ec);
149 if (ec) {
150 EONC_LOG_ERROR("deleteUnbundledFiles: cannot remove {}: {}", filename,
151 ec.message());
152 }
153 }
154}

◆ disableFPE()

void eonc::disableFPE ( )

Definition at line 527 of file fpe_handler.cpp.

527 {
528#ifdef _WIN32
529 // Mask all floating-point exceptions (restore default behavior)
530 unsigned int control;
531 _controlfp_s(&control, _MCW_EM, _MCW_EM);
532#elif defined(__unix__)
533 fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
534#elif defined(__APPLE__)
535 fenv_t env;
536 fegetenv(&env);
537#if defined(__aarch64__)
538 env.__fpcr &= ~((1u << 8) | (1u << 9) | (1u << 10));
539#elif defined(__x86_64__)
540 // enableFPE clears MXCSR IM/ZM/OM. Restoring that environment unchanged
541 // leaves the traps armed.
542 env.__mxcsr |= (MXCSR_MASK_IM | MXCSR_MASK_ZM | MXCSR_MASK_OM);
543 env.__mxcsr &= ~0x3Fu;
544 env.__control = static_cast<unsigned short>(env.__control | (1u << 0) |
545 (1u << 2) | (1u << 3));
546 env.__status = static_cast<unsigned short>(env.__status & ~0x3Fu);
547#endif
548 fesetenv(&env);
549#if defined(__x86_64__)
550 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_INVALID |
551 _MM_MASK_DIV_ZERO | _MM_MASK_OVERFLOW);
552#endif
553#endif
554}
static constexpr unsigned MXCSR_MASK_ZM
static constexpr unsigned MXCSR_MASK_OM
static constexpr unsigned MXCSR_MASK_IM

◆ eigenmodeCompute()

void eonc::eigenmodeCompute ( LowestEigenmode & s,
std::shared_ptr< Matter > matter,
AtomMatrix direction )
inline

Definition at line 31 of file EigenmodeStrategy.h.

32 {
33 s.compute(matter, direction);
34}
virtual void compute(std::shared_ptr< Matter > matter, AtomMatrix initialDirection)=0

◆ eigenmodeGetEigenvalue()

double eonc::eigenmodeGetEigenvalue ( LowestEigenmode & s)
inline

Definition at line 36 of file EigenmodeStrategy.h.

36 {
37 return s.getEigenvalue();
38}
virtual double getEigenvalue()=0

◆ eigenmodeGetEigenvector()

AtomMatrix eonc::eigenmodeGetEigenvector ( LowestEigenmode & s)
inline

Definition at line 40 of file EigenmodeStrategy.h.

40 {
41 return s.getEigenvector();
42}
virtual AtomMatrix getEigenvector()=0

◆ eigenmodeStatsAngle()

double eonc::eigenmodeStatsAngle ( LowestEigenmode & s)
inline

Definition at line 54 of file EigenmodeStrategy.h.

54{ return s.statsAngle; }

◆ eigenmodeStatsRotations()

long eonc::eigenmodeStatsRotations ( LowestEigenmode & s)
inline

Definition at line 56 of file EigenmodeStrategy.h.

56 {
57 return s.statsRotations;
58}

◆ eigenmodeStatsTorque()

double eonc::eigenmodeStatsTorque ( LowestEigenmode & s)
inline

Definition at line 52 of file EigenmodeStrategy.h.

52{ return s.statsTorque; }

◆ eigenmodeTotalForceCalls()

long eonc::eigenmodeTotalForceCalls ( LowestEigenmode & s)
inline

Definition at line 48 of file EigenmodeStrategy.h.

48 {
49 return s.totalForceCalls;
50}

◆ eigenmodeTotalIterations()

long eonc::eigenmodeTotalIterations ( LowestEigenmode & s)
inline

Definition at line 60 of file EigenmodeStrategy.h.

60 {
61 return s.totalIterations;
62}

◆ enableFPE()

void eonc::enableFPE ( )

Definition at line 491 of file fpe_handler.cpp.

491 {
492#ifdef _WIN32
493 // Register Windows SEH handler for FPE reporting
494 SetUnhandledExceptionFilter(windowsFPEHandler);
495 // Enable floating-point exceptions on Windows
496 _controlfp_s(nullptr, 0, _MCW_EM);
497 _controlfp_s(nullptr, ~(_EM_ZERODIVIDE | _EM_INVALID | _EM_OVERFLOW),
498 _MCW_EM);
499#elif defined(__unix__)
500 // Enable floating-point exceptions on Unix
501 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
502#elif defined(__APPLE__) && defined(__aarch64__)
503 // ARM: trap-enable bits live in FPCR (IOE/DZE/OFE), not FPSR flags.
504 fenv_t env;
505 fegetenv(&env);
506 env.__fpcr |= ((1u << 8) | (1u << 9) | (1u << 10));
507 fesetenv(&env);
508#elif defined(__APPLE__) && defined(__x86_64__)
509 // Enable floating-point exceptions on Intel macOS
510 _MM_SET_EXCEPTION_MASK(
511 _MM_MASK_MASK &
512 ~(_MM_MASK_INVALID | _MM_MASK_DIV_ZERO | _MM_MASK_OVERFLOW));
513#else
514 fprintf(stderr, "FPE trapping not supported on this platform.\n");
515#endif
516
517#ifndef _WIN32
518 // Register POSIX signal handler
519 struct sigaction act;
520 act.sa_sigaction = fpe_signal_handler;
521 sigemptyset(&act.sa_mask);
522 act.sa_flags = SA_SIGINFO;
523 sigaction(SIGFPE, &act, nullptr);
524#endif
525}
static void fpe_signal_handler(int sig, siginfo_t *sip, void *scp)

◆ ensure_interpreter()

void eonc::ensure_interpreter ( )
inline

Definition at line 21 of file NbGuard.h.

21 {
22 if (!Py_IsInitialized()) {
23 // 0 = skip signal handlers (same idea as pybind11 embed defaults)
24 Py_InitializeEx(0);
25 }
26}

◆ evaluateTogether()

void eonc::evaluateTogether ( Potential & pot,
std::span< Matter *const > systems )

Evaluates every system that needs a force update.

With a potential that batches, the dirty systems go through forceBatch in one call, so calculator groups take them together; otherwise each computes on its own. Systems that are current are left alone.

Definition at line 847 of file Matter.cpp.

847 {
848 std::vector<Matter *> dirty;
849 for (Matter *m : systems) {
850 if (m != nullptr && m->needsForceUpdate()) {
851 dirty.push_back(m);
852 }
853 }
854 if (dirty.empty()) {
855 return;
856 }
857 if (dirty.size() == 1 || !pot.supportsBatchEvaluation()) {
858 for (Matter *m : dirty) {
859 m->getForcesRaw();
860 }
861 return;
862 }
863 const long n = dirty.size();
864 const long atoms = dirty.front()->numberOfAtoms();
865 std::vector<VectorXi> nrs(n);
866 std::vector<Matrix3d> boxes(n);
867 std::vector<const double *> posPtr, boxPtr;
868 std::vector<const int *> nrsPtr;
869 std::vector<double *> frcPtr;
870 for (long j = 0; j < n; ++j) {
871 Matter *m = dirty[j];
872 if (m->numberOfAtoms() != atoms) {
873 throw std::invalid_argument(
874 "evaluateTogether: systems differ in atom count");
875 }
876 nrs[j] = m->getAtomicNrs();
877 // A non-periodic system hands the potential a zero box, as
878 // computePotential does.
879 boxes[j] = m->getPeriodic() ? m->getCell() : Matrix3d::Zero().eval();
880 }
881 for (long j = 0; j < n; ++j) {
882 posPtr.push_back(dirty[j]->getPositions().data());
883 nrsPtr.push_back(nrs[j].data());
884 frcPtr.push_back(dirty[j]->forcesData());
885 boxPtr.push_back(boxes[j].data());
886 }
887 std::vector<double> energies(n), variances(n);
888 pot.forceBatch(n, atoms, posPtr.data(), nrsPtr.data(), frcPtr.data(),
889 energies.data(), variances.data(), boxPtr.data());
890 for (long j = 0; j < n; ++j) {
891 dirty[j]->setComputedPotential(energies[j], variances[j]);
892 }
893}
VectorXi getAtomicNrs() const
Definition Matter.cpp:691

◆ fdForceDerivative()

template<class M>
M eonc::fdForceDerivative ( FdScheme scheme,
double dr,
const M & f0,
const M & fPlus,
const M & fMinus,
const M & fPlus2,
const M & fMinus2 )

Derivative of a sampled force map along one real step of length dr.

Fourth-order central: [-f(+2h) + 8 f(+h) - 8 f(-h) + f(-2h)] / (12 h).

Definition at line 46 of file FiniteDifference.h.

47 {
48 M slope = fPlus;
49 switch (scheme) {
51 slope = (-fPlus2 + 8.0 * fPlus - 8.0 * fMinus + fMinus2) / (12.0 * dr);
52 break;
54 slope = (fPlus - fMinus) / (2.0 * dr);
55 break;
57 slope = (fPlus - f0) / dr;
58 break;
59 }
60 return slope;
61}

◆ fdHessianVector()

template<class Eval>
VectorXd eonc::fdHessianVector ( FdScheme scheme,
double dr,
const VectorXd & force0,
Eval && eval )

Energy Hessian-vector product -dF.

eval(scale) is the force at x + scale * dr * v. One-sided and central read only the samples they need; fourth reads scale in {1, -1, 2, -2}.

Definition at line 67 of file FiniteDifference.h.

68 {
69 const VectorXd zero = VectorXd::Zero(force0.size());
70 switch (scheme) {
71 case FdScheme::Fourth: {
72 const VectorXd fPlus = eval(1.0);
73 const VectorXd fMinus = eval(-1.0);
74 const VectorXd fPlus2 = eval(2.0);
75 const VectorXd fMinus2 = eval(-2.0);
76 return -fdForceDerivative(scheme, dr, force0, fPlus, fMinus, fPlus2,
77 fMinus2);
78 }
79 case FdScheme::Central: {
80 const VectorXd fPlus = eval(1.0);
81 const VectorXd fMinus = eval(-1.0);
82 return -fdForceDerivative(scheme, dr, force0, fPlus, fMinus, zero, zero);
83 }
85 break;
86 }
87 const VectorXd fPlus = eval(1.0);
88 return -fdForceDerivative(FdScheme::OneSided, dr, force0, fPlus, zero, zero,
89 zero);
90}
M fdForceDerivative(FdScheme scheme, double dr, const M &f0, const M &fPlus, const M &fMinus, const M &fPlus2, const M &fMinus2)
Derivative of a sampled force map along one real step of length dr.

◆ forceJobRegistration()

void eonc::forceJobRegistration ( )

Definition at line 41 of file Job.cpp.

41{}

◆ forEachImage()

template<typename Work>
void eonc::forEachImage ( long n,
Work && work )
inline

Definition at line 19 of file ForEachImage.h.

19 {
20 if (n <= 0)
21 return;
22 const long hw =
23 std::max(1L, static_cast<long>(std::thread::hardware_concurrency()));
24 const long nThreads = std::min(n, hw);
25 std::atomic<long> next{1};
26 std::exception_ptr failure;
27 std::mutex failureMutex;
28 auto worker = [&] {
29 for (long i = next.fetch_add(1); i <= n; i = next.fetch_add(1)) {
30 try {
31 work(i);
32 } catch (...) {
33 std::lock_guard<std::mutex> lock(failureMutex);
34 if (!failure)
35 failure = std::current_exception();
36 }
37 }
38 };
39 std::vector<std::thread> threads;
40 threads.reserve(static_cast<size_t>(nThreads - 1));
41 try {
42 for (long t = 1; t < nThreads; t++)
43 threads.emplace_back(worker);
44 } catch (...) {
45 // Thread creation failed; the threads already running finish the band.
46 std::lock_guard<std::mutex> lock(failureMutex);
47 if (!failure)
48 failure = std::current_exception();
49 }
50 worker();
51 for (auto &t : threads)
52 t.join();
53 if (failure)
54 std::rethrow_exception(failure);
55}

◆ fpe_signal_handler()

void eonc::fpe_signal_handler ( int sig,
siginfo_t * sip,
void * scp )
static

Definition at line 289 of file fpe_handler.cpp.

289 {
290 // Async-signal-safe only: write(2) and sig_atomic_t. No iostream, malloc,
291 // backtrace, or fenv helpers (fedisableexcept / feclearexcept are not
292 // async-signal-safe). All continue-state is written into the saved ucontext
293 // so it is restored on sigreturn.
294 //
295 // x86 cannot "continue" past a trapped FP op by clearing sticky flags:
296 // flags are bits 0-5 of MXCSR/swd, but the exception MASK bits live at
297 // MXCSR 7-12. Clearing 0x3F leaves trapping armed, so the faulting
298 // instruction re-executes on the same operands and re-raises forever
299 // (report, sigreturn, refault) -- multi-GB identical stderr lines and a
300 // client stuck at ~100% CPU. Mask the class in the restored MXCSR so
301 // re-execution produces the IEEE default (Inf/NaN) and proceeds.
302 static volatile sig_atomic_t reported_div = 0;
303 static volatile sig_atomic_t reported_inv = 0;
304 static volatile sig_atomic_t reported_ovf = 0;
305 static volatile sig_atomic_t reported_unk = 0;
306 static volatile sig_atomic_t reported_int = 0;
307
308 static constexpr char prefix[] = "FPE (continuing, masking further): ";
309 static constexpr char msg_div[] = "division by zero\n";
310 static constexpr char msg_inv[] = "invalid operation\n";
311 static constexpr char msg_ovf[] = "overflow\n";
312 static constexpr char msg_unk[] = "unknown\n";
313
314 // Default: mask all three classes we enable at startup, so an unknown
315 // si_code cannot leave trapping armed and re-storm.
316 unsigned mxcsr_mask_bits = MXCSR_MASK_IM | MXCSR_MASK_ZM | MXCSR_MASK_OM;
317 volatile sig_atomic_t *reported = &reported_unk;
318 const char *msg = msg_unk;
319 size_t msg_len = sizeof(msg_unk) - 1;
320
321 // Integer #DE has no mask bit. Returning here re-executes the divide.
322 if (sip->si_code == FPE_INTDIV || sip->si_code == FPE_INTOVF) {
323 if (reported_int == 0) {
324 reported_int = 1;
325 static constexpr char iprefix[] = "FPE (continuing, skipping divide): ";
326 static constexpr char msg_idiv[] = "integer divide\n";
327 static constexpr char msg_iovf[] = "integer overflow\n";
328 const char *imsg = sip->si_code == FPE_INTDIV ? msg_idiv : msg_iovf;
329 size_t imsg_len = sizeof(msg_iovf) - 1;
330 if (sip->si_code == FPE_INTDIV) {
331 imsg_len = sizeof(msg_idiv) - 1;
332 }
333 write(STDERR_FILENO, iprefix, sizeof(iprefix) - 1);
334 write(STDERR_FILENO, imsg, imsg_len);
335 write_fault_rip(scp);
336 }
337 if (!advance_integer_div(scp) && sip->si_code == FPE_INTDIV) {
338 static constexpr char stuck[] =
339 "FPE integer divide: could not skip faulting instruction\n";
340 write(STDERR_FILENO, stuck, sizeof(stuck) - 1);
341 _exit(128 + SIGFPE);
342 }
343 return;
344 }
345
346 switch (sip->si_code) {
347 case FPE_FLTDIV:
348 reported = &reported_div;
349 msg = msg_div;
350 msg_len = sizeof(msg_div) - 1;
351 mxcsr_mask_bits = MXCSR_MASK_ZM;
352 break;
353 case FPE_FLTINV:
354 reported = &reported_inv;
355 msg = msg_inv;
356 msg_len = sizeof(msg_inv) - 1;
357 mxcsr_mask_bits = MXCSR_MASK_IM;
358 break;
359 case FPE_FLTOVF:
360 reported = &reported_ovf;
361 msg = msg_ovf;
362 msg_len = sizeof(msg_ovf) - 1;
363 mxcsr_mask_bits = MXCSR_MASK_OM;
364 break;
365 default:
366 break;
367 }
368
369 if (*reported == 0) {
370 *reported = 1;
371 write(STDERR_FILENO, prefix, sizeof(prefix) - 1);
372 write(STDERR_FILENO, msg, msg_len);
373 // First-fault RIP for post-mortem addr2line / offline diagnosis.
374 write_fault_rip(scp);
375 }
376
377#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__))
378 ucontext_t *ctx = static_cast<ucontext_t *>(scp);
379 if (ctx->uc_mcontext.fpregs) {
380 // Clear sticky exception FLAGS (bits 0-5) and arm the MASK bit(s) for
381 // the fault class (bits 7-12). Mask sticks after sigreturn because the
382 // restored MXCSR becomes the live CPU state.
383 ctx->uc_mcontext.fpregs->swd &= ~0x3Fu;
384 ctx->uc_mcontext.fpregs->mxcsr &= ~0x3Fu;
385 ctx->uc_mcontext.fpregs->mxcsr |= mxcsr_mask_bits;
386 // x87 control word: mask bits are 0-5 of cwd (IM, DM, ZM, OM, UM, PM).
387 // Set the matching masks so a legacy x87 fault cannot re-storm either.
388 if (mxcsr_mask_bits & MXCSR_MASK_ZM) {
389 ctx->uc_mcontext.fpregs->cwd |= (1u << 2); // x87 ZM
390 }
391 if (mxcsr_mask_bits & MXCSR_MASK_IM) {
392 ctx->uc_mcontext.fpregs->cwd |= (1u << 0); // x87 IM
393 }
394 if (mxcsr_mask_bits & MXCSR_MASK_OM) {
395 ctx->uc_mcontext.fpregs->cwd |= (1u << 3); // x87 OM
396 }
397 }
398#elif defined(__linux__) && defined(__aarch64__)
399 // ARM polarity is the opposite of MXCSR: FPCR trap-enable bits SET mean
400 // trap. Clearing sticky FPSR flags alone re-executes with trapping still
401 // armed on aarch64. Clear the matching FPCR enables.
402 constexpr uint32_t kFpsimdMagic = 0x46508001u;
403 constexpr unsigned kFpcrIoe = 1u << 8;
404 constexpr unsigned kFpcrDze = 1u << 9;
405 constexpr unsigned kFpcrOfe = 1u << 10;
406 unsigned fpcr_clear = kFpcrIoe | kFpcrDze | kFpcrOfe;
407 if (mxcsr_mask_bits == MXCSR_MASK_ZM) {
408 fpcr_clear = kFpcrDze;
409 } else if (mxcsr_mask_bits == MXCSR_MASK_IM) {
410 fpcr_clear = kFpcrIoe;
411 } else if (mxcsr_mask_bits == MXCSR_MASK_OM) {
412 fpcr_clear = kFpcrOfe;
413 }
414 auto *ctx = static_cast<ucontext_t *>(scp);
415 unsigned char *p =
416 reinterpret_cast<unsigned char *>(ctx->uc_mcontext.__reserved);
417 unsigned char *end = p + sizeof(ctx->uc_mcontext.__reserved);
418 struct A64Head {
419 uint32_t magic;
420 uint32_t size;
421 };
422 struct Fpsimd {
423 A64Head head;
424 uint32_t fpsr;
425 uint32_t fpcr;
426 };
427 while (p + sizeof(A64Head) <= end) {
428 auto *h = reinterpret_cast<A64Head *>(p);
429 if (h->magic == 0 || h->size < sizeof(A64Head)) {
430 break;
431 }
432 if (h->magic == kFpsimdMagic && h->size >= sizeof(Fpsimd) &&
433 p + h->size <= end) {
434 auto *f = reinterpret_cast<Fpsimd *>(p);
435 f->fpsr &= ~0x1Fu;
436 f->fpcr &= ~fpcr_clear;
437 break;
438 }
439 if (h->size == 0) {
440 break;
441 }
442 p += h->size;
443 }
444#elif defined(__APPLE__) && defined(__x86_64__)
445 // Darwin restores SSE state from uc_mcontext->__fs. Mask bits have the
446 // same polarity as Linux MXCSR: set means the class does not trap. Without
447 // that update the faulting instruction re-executes and re-raises forever.
448 auto *ctx = static_cast<ucontext_t *>(scp);
449 if (ctx->uc_mcontext) {
450 auto &fs = ctx->uc_mcontext->__fs;
451 fs.__fpu_mxcsr &= ~0x3Fu;
452 fs.__fpu_mxcsr |= mxcsr_mask_bits;
453 if (mxcsr_mask_bits & MXCSR_MASK_ZM) {
454 fs.__fpu_fcw.__zdiv = 1;
455 }
456 if (mxcsr_mask_bits & MXCSR_MASK_IM) {
457 fs.__fpu_fcw.__invalid = 1;
458 }
459 if (mxcsr_mask_bits & MXCSR_MASK_OM) {
460 fs.__fpu_fcw.__ovrfl = 1;
461 }
462 fs.__fpu_fsw.__invalid = 0;
463 fs.__fpu_fsw.__denorm = 0;
464 fs.__fpu_fsw.__zdiv = 0;
465 fs.__fpu_fsw.__ovrfl = 0;
466 fs.__fpu_fsw.__undfl = 0;
467 fs.__fpu_fsw.__precis = 0;
468 }
469#elif defined(__APPLE__) && defined(__aarch64__)
470 constexpr unsigned kFpcrIoe = 1u << 8;
471 constexpr unsigned kFpcrDze = 1u << 9;
472 constexpr unsigned kFpcrOfe = 1u << 10;
473 unsigned fpcr_clear = kFpcrIoe | kFpcrDze | kFpcrOfe;
474 if (mxcsr_mask_bits == MXCSR_MASK_ZM) {
475 fpcr_clear = kFpcrDze;
476 } else if (mxcsr_mask_bits == MXCSR_MASK_IM) {
477 fpcr_clear = kFpcrIoe;
478 } else if (mxcsr_mask_bits == MXCSR_MASK_OM) {
479 fpcr_clear = kFpcrOfe;
480 }
481 auto *ctx = static_cast<ucontext_t *>(scp);
482 if (ctx->uc_mcontext) {
483 ctx->uc_mcontext->__ns.__fpsr &= ~0x1Fu;
484 ctx->uc_mcontext->__ns.__fpcr &= ~fpcr_clear;
485 }
486#endif
487 (void)sig;
488}
static void write_fault_rip(void *scp)
static bool advance_integer_div(void *scp)

◆ freeAtomIndices()

VectorXi eonc::freeAtomIndices ( const Matter * matter)

Free (unfixed) atom indices in ascending order.

Definition at line 49 of file MobileAtoms.cpp.

49 {
50 if (!matter) {
51 throw std::invalid_argument("freeAtomIndices: null Matter");
52 }
53 const long n = matter->numberOfAtoms();
54 std::vector<int> free;
55 free.reserve(static_cast<size_t>(matter->numberOfFreeAtoms()));
56 for (long i = 0; i < n; ++i) {
57 if (!matter->getFixed(i)) {
58 free.push_back(static_cast<int>(i));
59 }
60 }
61 VectorXi out(static_cast<Eigen::Index>(free.size()));
62 for (Eigen::Index k = 0; k < out.size(); ++k) {
63 out(k) = free[static_cast<size_t>(k)];
64 }
65 return out;
66}
long int numberOfFreeAtoms() const
Definition Matter.cpp:583
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:505

◆ from_fortran_layout_vector()

AtomMatrix eonc::from_fortran_layout_vector ( const std::vector< double > & flat_colmajor,
int nat )
inline

Reconstruct AtomMatrix from a flat column-major vector (e.g.

from Fortran). RowMajor(N,3) and ColMajor(3,N) share the same contiguous memory layout, so this is effectively a reinterpretation of the flat data.

Definition at line 61 of file Eigen.h.

61 {
62 assert(flat_colmajor.size() >= static_cast<size_t>(3 * nat));
63 return Eigen::Map<const AtomMatrix>(flat_colmajor.data(), nat, 3);
64}

◆ get_artn_resource()

ARTnResource & eonc::get_artn_resource ( )
inline

Global access to thread-safe ARTn resource.

Definition at line 171 of file ARTnResource.h.

171{ return ARTnResource::instance(); }
static ARTnResource & instance()
Thread-safe singleton accessor (Meyer's pattern).

◆ get_ira_resource()

IRAResource & eonc::get_ira_resource ( )
inline

Global access to thread-safe IRA resource.

Definition at line 127 of file IRAResource.h.

127{ return IRAResource::instance(); }
static IRAResource & instance()
Thread-safe singleton accessor (Meyer's pattern).

◆ getBundleSize()

int eonc::getBundleSize ( )

Definition at line 27 of file Bundling.cpp.

27 {
28 int num_bundle = -1;
29
30 for (const auto &entry : fs::directory_iterator(".")) {
31 std::string name = entry.path().filename().string();
32
33 if (name.empty() || name[0] == '.') {
34 continue;
35 }
36
37 // If "config" is not in the filename
38 // then skip.
39 if (name.find("config") == std::string::npos &&
40 name.find("ini") == std::string::npos) {
41 continue;
42 }
43
44 // Find the last underscore
45 auto upos = name.rfind('_');
46 if (upos == std::string::npos) {
47 continue;
48 }
49
50 // Find the last period
51 auto dpos = name.rfind('.');
52 if (dpos == std::string::npos || dpos <= upos) {
53 continue;
54 }
55
56 std::string numstr = name.substr(upos + 1, dpos - upos - 1);
57 int value = 0;
58 const auto parsed =
59 std::from_chars(numstr.data(), numstr.data() + numstr.size(), value);
60 if (parsed.ec == std::errc{} && parsed.ptr != numstr.data()) {
61 const int i = value + 1;
62 if (i > num_bundle) {
63 num_bundle = i;
64 }
65 }
66 }
67
68 return num_bundle;
69}

◆ greedyColorCutoffGraph()

std::vector< int > eonc::greedyColorCutoffGraph ( const std::vector< std::vector< int > > & adj)

Greedy coloring of an undirected graph.

adj[v] lists neighbors of v (self-loops ignored). Colors are dense from 0 in vertex order.

Definition at line 241 of file Hessian.cpp.

241 {
242 const int n = static_cast<int>(adj.size());
243 std::vector<int> color(static_cast<std::size_t>(n), -1);
244 std::vector<int> used(static_cast<std::size_t>(std::max(n, 0)), 0);
245 int epoch = 0;
246 for (int v = 0; v < n; ++v) {
247 ++epoch;
248 for (int u : adj[static_cast<std::size_t>(v)]) {
249 if (u < 0 || u >= n || u == v) {
250 continue;
251 }
252 const int cu = color[static_cast<std::size_t>(u)];
253 if (cu >= 0 && cu < n) {
254 used[static_cast<std::size_t>(cu)] = epoch;
255 }
256 }
257 int c = 0;
258 while (c < n && used[static_cast<std::size_t>(c)] == epoch) {
259 ++c;
260 }
261 color[static_cast<std::size_t>(v)] = c;
262 }
263 return color;
264}

◆ jobTable()

std::map< JobType, JobFactory > & eonc::jobTable ( )

Definition at line 14 of file JobRegistry.cpp.

14 {
15 static std::map<JobType, JobFactory> t;
16 return t;
17}

◆ lammpsOpenArgs()

std::vector< std::string > eonc::lammpsOpenArgs ( bool logging,
bool with_omp,
const std::string & screen )
inline

LAMMPS argv.

The log file stays off. A screen path is copied into the process logger by the caller.

Definition at line 51 of file LAMMPSPot.h.

52 {
53 std::vector<std::string> args{"liblammps", "-echo", "screen", "-log", "none"};
54 if (logging) {
55 args.insert(args.end(), {"-screen", screen});
56 } else {
57 args.insert(args.end(), {"-screen", "none"});
58 }
59 if (with_omp) {
60 args.insert(args.end(), {"-suffix", "omp"});
61 }
62 return args;
63}

◆ lammpsScreenCursor()

std::int64_t eonc::lammpsScreenCursor ( std::int64_t pos,
std::int64_t fileSize,
bool restarted )
inline

Byte offset at which to keep copying a LAMMPS screen file.

A new LAMMPS open truncates that file, so a restart or a shorter file reads from the start.

Definition at line 41 of file LAMMPSPot.h.

42 {
43 if (restarted || pos < 0 || fileSize < pos) {
44 return 0;
45 }
46 return pos;
47}

◆ lammpsWorkerReaped()

bool eonc::lammpsWorkerReaped ( long got,
long child,
int err )
inline

True when waitpid has collected the child. EINTR is not a collection.

Definition at line 31 of file LAMMPSPot.h.

31 {
32 if (got == child) {
33 return true;
34 }
35 return got < 0 && err != EINTR;
36}

◆ lattice_rows_to_fortran_box()

void eonc::lattice_rows_to_fortran_box ( const Matrix3d & cell,
double * box )
inline

Pack an eOn cell for pARTn artn_step.

Lattice vector i is row i here and Fortran column i there (box(:,i)). Row-major cell memory is already that column-major layout. Filling box so Fortran box(i,j) equals cell(i,j) sends the transpose.

Definition at line 71 of file Eigen.h.

71 {
72 for (int vec = 0; vec < 3; ++vec) {
73 for (int comp = 0; comp < 3; ++comp) {
74 box[vec * 3 + comp] = cell(vec, comp);
75 }
76 }
77}

◆ maskWindowsMxcsrForContinue()

std::uint32_t eonc::maskWindowsMxcsrForContinue ( std::uint32_t mxcsr)
constexpr

Definition at line 24 of file fpe_handler.h.

24 {
25 return (mxcsr & ~std::uint32_t{0x3Fu}) | kWindowsMxcsrExceptionMasks;
26}
constexpr std::uint32_t kWindowsMxcsrExceptionMasks
Definition fpe_handler.h:23

◆ maxFreeAtomForceNorm()

double eonc::maxFreeAtomForceNorm ( const double * forces,
const double * fixed,
long nAtoms )
nodiscard

Max Euclidean norm over N x 3 row-major force rows.

An atom is ignored when fixed is non-null and all three of its mask entries are greater than 0.5 (fully fixed). fixed == nullptr keeps every atom. Returns 0 when nAtoms is not positive, and NaN when any free atom's norm is NaN, on every SIMD target.

Definition at line 106 of file ForceNorm.cpp.

107 {
108 return detail::maxFreeAtomForceNormScalar(forces, fixed, 0, nAtoms);
109}
double maxFreeAtomForceNormScalar(const double *forces, const double *fixed, long begin, long nAtoms)
Scalar max of per-atom Euclidean norms on [begin, nAtoms).
Definition ForceNorm.h:25

◆ minImageRemoveRigidDrift()

AtomMatrix eonc::minImageRemoveRigidDrift ( const Matter & reference,
AtomMatrix diff,
Eigen::RowVector3d * totalDrift )

Minimum-image a free-atom difference and remove rigid translation.

One pbc pass wraps boundary atoms while a uniform drift remains, so the primary guideline and each symmetry product share this fixed point.

Definition at line 71 of file OHTSTJob.cpp.

72 {
73 // AV-embedded frames ride the defect (drift = one hop vector, a/2<011>
74 // observed). Atoms near a cell boundary min-image inconsistently until
75 // that drift is gone, so min-image and de-drift iterate to a fixed point.
76 // The residual is the localized reaction coordinate.
77 Eigen::RowVector3d total = Eigen::RowVector3d::Zero();
78 for (int pass = 0; pass < 6; ++pass) {
79 diff = reference.pbc(diff);
80 const Eigen::RowVector3d drift =
81 diff.colwise().sum() / static_cast<double>(diff.rows());
82 diff.rowwise() -= drift;
83 total += drift;
84 if (drift.norm() < 1e-6) {
85 break;
86 }
87 }
88 if (totalDrift != nullptr) {
89 *totalDrift = total;
90 }
91 return diff;
92}
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.cpp:810

◆ mobileForces()

VectorXd eonc::mobileForces ( Matter * matter,
const VectorXi & mobile )

Force components on mobile atoms after Matter has a valid force cache (calls getForces under the hood if needed via the non-const Matter API).

Definition at line 142 of file MobileAtoms.cpp.

142 {
143 const AtomMatrix forces = matter->getForces();
144 return packMobileRows(forces, mobile);
145}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
const AtomMatrix & getForces() const
Definition Matter.cpp:412
VectorXd packMobileRows(const AtomMatrix &full, const VectorXi &mobile)
Pack full (n_atoms,3) rows of mobile atoms into a 3*n_mobile vector.

◆ packMobileRows()

VectorXd eonc::packMobileRows ( const AtomMatrix & full,
const VectorXi & mobile )

Pack full (n_atoms,3) rows of mobile atoms into a 3*n_mobile vector.

Definition at line 127 of file MobileAtoms.cpp.

127 {
128 VectorXd packed(3 * mobile.size());
129 for (Eigen::Index a = 0; a < mobile.size(); ++a) {
130 packed.segment<3>(3 * a) = full.row(mobile(a));
131 }
132 return packed;
133}

◆ parseFdScheme()

FdScheme eonc::parseFdScheme ( std::string_view scheme)
inline

Definition at line 27 of file FiniteDifference.h.

27 {
28 std::string lower;
29 lower.reserve(scheme.size());
30 for (unsigned char c : scheme) {
31 lower.push_back(static_cast<char>(std::tolower(c)));
32 }
33 if (lower == "central") {
34 return FdScheme::Central;
35 }
36 if (lower == "fourth" || lower == "fourth_order" || lower == "central4") {
37 return FdScheme::Fourth;
38 }
39 return FdScheme::OneSided;
40}

◆ parseServeSpec()

std::vector< ServeEndpoint > eonc::parseServeSpec ( const std::string & spec)

Parse a serve configuration string into endpoints.

Accepts comma-separated entries of the form "potential:port" or "potential:host:port". Examples: "lj:12345" "metatomic:12345,lj:12346" "metatomic:0.0.0.0:12345"

Parameters
specThe comma-separated endpoint specification.
Returns
A vector of ServeEndpoint structs.

Definition at line 232 of file ServeMode.cpp.

232 {
233 std::vector<ServeEndpoint> endpoints;
234 std::istringstream stream(spec);
235 std::string token;
236
237 while (std::getline(stream, token, ',')) {
238 // Trim whitespace
239 token.erase(0, token.find_first_not_of(" \t"));
240 token.erase(token.find_last_not_of(" \t") + 1);
241 if (token.empty())
242 continue;
243
244 // Parse "potential:port" or "potential:host:port"
245 size_t first_colon = token.find(':');
246 if (first_colon == std::string::npos) {
247 EONC_LOG_ERROR("Invalid serve spec '{}': expected 'potential:port'",
248 token);
249 continue;
250 }
251
252 std::string pot_str = token.substr(0, first_colon);
253 std::string rest = token.substr(first_colon + 1);
254
255 // Trim parts after colon split
256 pot_str.erase(0, pot_str.find_first_not_of(" \t"));
257 pot_str.erase(pot_str.find_last_not_of(" \t") + 1);
258 rest.erase(0, rest.find_first_not_of(" \t"));
259 rest.erase(rest.find_last_not_of(" \t") + 1);
260
261 // Lowercase the potential name
262 std::ranges::transform(pot_str, pot_str.begin(), [](unsigned char c) {
263 return static_cast<char>(std::tolower(c));
264 });
265
266 ServeEndpoint ep;
267 ep.potential =
268 magic_enum::enum_cast<PotType>(pot_str, magic_enum::case_insensitive)
269 .value_or(PotType::UNKNOWN);
270
271 if (ep.potential == PotType::UNKNOWN) {
272 EONC_LOG_ERROR("Unknown potential type '{}'", pot_str);
273 continue;
274 }
275
276 size_t second_colon = rest.find(':');
277 if (second_colon != std::string::npos) {
278 // "host:port" format
279 ep.host = rest.substr(0, second_colon);
280 ep.host.erase(0, ep.host.find_first_not_of(" \t"));
281 ep.host.erase(ep.host.find_last_not_of(" \t") + 1);
282 std::string port_str = rest.substr(second_colon + 1);
283 port_str.erase(0, port_str.find_first_not_of(" \t"));
284 port_str.erase(port_str.find_last_not_of(" \t") + 1);
285 ep.port = static_cast<uint16_t>(std::stoi(port_str));
286 } else {
287 // "port" only
288 ep.host = "localhost";
289 ep.port = static_cast<uint16_t>(std::stoi(rest));
290 }
291
292 QUILL_LOG_INFO(eonc::log::get(), "Parsed endpoint: {} on {}:{}",
293 std::string(magic_enum::enum_name(ep.potential)), ep.host,
294 ep.port);
295 endpoints.push_back(ep);
296 }
297
298 return endpoints;
299}
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition EonLogger.h:44

◆ pmfScanS()

double eonc::pmfScanS ( long plane,
long nScan,
double guideLen )
inline

Uniform PMF-scan coordinate.

Plane 0 is the reactant (s = 0) and plane nScan-1 is the product (s = guideLen). s_init is not applied.

Definition at line 26 of file OHTSTJob.h.

26 {
27 const long n = nScan < 2L ? 2L : nScan;
28 return static_cast<double>(plane) * guideLen / static_cast<double>(n - 1);
29}

◆ potAllowsSharedInstance()

template<class P>
requires requires(const P &p) { { p.isSharedInstanceThreadSafe() } -> std::convertible_to<bool>; }
bool eonc::potAllowsSharedInstance ( const P & p)
nodiscardnoexcept

Definition at line 38 of file PotCapabilities.h.

38 {
39 return p.isSharedInstanceThreadSafe();
40}

◆ potIsThreadSafe()

template<class P>
requires ThreadSafeQueryable<P>
bool eonc::potIsThreadSafe ( const P & p)
nodiscardnoexcept

Definition at line 30 of file PotCapabilities.h.

30 {
31 return p.isThreadSafe();
32}

◆ registerJob()

void eonc::registerJob ( JobType type,
JobFactory factory )

Definition at line 19 of file JobRegistry.cpp.

19 {
20 jobTable()[type] = std::move(factory);
21}
std::map< JobType, JobFactory > & jobTable()

◆ resolveMobileAtoms() [1/2]

VectorXi eonc::resolveMobileAtoms ( const Matter * matter,
const std::string & atomList )

PHVA-class mobile set for FD Hessian and matrix-free Krylov (Lanczos / Davidson).

free/fixed on Matter is the optimizer mask. The mobile set is a (possibly proper) subset of free atoms: those that are displaced in finite-difference Hessian-vector products (Li & Jensen, Theor. Chem. Acc. 107, 211 (2002)).

atomList empty or "all" -> all free atoms (backward-compatible default). Otherwise comma/space-separated 0-based indices, intersected with free flags; order follows the list (duplicates dropped). Out-of-range and fixed indices are skipped.

Definition at line 68 of file MobileAtoms.cpp.

68 {
69 if (!matter) {
70 throw std::invalid_argument("resolveMobileAtoms: null Matter");
71 }
72 if (atomListMeansAll(atomList)) {
73 return freeAtomIndices(matter);
74 }
75 const long n = matter->numberOfAtoms();
76 std::vector<int> mobile;
77 std::unordered_set<int> seen;
78 std::string token;
79 for (size_t p = 0; p <= atomList.size(); ++p) {
80 const char c = (p < atomList.size()) ? atomList[p] : ',';
81 if (c == ',' || c == ' ' || c == '\t' || p == atomList.size()) {
82 if (!token.empty()) {
83 try {
84 const long idx = std::stol(token);
85 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
86 seen.insert(static_cast<int>(idx)).second) {
87 mobile.push_back(static_cast<int>(idx));
88 }
89 } catch (const std::exception &) {
90 // skip non-integer tokens
91 }
92 token.clear();
93 }
94 } else {
95 token.push_back(c);
96 }
97 }
98 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
99 for (Eigen::Index k = 0; k < out.size(); ++k) {
100 out(k) = mobile[static_cast<size_t>(k)];
101 }
102 return out;
103}
bool atomListMeansAll(const std::string &atomList)
Whether atomList means "every free atom" (empty, "all", case-insensitive).
VectorXi freeAtomIndices(const Matter *matter)
Free (unfixed) atom indices in ascending order.

◆ resolveMobileAtoms() [2/2]

VectorXi eonc::resolveMobileAtoms ( const Matter * matter,
const VectorXi & candidates )

Explicit candidate indices, intersected with free flags (order preserved, duplicates dropped).

Used by pyeonclient compute(..., atoms=...).

Definition at line 105 of file MobileAtoms.cpp.

105 {
106 if (!matter) {
107 throw std::invalid_argument("resolveMobileAtoms: null Matter");
108 }
109 const long n = matter->numberOfAtoms();
110 std::vector<int> mobile;
111 std::unordered_set<int> seen;
112 mobile.reserve(static_cast<size_t>(candidates.size()));
113 for (Eigen::Index k = 0; k < candidates.size(); ++k) {
114 const long idx = candidates(k);
115 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
116 seen.insert(static_cast<int>(idx)).second) {
117 mobile.push_back(static_cast<int>(idx));
118 }
119 }
120 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
121 for (Eigen::Index k = 0; k < out.size(); ++k) {
122 out(k) = mobile[static_cast<size_t>(k)];
123 }
124 return out;
125}

◆ runAlternativeRotation()

std::optional< DimerRotationResult > eonc::runAlternativeRotation ( DimerRotationBackend backend,
const std::shared_ptr< Matter > & matter,
const Parameters & params,
const std::shared_ptr< Potential > & pot,
const AtomMatrix & initialDirection,
quill::Logger * log = nullptr )
inlinenodiscard

Run Lanczos, Davidson, or LOR.

Classical returns nullopt (stock rotation loop).

Definition at line 70 of file DimerRotationDispatch.h.

73 {
74 if (!usesAlternativeRotation(backend)) {
75 return std::nullopt;
76 }
77
78 const std::string_view backendName = magic_enum::enum_name(backend);
79
80 if (log) {
81 QUILL_LOG_INFO(log,
82 "[DimerRot] rotation_backend={} (skipping classical "
83 "constrained rotation loop)",
84 backendName);
85 }
86
88 switch (backend) {
90 result = detail::runRotationSolver<LORRotation>(matter, params, pot,
91 initialDirection);
92 break;
94 result = detail::runRotationSolver<Lanczos>(matter, params, pot,
95 initialDirection);
96 break;
98 result = detail::runRotationSolver<Davidson>(matter, params, pot,
99 initialDirection);
100 break;
102 return std::nullopt;
103 }
104
105 if (log) {
106 QUILL_LOG_INFO(log,
107 "[DimerRot] alternative rotation done backend={} "
108 "eigenvalue={:.6f} force_calls={}",
109 backendName, result.eigenvalue, result.forceCalls);
110 }
111 return result;
112}
DimerRotationResult runRotationSolver(const std::shared_ptr< Matter > &matter, const Parameters &params, const std::shared_ptr< Potential > &pot, const AtomMatrix &initialDirection)
constexpr bool usesAlternativeRotation(DimerRotationBackend backend) noexcept
Result of a non-classical dimer rotation backend (mode estimate only).

◆ serveFromConfig()

void eonc::serveFromConfig ( const Parameters & params)

Start serve mode from config-file parameters.

Reads serve_options from params and dispatches to the appropriate mode:

  • If endpoints is set, uses multi-model serve (serveMultiple).
  • If gateway_port > 0, uses gateway mode (serveGateway).
  • Otherwise, uses replicated mode (serveReplicated).
Parameters
paramsThe eOn parameters with serve_options populated.

Definition at line 203 of file ServeMode.cpp.

203 {
204 const auto &opts = params.serve_options();
205
206 // Multi-model endpoints take priority
207 if (!opts.endpoints.empty()) {
208 auto endpoints = parseServeSpec(opts.endpoints);
209 if (endpoints.empty()) {
210 EONC_LOG_ERROR("No valid endpoints in spec: {}", opts.endpoints);
211 return;
212 }
213 serveMultiple(endpoints, params);
214 return;
215 }
216
217 // Gateway mode
218 if (opts.gateway_port > 0) {
219 size_t pool = (opts.replicas > 0) ? opts.replicas : 1;
220 serveGateway(params, opts.host, opts.gateway_port, pool);
221 return;
222 }
223
224 // Replicated mode (default)
225 serveReplicated(params, opts.host, opts.port, opts.replicas);
226}
const serve_options_t & serve_options() const

◆ serveGateway()

void eonc::serveGateway ( const Parameters & params,
const std::string & host,
uint16_t port,
size_t pool_size )

Start a gateway server backed by a pool of potential instances.

Creates pool_size instances of the configured potential and serves them behind a single gateway port. Incoming requests are dispatched round-robin across the pool. This gives clients a single endpoint while spreading load.

Parameters
paramsThe eOn parameters (potential_options.potential must be set).
hostThe hostname to listen on.
portThe gateway port.
pool_sizeNumber of potential instances in the pool.

Definition at line 170 of file ServeMode.cpp.

171 {
172 if (pool_size == 0) {
173 EONC_LOG_ERROR("Pool size must be >= 1");
174 return;
175 }
176
177 auto pot_type = params.potential_options().potential;
178 EONC_LOG_INFO("Creating pool of {} {} instances for gateway on {}:{}",
179 pool_size, std::string(magic_enum::enum_name(pot_type)), host,
180 port);
181
182 std::vector<ForceCallback> pool;
183 pool.reserve(pool_size);
184
185 for (size_t i = 0; i < pool_size; ++i) {
186 auto eon_pot = eonc::helpers::makePotential(params);
187 if (!eon_pot) {
188 EONC_LOG_ERROR("Failed to create potential instance {}/{}", i + 1,
189 pool_size);
190 return;
191 }
192 pool.push_back(makeForceCallback(std::move(eon_pot)));
193 }
194
195 EONC_LOG_INFO("Pool ready, starting gateway server");
196 startPooledRpcServer(std::move(pool), host, port);
197}
#define EONC_LOG_INFO(...)
Definition EonLogger.h:249
const potential_options_t & potential_options() const
void startPooledRpcServer(std::vector< ForceCallback > pool, const std::string &host, uint16_t port)
Start a blocking Cap'n Proto RPC server backed by a pool of force callbacks dispatched round-robin.

◆ serveMode()

void eonc::serveMode ( const Parameters & params,
const std::string & host,
uint16_t port )

Start a single rgpot-compatible Cap'n Proto RPC server.

Wraps eOn's Potential::force() as an rgpot PotentialBase and serves it over Cap'n Proto RPC. Blocks until the server is killed.

Parameters
paramsThe eOn parameters (potential_options.potential must be set).
hostThe hostname to listen on (e.g., "localhost" or "*").
portThe TCP port to listen on.

Definition at line 58 of file ServeMode.cpp.

59 {
60 auto pot_type = params.potential_options().potential;
61 EONC_LOG_INFO("Creating potential: {}",
62 std::string(magic_enum::enum_name(pot_type)));
63
64 auto eon_pot = eonc::helpers::makePotential(params);
65 if (!eon_pot) {
66 EONC_LOG_ERROR("Failed to create potential of type {}",
67 std::string(magic_enum::enum_name(pot_type)));
68 return;
69 }
70
71 auto callback = makeForceCallback(std::move(eon_pot));
72
73 // Blocks until killed (runs Cap'n Proto event loop)
74 startRpcServer(std::move(callback), host, port);
75}
void startRpcServer(ForceCallback callback, const std::string &host, uint16_t port)
Start a blocking Cap'n Proto RPC server using a force callback.

◆ serveMultiple()

void eonc::serveMultiple ( const std::vector< ServeEndpoint > & endpoints,
const Parameters & params )

Serve multiple potentials concurrently on different ports.

Each endpoint gets its own thread, its own potential instance, and its own Cap'n Proto event loop. All threads block until SIGINT/SIGTERM.

Parameters
endpointsList of {potential, host, port} configurations.
paramsBase eOn parameters (potential type is overridden per endpoint).

Definition at line 81 of file ServeMode.cpp.

82 {
83 if (endpoints.empty()) {
84 EONC_LOG_ERROR("No serve endpoints specified");
85 return;
86 }
87
88 // Single endpoint: run in the main thread (no extra overhead)
89 if (endpoints.size() == 1) {
90 auto params = base_params;
92 endpoints[0].potential;
93 serveMode(params, endpoints[0].host, endpoints[0].port);
94 return;
95 }
96
97 // Multiple endpoints: one thread per server
98 EONC_LOG_INFO("Starting {} concurrent RPC servers", endpoints.size());
99
100 std::vector<std::thread> threads;
101 threads.reserve(endpoints.size());
102
103 for (const auto &ep : endpoints) {
104 threads.emplace_back([&base_params, ep]() {
105 auto params = base_params;
107 auto pot_name = std::string(magic_enum::enum_name(ep.potential));
108
109 EONC_LOG_INFO("[{}:{}] Creating potential: {}", ep.host, ep.port,
110 pot_name);
111
112 auto eon_pot = eonc::helpers::makePotential(params);
113 if (!eon_pot) {
114 EONC_LOG_ERROR("[{}:{}] Failed to create potential {}", ep.host,
115 ep.port, pot_name);
116 return;
117 }
118
119 auto callback = makeForceCallback(std::move(eon_pot));
120 startRpcServer(std::move(callback), ep.host, ep.port);
121 });
122 }
123
124 // Wait for all threads (they block until killed)
125 for (auto &t : threads) {
126 if (t.joinable()) {
127 t.join();
128 }
129 }
130}

◆ serveReplicated()

void eonc::serveReplicated ( const Parameters & params,
const std::string & host,
uint16_t base_port,
size_t replicas )

Serve N replicas of the same potential across sequential ports.

Starts replicas threads, each serving the same potential type on ports base_port, base_port+1, ..., base_port+replicas-1.

Parameters
paramsThe eOn parameters (potential_options.potential must be set).
hostThe hostname to listen on.
base_portThe first port; replicas use base_port+0 .. base_port+N-1.
replicasNumber of concurrent server instances.

Definition at line 136 of file ServeMode.cpp.

137 {
138 if (replicas == 0) {
139 EONC_LOG_ERROR("Replicas must be >= 1");
140 return;
141 }
142 if (replicas == 1) {
143 serveMode(params, host, base_port);
144 return;
145 }
146
147 EONC_LOG_INFO("Starting {} replicated servers on ports {}-{}", replicas,
148 base_port, base_port + replicas - 1);
149
150 std::vector<std::thread> threads;
151 threads.reserve(replicas);
152
153 for (size_t i = 0; i < replicas; ++i) {
154 uint16_t port = static_cast<uint16_t>(base_port + i);
155 threads.emplace_back(
156 [&params, &host, port]() { serveMode(params, host, port); });
157 }
158
159 for (auto &t : threads) {
160 if (t.joinable()) {
161 t.join();
162 }
163 }
164}

◆ startPooledRpcServer()

void eonc::startPooledRpcServer ( std::vector< ForceCallback > pool,
const std::string & host,
uint16_t port )

Start a blocking Cap'n Proto RPC server backed by a pool of force callbacks dispatched round-robin.

Parameters
poolVector of force callbacks (one per pool instance).
hostThe hostname to listen on.
portThe TCP port to listen on.

Definition at line 187 of file ServeRpcServer.cpp.

188 {
189 EONC_LOG_INFO("Starting pooled RPC gateway on {}:{} with {} instances", host,
190 port, pool.size());
191
192 capnp::EzRpcServer server(kj::heap<PooledCallbackPotImpl>(std::move(pool)),
193 host, port);
194
195 auto &waitScope = server.getWaitScope();
196 EONC_LOG_INFO("Gateway ready on port {}. Ctrl+C to stop.", port);
197 kj::NEVER_DONE.wait(waitScope);
198}

◆ startRpcServer()

void eonc::startRpcServer ( ForceCallback callback,
const std::string & host,
uint16_t port )

Start a blocking Cap'n Proto RPC server using a force callback.

Defined in a separate translation unit to avoid naming collision between eOn's class Potential and the capnp-generated Potential interface.

Parameters
callbackForce evaluation function.
hostThe hostname to listen on.
portThe TCP port to listen on.

Definition at line 105 of file ServeRpcServer.cpp.

106 {
107 EONC_LOG_INFO("Starting Cap'n Proto RPC server on {}:{}", host, port);
108
109 capnp::EzRpcServer server(kj::heap<CallbackPotImpl>(std::move(callback)),
110 host, port);
111
112 auto &waitScope = server.getWaitScope();
113 EONC_LOG_INFO("Server ready on port {}. Ctrl+C to stop.", port);
114 kj::NEVER_DONE.wait(waitScope);
115}

◆ trivialModeCountIsPhysical()

bool eonc::trivialModeCountIsPhysical ( long removed,
long fixedAtoms )

Whether removed zero-frequency modes are what the structure's symmetries give: 6 for a free cluster (3 translations and 3 rotations), 5 for a linear one, 3 for a periodic cell, where rotations are no symmetry of the lattice, and none once any atom is fixed.

Definition at line 798 of file Hessian.cpp.

798 {
799 if (fixedAtoms > 0) {
800 return removed == 0;
801 }
802 return removed == 3 || removed == 5 || removed == 6;
803}

◆ unbundle()

std::vector< std::string > eonc::unbundle ( int number)

Definition at line 71 of file Bundling.cpp.

71 {
72 std::vector<std::string> filenames;
73
74 for (const auto &entry : fs::directory_iterator(".")) {
75 std::string originalFilename = entry.path().filename().string();
76
77 if (originalFilename.empty() || originalFilename[0] == '.') {
78 continue;
79 }
80
81 if (std::ranges::count(originalFilename, '_') < 1) {
82 continue;
83 }
84
85 // Find the last underscore
86 auto upos = originalFilename.rfind('_');
87 if (upos == std::string::npos) {
88 continue;
89 }
90
91 // Find the last period
92 auto dpos = originalFilename.rfind('.');
93 if (dpos == std::string::npos || dpos <= upos) {
94 continue;
95 }
96
97 // bundle() writes results_3.con.gz. The span from the last underscore
98 // to the last dot is "3.con", so the index is only the digit run.
99 const size_t numBegin = upos + 1;
100 size_t numEnd = numBegin;
101 while (numEnd < originalFilename.size() &&
102 std::isdigit(static_cast<unsigned char>(originalFilename[numEnd]))) {
103 ++numEnd;
104 }
105 if (numEnd == numBegin || numEnd >= originalFilename.size() ||
106 originalFilename[numEnd] != '.') {
107 continue;
108 }
109 int bundleNumber = 0;
110 const auto parsed =
111 std::from_chars(originalFilename.data() + numBegin,
112 originalFilename.data() + numEnd, bundleNumber);
113 if (parsed.ec != std::errc{} ||
114 parsed.ptr != originalFilename.data() + numEnd) {
115 continue;
116 }
117 if (bundleNumber != number) {
118 continue;
119 }
120
121 std::string baseName = originalFilename.substr(0, upos);
122 // Drop the "_<n>" token and keep everything after it, so a compound
123 // extension (".con.gz", ".con.zst") survives whichever side of the
124 // underscore it sits on.
125 size_t extStart =
126 originalFilename.find_first_not_of("0123456789", upos + 1);
127 if (extStart == std::string::npos) {
128 extStart = originalFilename.size();
129 }
130 std::string newFilename = baseName + originalFilename.substr(extStart);
131
132 try {
133 fs::copy_file(originalFilename, newFilename,
134 fs::copy_options::overwrite_existing);
135 filenames.push_back(newFilename);
136 } catch (const fs::filesystem_error &e) {
137 EONC_LOG_ERROR("unbundle: problem copying {} to {}: {}", originalFilename,
138 newFilename, e.what());
139 }
140 }
141
142 return filenames;
143}

◆ unpackMobileRows()

void eonc::unpackMobileRows ( const VectorXd & packed,
const VectorXi & mobile,
AtomMatrix & full )

Write a 3*n_mobile vector into full AtomMatrix rows (other rows unchanged).

Definition at line 135 of file MobileAtoms.cpp.

136 {
137 for (Eigen::Index a = 0; a < mobile.size(); ++a) {
138 full.row(mobile(a)) = packed.segment<3>(3 * a);
139 }
140}

◆ usesAlternativeRotation()

bool eonc::usesAlternativeRotation ( DimerRotationBackend backend)
inlinenodiscardconstexprnoexcept

Definition at line 41 of file DimerRotationDispatch.h.

41 {
42 return backend != DimerRotationBackend::Classical;
43}

◆ write_fault_rip()

void eonc::write_fault_rip ( void * scp)
static

Definition at line 272 of file fpe_handler.cpp.

272 {
273#if defined(__linux__) && defined(__x86_64__)
274 auto *ctx_log = static_cast<ucontext_t *>(scp);
275 unsigned long rip =
276 static_cast<unsigned long>(ctx_log->uc_mcontext.gregs[REG_RIP]);
277 char hex[] = "FPE rip=0x0000000000000000\n";
278 for (int i = 0; i < 16; ++i) {
279 unsigned nibble = static_cast<unsigned>((rip >> (4 * (15 - i))) & 0xFu);
280 hex[10 + i] =
281 static_cast<char>(nibble < 10 ? '0' + nibble : 'a' + (nibble - 10));
282 }
283 write(STDERR_FILENO, hex, sizeof(hex) - 1);
284#else
285 (void)scp;
286#endif
287}

◆ writeNormalModes()

bool eonc::writeNormalModes ( Matter & matter,
const VectorXi & atoms,
const VectorXd & eigenvalues,
const MatrixXd & modes,
const std::string & path )

Writes one frame of matter per mode to path, the mode as the displacements section and mode_eigenvalue (eV / (Angstrom^2 amu)), hbar_omega (eV, negative for an imaginary mode) and wavenumber (cm^-1, same sign) as frame metadata.

Definition at line 775 of file Hessian.cpp.

777 {
778 if (modes.cols() != eigenvalues.size() || modes.rows() != 3 * atoms.size()) {
779 return false;
780 }
781 for (long k = 0; k < eigenvalues.size(); ++k) {
782 const double lambda = eigenvalues(k);
783 const double hw =
784 std::copysign(tunneling::kHbar * std::sqrt(std::abs(lambda)), lambda);
785 io::ConFrameMetadata meta;
786 meta.frame_index = static_cast<uint64_t>(k);
787 meta.scalars = {{"mode_eigenvalue", lambda},
788 {"hbar_omega", hw},
789 {"wavenumber", hw * kEvToWavenumber}};
790 meta.displacements = cartesianMode(matter, atoms, modes.col(k));
791 if (!io::io_ok(matter.matter2con(path, k > 0, &meta))) {
792 return false;
793 }
794 }
795 return true;
796}
io::IoStatus matter2con(std::string filename, bool append=false, const io::ConFrameMetadata *metadata=nullptr)
Definition Matter.h:268
constexpr double kHbar
hbar in eV^0.5 amu^0.5 Angstrom, correctly rounded from the exact SI values (h = 6....
Definition Tunneling.h:37
constexpr double kEvToWavenumber
1 eV in cm^-1, e / (h c) from the exact SI values.
Definition Hessian.h:31
std::vector< double > cartesianMode(const Matter &matter, const VectorXi &atoms, const Eigen::Ref< const VectorXd > &mode)
Cartesian displacement of every atom along one mass-weighted mode over the mobile degrees of freedom ...
Definition Hessian.cpp:748

◆ x86_div_regs()

X86DivRegs eonc::x86_div_regs ( void * scp)
static

Definition at line 215 of file fpe_handler.cpp.

215 {
216 X86DivRegs regs{nullptr, nullptr, nullptr};
217 if (scp == nullptr) {
218 return regs;
219 }
220 auto *ctx = static_cast<ucontext_t *>(scp);
221#if defined(__linux__) && defined(__x86_64__)
222 regs.ip = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_RIP]);
223 regs.ax = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_RAX]);
224 regs.dx = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_RDX]);
225#elif defined(__linux__) && defined(__i386__)
226 regs.ip = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_EIP]);
227 regs.ax = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_EAX]);
228 regs.dx = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext.gregs[REG_EDX]);
229#elif defined(__APPLE__) && defined(__x86_64__)
230 if (ctx->uc_mcontext != nullptr) {
231 regs.ip = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__rip);
232 regs.ax = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__rax);
233 regs.dx = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__rdx);
234 }
235#elif defined(__APPLE__) && defined(__i386__)
236 if (ctx->uc_mcontext != nullptr) {
237 regs.ip = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__eip);
238 regs.ax = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__eax);
239 regs.dx = reinterpret_cast<uintptr_t *>(&ctx->uc_mcontext->__ss.__edx);
240 }
241#else
242 (void)ctx;
243#endif
244 return regs;
245}

Variable Documentation

◆ AM

double eonc::AM = 1.0 / IM
constexpr

Definition at line 18 of file RandomNumbers.h.

◆ EPS

double eonc::EPS = 1.2e-7
constexpr

Definition at line 21 of file RandomNumbers.h.

◆ IA1

long eonc::IA1 = 40014
constexpr

Definition at line 26 of file RandomNumbers.h.

◆ IA2

long eonc::IA2 = 40692
constexpr

Definition at line 27 of file RandomNumbers.h.

◆ IM

double eonc::IM = 2147483647.0
constexpr

Definition at line 17 of file RandomNumbers.h.

◆ IM1

long eonc::IM1 = 2147483563
constexpr

Definition at line 23 of file RandomNumbers.h.

◆ IM2

long eonc::IM2 = 2147483399
constexpr

Definition at line 24 of file RandomNumbers.h.

◆ IMM1

long eonc::IMM1 = IM1 - 1
constexpr

Definition at line 25 of file RandomNumbers.h.

◆ IQ1

long eonc::IQ1 = 53668
constexpr

Definition at line 28 of file RandomNumbers.h.

◆ IQ2

long eonc::IQ2 = 52774
constexpr

Definition at line 29 of file RandomNumbers.h.

◆ IR1

long eonc::IR1 = 12211
constexpr

Definition at line 30 of file RandomNumbers.h.

◆ IR2

long eonc::IR2 = 3791
constexpr

Definition at line 31 of file RandomNumbers.h.

◆ kEvToWavenumber

double eonc::kEvToWavenumber = 8065.543937349212
inlineconstexpr

1 eV in cm^-1, e / (h c) from the exact SI values.

Definition at line 31 of file Hessian.h.

◆ kWindowsMxcsrExceptionMasks

std::uint32_t eonc::kWindowsMxcsrExceptionMasks = 0x1F80u
constexpr

Definition at line 23 of file fpe_handler.h.

◆ MXCSR_MASK_IM

unsigned eonc::MXCSR_MASK_IM = 1u << 7
staticconstexpr

Definition at line 106 of file fpe_handler.cpp.

◆ MXCSR_MASK_OM

unsigned eonc::MXCSR_MASK_OM = 1u << 10
staticconstexpr

Definition at line 108 of file fpe_handler.cpp.

◆ MXCSR_MASK_ZM

unsigned eonc::MXCSR_MASK_ZM = 1u << 9
staticconstexpr

Definition at line 107 of file fpe_handler.cpp.

◆ NDIV

int eonc::NDIV = 1 + (IM / NTAB)
constexpr

Definition at line 20 of file RandomNumbers.h.

◆ NTAB

int eonc::NTAB = 32
constexpr

Definition at line 19 of file RandomNumbers.h.

◆ RNMX

double eonc::RNMX = 1.0 - EPS
constexpr

Definition at line 22 of file RandomNumbers.h.