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  params_ssot
namespace  pbc
namespace  pot
namespace  Prefactor
namespace  rng
namespace  safemath

Classes

class  ARTnResource
class  ARTnSaddleSearch
 Saddle search method using the Activation-Relaxation Technique nouveau. More...
class  AtomicGPDimer
class  BasinHoppingJob
class  BasinHoppingSaddleSearch
class  BiasedGradientSquaredDescent
class  BondBoost
 Functionality relying on the conjugate gradients algorithm. More...
class  CollectiveIDPPObjectiveFunction
class  ConjugateGradients
 Decleration of the Conjugate Gradients optimizer. More...
class  Davidson
 Davidson method for the lowest Hessian curvature mode (min-mode). More...
class  Dimer
 Classic dimer method to find the lowest curvature mode. More...
class  DimerModeLostException
class  DimerModeRestoredException
struct  DimerRotationResult
 Result of a non-classical dimer rotation backend (mode estimate only). More...
class  Dynamics
struct  DynamicsConfig
 Configuration extracted from Parameters for Dynamics. More...
class  DynamicsJob
class  DynamicsSaddleSearch
class  FiniteDifferenceJob
class  FIRE
class  ForceCallTimer
 RAII wrapper for tracking force calls over a scope. More...
class  FPEHandler
class  GleThermostat
 Colored-noise (generalized Langevin) thermostat. More...
class  GlobalOptimization
class  GlobalOptimizationJob
class  GPSurrogateJob
class  Hessian
class  HessianJob
class  Hyperdynamics
class  IDPPObjectiveFunction
class  ImprovedDimer
class  IRACompare
 C++ wrapper for the IRA (Iterative Rotations and Assignments) library. More...
class  IRAResource
class  Job
 Declaration of job class. More...
class  LammpsLoader
class  Lanczos
class  LBFGS
class  LORRotation
class  LowestEigenmode
 Base for eigenmode solvers. More...
class  Matter
class  MetatomicDynPot
class  MetatomicLoader
class  MinimizationJob
class  MinModeSaddleSearch
class  MonteCarlo
class  MonteCarloJob
class  NEBObjectiveFunction
class  NudgedElasticBand
class  NudgedElasticBandJob
class  ObjectiveFunction
class  OHTSTJob
class  Optimizer
struct  OptimizerConfig
 Declaration of the optimizer class. More...
class  ParallelReplicaJob
class  Parameters
class  PluginLoader
class  PointJob
class  Potential
class  PotRegistry
class  PrefactorJob
class  ProcessSearchJob
 Declaration of the Process Search job. More...
class  Quickmin
class  ReplicaDynamicsJob
 Base class for replica dynamics jobs (TAD, SafeHyper). More...
class  ReplicaExchangeJob
class  SaddleSearchJob
 Declaration of the Saddle Search job. More...
class  SaddleSearchMethod
class  SafeHyperJob
struct  ServeEndpoint
 Configuration for a single serve endpoint. More...
class  SteepestDescent
class  StructureComparisonJob
class  SurrogatePotential
class  TADJob
class  TestJob
class  VesinNeighbors
 RAII wrapper around vesin_neighbors for Matter-style boxes (double[9] row-major 3×3 cell, same layout as Matter::cell). More...
class  ZBLRepulsiveIDPPObjective

Typedefs

using EigenmodeStrategy = std::variant<Dimer, ImprovedDimer, Lanczos, Davidson>
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
}
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
}
enum class  OptType {
  Unknown = -1 , None = 0 , QM , CG ,
  LBFGS , FIRE , SD
}
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  PbcConvention { Legacy = 0 , MinimumImage = 1 }

Functions

int getBundleSize ()
int strchrcount (const char *haystack, char needle)
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)
static void fpe_signal_handler (int sig, siginfo_t *sip, void *scp)
void enableFPE ()
void disableFPE ()
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).
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< ServeEndpointparseServeSpec (const std::string &spec)
 Parse a serve configuration string into endpoints.
constexpr bool usesAlternativeRotation (DimerRotationBackend backend) noexcept
std::optional< DimerRotationResultrunAlternativeRotation (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.
std::shared_ptr< EigenmodeStrategybuildEigenmodeStrategy (std::shared_ptr< Matter > matter, const Parameters &params, std::shared_ptr< Potential > pot)
 Build the eigenmode solver from parameters.
void eigenmodeCompute (EigenmodeStrategy &s, std::shared_ptr< Matter > matter, AtomMatrix direction)
 Dispatch compute() to the active variant.
double eigenmodeGetEigenvalue (EigenmodeStrategy &s)
 Dispatch getEigenvalue() to the active variant.
AtomMatrix eigenmodeGetEigenvector (EigenmodeStrategy &s)
 Dispatch getEigenvector() to the active variant.
ImprovedDimerasImprovedDimer (EigenmodeStrategy &s)
 Access ImprovedDimer-specific features.
long eigenmodeTotalForceCalls (EigenmodeStrategy &s)
 Read stats from any variant (all inherit LowestEigenmode stats fields).
double eigenmodeStatsTorque (EigenmodeStrategy &s)
double eigenmodeStatsAngle (EigenmodeStrategy &s)
long eigenmodeStatsRotations (EigenmodeStrategy &s)
long eigenmodeTotalIterations (EigenmodeStrategy &s)
ARTnResourceget_artn_resource ()
 Global access to thread-safe ARTn resource.
IRAResourceget_ira_resource ()
 Global access to thread-safe IRA resource.
void ensure_interpreter ()
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.

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 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

Definition at line 32 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.

Enumeration Type Documentation

◆ DimerRotationBackend

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

Definition at line 116 of file BaseStructures.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 

Definition at line 73 of file BaseStructures.h.

73 {
74 // Only add to the end of this!!!
75 Unknown = 0,
79 Point,
82 TAD,
85 Hessian,
93 Test,
95 OH_TST
96};

◆ NEBInit

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

Definition at line 109 of file BaseStructures.h.

◆ OptType

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

Definition at line 98 of file BaseStructures.h.

98 {
99 // Only add to the end of this!!!
100 Unknown = -1, // an error case
101 None = 0,
102 QM,
103 CG,
104 LBFGS,
105 FIRE,
106 SD
107};

◆ PbcConvention

enum class eonc::PbcConvention
strong
Enumerator
Legacy 
MinimumImage 

Definition at line 34 of file Matter.h.

34 {
35 Legacy = 0,
36 MinimumImage = 1,
37};

◆ 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 

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};

◆ RunStatus

enum class eonc::RunStatus
strong
Enumerator
GOOD 
FAIL_MAX_ITERATIONS 
FAIL_POTENTIAL_FAILED 

Definition at line 111 of file BaseStructures.h.

Function Documentation

◆ asImprovedDimer()

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

Access ImprovedDimer-specific features.

Returns nullptr if not ImprovedDimer.

Definition at line 93 of file EigenmodeStrategy.h.

93 {
94 return std::get_if<ImprovedDimer>(&s);
95}

◆ atomListMeansAll()

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

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

Definition at line 21 of file MobileAtoms.cpp.

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

◆ buildEigenmodeStrategy()

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

Build the eigenmode solver from parameters.

min_mode_method: dimer (rotation CG) | lanczos | davidson | gprdimer

Definition at line 38 of file EigenmodeStrategy.h.

39 {
42 if (params.dimer_options.improved) {
43 return std::make_shared<EigenmodeStrategy>(
44 ImprovedDimer(matter, params, pot));
45 }
46 return std::make_shared<EigenmodeStrategy>(Dimer(matter, params, pot));
47 } else if (params.saddle_search_options.minmode_method ==
49 return std::make_shared<EigenmodeStrategy>(Lanczos(matter, params, pot));
50 } else if (params.saddle_search_options.minmode_method ==
52 return std::make_shared<EigenmodeStrategy>(Davidson(matter, params, pot));
53 }
54#ifdef WITH_GPRD
55 else if (params.saddle_search_options.minmode_method ==
57 // AtomicGPDimer embeds atmd::AtomicDimer (unique_ptr + user dtor → not
58 // movable). Construct the alternative in place; do not pass a temporary.
59 return std::make_shared<EigenmodeStrategy>(
60 std::in_place_type<AtomicGPDimer>, matter, params, pot);
61 }
62#else
63 else if (params.saddle_search_options.minmode_method ==
65 throw std::runtime_error(
66 "min_mode_method=gprdimer requires -Dwith_gprd=true (WITH_GPRD)");
67 }
68#endif
69 // Default to improved dimer
70 return std::make_shared<EigenmodeStrategy>(
71 ImprovedDimer(matter, params, pot));
72}
Classic dimer method to find the lowest curvature mode.
Definition Dimer.h:22
static const char MINMODE_DIMER[]
static const char MINMODE_GPRDIMER[]
static const char MINMODE_DAVIDSON[]
static const char MINMODE_LANCZOS[]
struct eonc::Parameters::dimer_options_t dimer_options
struct eonc::Parameters::saddle_search_options_t saddle_search_options

◆ bundle()

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

Definition at line 175 of file Bundling.cpp.

176 {
177 for (const auto &filename : filenames) {
178 const auto [baseName, ext] = splitBundleExtension(filename);
179 const std::string newFilename =
180 baseName + "_" + std::to_string(number) + ext;
181
182 try {
183 fs::rename(filename, newFilename);
184 bundledFilenames->push_back(newFilename);
185 } catch (const fs::filesystem_error &e) {
186 EONC_LOG_ERROR("bundle: cannot rename {} to {}: {}", filename,
187 newFilename, e.what());
188 }
189 }
190}
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:262

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

◆ config_from_params()

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

Definition at line 15 of file MetatomicDynPot.cpp.

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

◆ deleteUnbundledFiles()

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

Definition at line 140 of file Bundling.cpp.

140 {
141 for (const auto &filename : unbundledFilenames) {
142 std::error_code ec;
143 fs::remove(filename, ec);
144 if (ec) {
145 EONC_LOG_ERROR("deleteUnbundledFiles: cannot remove {}: {}", filename,
146 ec.message());
147 }
148 }
149}

◆ disableFPE()

void eonc::disableFPE ( )

Definition at line 229 of file fpe_handler.cpp.

229 {
230#ifdef _WIN32
231 // Mask all floating-point exceptions (restore default behavior)
232 unsigned int control;
233 _controlfp_s(&control, _MCW_EM, _MCW_EM);
234#elif defined(__unix__)
235 fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
236#elif defined(__APPLE__)
237 fenv_t env;
238 fegetenv(&env);
239#if defined(__aarch64__)
240 env.__fpsr |= (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
241#endif
242 fesetenv(&env);
243#endif
244}

◆ eigenmodeCompute()

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

Dispatch compute() to the active variant.

Definition at line 75 of file EigenmodeStrategy.h.

77 {
78 std::visit([&](auto &impl) { impl.compute(matter, direction); }, s);
79}

◆ eigenmodeGetEigenvalue()

double eonc::eigenmodeGetEigenvalue ( EigenmodeStrategy & s)
inline

Dispatch getEigenvalue() to the active variant.

Definition at line 82 of file EigenmodeStrategy.h.

82 {
83 return std::visit([](auto &impl) { return impl.getEigenvalue(); }, s);
84}

◆ eigenmodeGetEigenvector()

AtomMatrix eonc::eigenmodeGetEigenvector ( EigenmodeStrategy & s)
inline

Dispatch getEigenvector() to the active variant.

Definition at line 87 of file EigenmodeStrategy.h.

87 {
88 return std::visit([](auto &impl) { return impl.getEigenvector(); }, s);
89}

◆ eigenmodeStatsAngle()

double eonc::eigenmodeStatsAngle ( EigenmodeStrategy & s)
inline

Definition at line 106 of file EigenmodeStrategy.h.

106 {
107 return std::visit([](auto &impl) { return impl.statsAngle; }, s);
108}

◆ eigenmodeStatsRotations()

long eonc::eigenmodeStatsRotations ( EigenmodeStrategy & s)
inline

Definition at line 110 of file EigenmodeStrategy.h.

110 {
111 return std::visit([](auto &impl) { return impl.statsRotations; }, s);
112}

◆ eigenmodeStatsTorque()

double eonc::eigenmodeStatsTorque ( EigenmodeStrategy & s)
inline

Definition at line 102 of file EigenmodeStrategy.h.

102 {
103 return std::visit([](auto &impl) { return impl.statsTorque; }, s);
104}

◆ eigenmodeTotalForceCalls()

long eonc::eigenmodeTotalForceCalls ( EigenmodeStrategy & s)
inline

Read stats from any variant (all inherit LowestEigenmode stats fields).

Definition at line 98 of file EigenmodeStrategy.h.

98 {
99 return std::visit([](auto &impl) { return impl.totalForceCalls; }, s);
100}

◆ eigenmodeTotalIterations()

long eonc::eigenmodeTotalIterations ( EigenmodeStrategy & s)
inline

Definition at line 114 of file EigenmodeStrategy.h.

114 {
115 return std::visit([](auto &impl) { return impl.totalIterations; }, s);
116}

◆ enableFPE()

void eonc::enableFPE ( )

Definition at line 193 of file fpe_handler.cpp.

193 {
194#ifdef _WIN32
195 // Register Windows SEH handler for FPE reporting
196 SetUnhandledExceptionFilter(windowsFPEHandler);
197 // Enable floating-point exceptions on Windows
198 _controlfp_s(nullptr, 0, _MCW_EM);
199 _controlfp_s(nullptr, ~(_EM_ZERODIVIDE | _EM_INVALID | _EM_OVERFLOW),
200 _MCW_EM);
201#elif defined(__unix__)
202 // Enable floating-point exceptions on Unix
203 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
204#elif defined(__APPLE__) && defined(__aarch64__)
205 // Enable floating-point exceptions on ARM macOS
206 fenv_t env;
207 fegetenv(&env);
208 env.__fpsr &= ~(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
209 fesetenv(&env);
210#elif defined(__APPLE__) && defined(__x86_64__)
211 // Enable floating-point exceptions on Intel macOS
212 _MM_SET_EXCEPTION_MASK(
213 _MM_MASK_MASK &
214 ~(_MM_MASK_INVALID | _MM_MASK_DIV_ZERO | _MM_MASK_OVERFLOW));
215#else
216 fprintf(stderr, "FPE trapping not supported on this platform.\n");
217#endif
218
219#ifndef _WIN32
220 // Register POSIX signal handler
221 struct sigaction act;
222 act.sa_sigaction = fpe_signal_handler;
223 sigemptyset(&act.sa_mask);
224 act.sa_flags = SA_SIGINFO;
225 sigaction(SIGFPE, &act, nullptr);
226#endif
227}
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}

◆ fpe_signal_handler()

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

Definition at line 94 of file fpe_handler.cpp.

94 {
95 // Async-signal-safe only: write(2) and sig_atomic_t. No iostream, malloc,
96 // backtrace, or fenv helpers (fedisableexcept / feclearexcept are not
97 // async-signal-safe). All continue-state is written into the saved ucontext
98 // so it is restored on sigreturn.
99 //
100 // x86 cannot "continue" past a trapped FP op by clearing sticky flags:
101 // flags are bits 0-5 of MXCSR/swd, but the exception MASK bits live at
102 // MXCSR 7-12. Clearing 0x3F leaves trapping armed, so the faulting
103 // instruction re-executes on the same operands and re-raises forever
104 // (report, sigreturn, refault) -- multi-GB identical stderr lines and a
105 // client stuck at ~100% CPU. Mask the class in the restored MXCSR so
106 // re-execution produces the IEEE default (Inf/NaN) and proceeds.
107 static volatile sig_atomic_t reported_div = 0;
108 static volatile sig_atomic_t reported_inv = 0;
109 static volatile sig_atomic_t reported_ovf = 0;
110 static volatile sig_atomic_t reported_unk = 0;
111
112 static constexpr char prefix[] = "FPE (continuing, masking further): ";
113 static constexpr char msg_div[] = "division by zero\n";
114 static constexpr char msg_inv[] = "invalid operation\n";
115 static constexpr char msg_ovf[] = "overflow\n";
116 static constexpr char msg_unk[] = "unknown\n";
117
118 // Default: mask all three classes we enable at startup, so an unknown
119 // si_code cannot leave trapping armed and re-storm.
120 unsigned mxcsr_mask_bits = MXCSR_MASK_IM | MXCSR_MASK_ZM | MXCSR_MASK_OM;
121 volatile sig_atomic_t *reported = &reported_unk;
122 const char *msg = msg_unk;
123 size_t msg_len = sizeof(msg_unk) - 1;
124
125 switch (sip->si_code) {
126 case FPE_FLTDIV:
127 reported = &reported_div;
128 msg = msg_div;
129 msg_len = sizeof(msg_div) - 1;
130 mxcsr_mask_bits = MXCSR_MASK_ZM;
131 break;
132 case FPE_FLTINV:
133 reported = &reported_inv;
134 msg = msg_inv;
135 msg_len = sizeof(msg_inv) - 1;
136 mxcsr_mask_bits = MXCSR_MASK_IM;
137 break;
138 case FPE_FLTOVF:
139 reported = &reported_ovf;
140 msg = msg_ovf;
141 msg_len = sizeof(msg_ovf) - 1;
142 mxcsr_mask_bits = MXCSR_MASK_OM;
143 break;
144 default:
145 break;
146 }
147
148 if (*reported == 0) {
149 *reported = 1;
150 write(STDERR_FILENO, prefix, sizeof(prefix) - 1);
151 write(STDERR_FILENO, msg, msg_len);
152#if defined(__linux__) && defined(__x86_64__)
153 // First-fault RIP for post-mortem addr2line / offline diagnosis.
154 ucontext_t *ctx_log = static_cast<ucontext_t *>(scp);
155 unsigned long rip =
156 static_cast<unsigned long>(ctx_log->uc_mcontext.gregs[REG_RIP]);
157 char hex[] = "FPE rip=0x0000000000000000\n";
158 for (int i = 0; i < 16; ++i) {
159 unsigned nibble = static_cast<unsigned>((rip >> (4 * (15 - i))) & 0xFu);
160 hex[10 + i] =
161 static_cast<char>(nibble < 10 ? '0' + nibble : 'a' + (nibble - 10));
162 }
163 write(STDERR_FILENO, hex, sizeof(hex) - 1);
164#endif
165 }
166
167#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__))
168 ucontext_t *ctx = static_cast<ucontext_t *>(scp);
169 if (ctx->uc_mcontext.fpregs) {
170 // Clear sticky exception FLAGS (bits 0-5) and arm the MASK bit(s) for
171 // the fault class (bits 7-12). Mask sticks after sigreturn because the
172 // restored MXCSR becomes the live CPU state.
173 ctx->uc_mcontext.fpregs->swd &= ~0x3Fu;
174 ctx->uc_mcontext.fpregs->mxcsr &= ~0x3Fu;
175 ctx->uc_mcontext.fpregs->mxcsr |= mxcsr_mask_bits;
176 // x87 control word: mask bits are 0-5 of cwd (IM, DM, ZM, OM, UM, PM).
177 // Set the matching masks so a legacy x87 fault cannot re-storm either.
178 if (mxcsr_mask_bits & MXCSR_MASK_ZM) {
179 ctx->uc_mcontext.fpregs->cwd |= (1u << 2); // x87 ZM
180 }
181 if (mxcsr_mask_bits & MXCSR_MASK_IM) {
182 ctx->uc_mcontext.fpregs->cwd |= (1u << 0); // x87 IM
183 }
184 if (mxcsr_mask_bits & MXCSR_MASK_OM) {
185 ctx->uc_mcontext.fpregs->cwd |= (1u << 3); // x87 OM
186 }
187 }
188#endif
189 (void)sig;
190}
static constexpr unsigned MXCSR_MASK_ZM
static constexpr unsigned MXCSR_MASK_OM
static constexpr unsigned MXCSR_MASK_IM

◆ freeAtomIndices()

VectorXi eonc::freeAtomIndices ( const Matter * matter)

Free (unfixed) atom indices in ascending order.

Definition at line 48 of file MobileAtoms.cpp.

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

◆ 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 120 of file ARTnResource.h.

120{ return ARTnResource::instance(); }
static ARTnResource & instance()
Singleton accessor (Meyer's pattern).

◆ get_ira_resource()

IRAResource & eonc::get_ira_resource ( )
inline

Global access to thread-safe IRA resource.

Definition at line 100 of file IRAResource.h.

100{ return IRAResource::instance(); }
static IRAResource & instance()
Singleton accessor (Meyer's pattern).

◆ getBundleSize()

int eonc::getBundleSize ( )

Definition at line 28 of file Bundling.cpp.

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

◆ 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 132 of file MobileAtoms.cpp.

132 {
133 const AtomMatrix forces = matter->getForces();
134 return packMobileRows(forces, mobile);
135}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
const AtomMatrix & getForces() const
Definition Matter.cpp:324
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 117 of file MobileAtoms.cpp.

117 {
118 VectorXd packed(3 * mobile.size());
119 for (Eigen::Index a = 0; a < mobile.size(); ++a) {
120 packed.segment<3>(3 * a) = full.row(mobile(a));
121 }
122 return packed;
123}

◆ 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 229 of file ServeMode.cpp.

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

◆ 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 64 of file MobileAtoms.cpp.

64 {
65 if (atomListMeansAll(atomList)) {
66 return freeAtomIndices(matter);
67 }
68 const long n = matter->numberOfAtoms();
69 std::vector<int> mobile;
70 std::unordered_set<int> seen;
71 std::string token;
72 for (size_t p = 0; p <= atomList.size(); ++p) {
73 const char c = (p < atomList.size()) ? atomList[p] : ',';
74 if (c == ',' || c == ' ' || c == '\t' || p == atomList.size()) {
75 if (!token.empty()) {
76 try {
77 const long idx = std::stol(token);
78 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
79 seen.insert(static_cast<int>(idx)).second) {
80 mobile.push_back(static_cast<int>(idx));
81 }
82 } catch (const std::exception &) {
83 // skip non-integer tokens
84 }
85 token.clear();
86 }
87 } else {
88 token.push_back(c);
89 }
90 }
91 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
92 for (Eigen::Index k = 0; k < out.size(); ++k) {
93 out(k) = mobile[static_cast<size_t>(k)];
94 }
95 return out;
96}
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 98 of file MobileAtoms.cpp.

98 {
99 const long n = matter->numberOfAtoms();
100 std::vector<int> mobile;
101 std::unordered_set<int> seen;
102 mobile.reserve(static_cast<size_t>(candidates.size()));
103 for (Eigen::Index k = 0; k < candidates.size(); ++k) {
104 const long idx = candidates(k);
105 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
106 seen.insert(static_cast<int>(idx)).second) {
107 mobile.push_back(static_cast<int>(idx));
108 }
109 }
110 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
111 for (Eigen::Index k = 0; k < out.size(); ++k) {
112 out(k) = mobile[static_cast<size_t>(k)];
113 }
114 return out;
115}

◆ 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 200 of file ServeMode.cpp.

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

◆ 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 167 of file ServeMode.cpp.

168 {
169 if (pool_size == 0) {
170 EONC_LOG_ERROR("Pool size must be >= 1");
171 return;
172 }
173
174 auto pot_type = params.potential_options.potential;
175 EONC_LOG_INFO("Creating pool of {} {} instances for gateway on {}:{}",
176 pool_size, std::string(magic_enum::enum_name(pot_type)), host,
177 port);
178
179 std::vector<ForceCallback> pool;
180 pool.reserve(pool_size);
181
182 for (size_t i = 0; i < pool_size; ++i) {
183 auto eon_pot = eonc::helpers::makePotential(params);
184 if (!eon_pot) {
185 EONC_LOG_ERROR("Failed to create potential instance {}/{}", i + 1,
186 pool_size);
187 return;
188 }
189 pool.push_back(makeForceCallback(std::move(eon_pot)));
190 }
191
192 EONC_LOG_INFO("Pool ready, starting gateway server");
193 startPooledRpcServer(std::move(pool), host, port);
194}
#define EONC_LOG_INFO(...)
Definition EonLogger.h:250
struct eonc::Parameters::potential_options_t potential_options
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 56 of file ServeMode.cpp.

57 {
58 auto pot_type = params.potential_options.potential;
59 EONC_LOG_INFO("Creating potential: {}",
60 std::string(magic_enum::enum_name(pot_type)));
61
62 auto eon_pot = eonc::helpers::makePotential(params);
63 if (!eon_pot) {
64 EONC_LOG_ERROR("Failed to create potential of type {}",
65 std::string(magic_enum::enum_name(pot_type)));
66 return;
67 }
68
69 auto callback = makeForceCallback(std::move(eon_pot));
70
71 // Blocks until killed (runs Cap'n Proto event loop)
72 startRpcServer(std::move(callback), host, port);
73}
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 79 of file ServeMode.cpp.

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

◆ 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 133 of file ServeMode.cpp.

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

◆ 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 185 of file ServeRpcServer.cpp.

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

◆ 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 103 of file ServeRpcServer.cpp.

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

◆ strchrcount()

int eonc::strchrcount ( const char * haystack,
char needle )

Definition at line 70 of file Bundling.cpp.

70 {
71 int count = 0;
72 for (const char *ch = haystack; *ch != '\0'; ch++) {
73 if (*ch == needle) {
74 count++;
75 }
76 }
77 return count;
78}

◆ unbundle()

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

Definition at line 80 of file Bundling.cpp.

80 {
81 std::vector<std::string> filenames;
82
83 for (const auto &entry : fs::directory_iterator(".")) {
84 std::string originalFilename = entry.path().filename().string();
85
86 if (originalFilename[0] == '.') {
87 continue;
88 }
89
90 int numUnderscores = strchrcount(originalFilename.c_str(), '_');
91 if (numUnderscores < 1) {
92 continue;
93 }
94
95 // Find the last underscore
96 auto upos = originalFilename.rfind('_');
97 if (upos == std::string::npos) {
98 continue;
99 }
100
101 // Find the last period
102 auto dpos = originalFilename.rfind('.');
103 if (dpos == std::string::npos || dpos <= upos) {
104 continue;
105 }
106
107 std::string numstr = originalFilename.substr(upos + 1, dpos - upos - 1);
108 if (!numstr.empty() &&
109 std::isdigit(static_cast<unsigned char>(numstr[0]))) {
110 int bundleNumber = std::atoi(numstr.c_str());
111 if (bundleNumber != number) {
112 continue;
113 }
114 }
115
116 std::string baseName = originalFilename.substr(0, upos);
117 // Drop the "_<n>" token and keep everything after it, so a compound
118 // extension (".con.gz", ".con.zst") survives whichever side of the
119 // underscore it sits on.
120 size_t extStart =
121 originalFilename.find_first_not_of("0123456789", upos + 1);
122 if (extStart == std::string::npos) {
123 extStart = originalFilename.size();
124 }
125 std::string newFilename = baseName + originalFilename.substr(extStart);
126
127 try {
128 fs::copy_file(originalFilename, newFilename,
129 fs::copy_options::overwrite_existing);
130 filenames.push_back(newFilename);
131 } catch (const fs::filesystem_error &e) {
132 EONC_LOG_ERROR("unbundle: problem copying {} to {}: {}", originalFilename,
133 newFilename, e.what());
134 }
135 }
136
137 return filenames;
138}
int strchrcount(const char *haystack, char needle)
Definition Bundling.cpp:70

◆ 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 125 of file MobileAtoms.cpp.

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

◆ usesAlternativeRotation()

bool eonc::usesAlternativeRotation ( DimerRotationBackend backend)
inlinenodiscardconstexprnoexcept

Definition at line 41 of file DimerRotationDispatch.h.

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

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.

◆ MXCSR_MASK_IM

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

Definition at line 90 of file fpe_handler.cpp.

◆ MXCSR_MASK_OM

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

Definition at line 92 of file fpe_handler.cpp.

◆ MXCSR_MASK_ZM

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

Definition at line 91 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.