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

Namespaces

namespace  create
namespace  eigen
namespace  neb_paths
namespace  surrogate

Functions

std::string get_value_from_env_or_param (const char *env_variable, const std::string &param_value, const std::string &default_value, const std::string &warning_message, const bool is_mandatory)
std::unique_ptr< JobmakeJob (std::unique_ptr< Parameters > params)
std::shared_ptr< PotentialmakePotential (const Parameters &params)
std::shared_ptr< PotentialmakePotential (PotType ptype, const Parameters &params)
template<typename T>
std::vector< T > get_val_from_string (std::string_view line, std::optional< size_t > nelements=std::nullopt)
 Parse a string into values.
template std::vector< size_t > get_val_from_string (std::string_view, std::optional< size_t >)
std::vector< std::string > get_split_strings (std::string_view line)
 Split a string into constituent strings.
bool isNumber (std::string_view token)
 Figure out if a string has a number in it.
gpr::InputParameters eon_parameters_to_gpr (const Parameters &parameters)
 Create a parameters object for gpr_dimer.
gpr::AtomsConfiguration eon_matter_to_atmconf (Matter *matter)
 Create a configuration of atoms for gpr_dimer.
gpr::Observation eon_matter_to_init_obs (Matter *matter)
 Create an initial Observation object for gpr_dimer.
AtomMatrix makeOrthogonal (const AtomMatrix v1, const AtomMatrix v2)
bool relaxMatter (Matter &matter, const Parameters &params, bool quiet=false, bool writeMovie=false, bool checkpoint=false, std::string prefixMovie=std::string(), std::string prefixCheckpoint=std::string(), std::vector< readcon::ConFrame > *outFrames=nullptr)
void getTime (double *real, double *user, double *sys)
bool existsFile (std::string filename)
std::string getRelevantFile (std::string filename)
VectorXd loadMasses (std::string filename, int nAtoms)
AtomMatrix loadMode (FILE *modeFile, int nAtoms)
AtomMatrix loadMode (std::string filename, int nAtoms)
bool loadOrSynthesizeDisplacement (Matter &target, const Matter &initial, const std::string &displacementPath, const std::string &modePath, double scale)
void saveMode (FILE *modeFile, std::shared_ptr< Matter > matter, AtomMatrix mode)
 Write a mode; constrained axes are emitted as 0.
void saveMode (const std::string &filename, std::shared_ptr< Matter > matter, AtomMatrix mode)
std::vector< int > split_string_int (std::string s, std::string delim)
std::optional< std::string_view > convergenceMetricLabel (std::string_view metric)
 Display label for a force-convergence metric, or nullopt when the name is none of the three the optimizer-driven searches understand.
void requireKnownConvergenceMetric (std::string_view metric, std::string_view context)
 Throws std::invalid_argument naming context when metric is unrecognized.
template<typename T>
bool eigenEquality (const Eigen::MatrixBase< T > &lhs, const Eigen::MatrixBase< T > &rhs, const double threshold=1e-4)
 Check two eigen objects for equality.
double gaussRandom (double avg, double std)
double random (long newSeed=0)
double randomDouble ()
long randomInt (int lower, int upper)
bool identical (const Matter &m1, const Matter &m2, const double distanceDifference)
double maxAtomMotion (const AtomMatrix v1)
AtomMatrix maxAtomMotionApplied (const AtomMatrix v1, double maxMotion)
VectorXd maxAtomMotionAppliedV (const VectorXd v1, double maxMotion)
double maxAtomMotionV (const VectorXd v1)
AtomMatrix maxMotionApplied (const AtomMatrix v1, double maxMotion)
VectorXd maxMotionAppliedV (const VectorXd v1, double maxMotion)
long numAtomsMoved (const AtomMatrix v1, double cutoff)
void projectOutRotTrans (Eigen::VectorXd &step, const AtomMatrix &positions)
void pushApart (std::shared_ptr< Matter > m1, double minDistance)
RotationMatrix rotationExtract (const AtomMatrix r1, const AtomMatrix r2)
bool rotationMatch (const Matter &m1, const Matter &m2, const double max_diff)
void rotationRemove (const AtomMatrix r1, std::shared_ptr< Matter > m2)
bool sortedR (const Matter &m1, const Matter &m2, const double distanceDifference)
void translationRemove (Matter &m1, const AtomMatrix r1)

Variables

constexpr double pi = 3.14159265358979323846

Function Documentation

◆ convergenceMetricLabel()

std::optional< std::string_view > eonc::helpers::convergenceMetricLabel ( std::string_view metric)

Display label for a force-convergence metric, or nullopt when the name is none of the three the optimizer-driven searches understand.

Single source of the accepted spellings, shared by the INI loader and every search that dispatches on the string.

Definition at line 250 of file HelperFunctions.cpp.

250 {
251 if (metric == "max_atom") {
252 return "Max atom force";
253 }
254 if (metric == "max_component") {
255 return "Max force comp";
256 }
257 if (metric == "norm") {
258 return "||Force||";
259 }
260 return std::nullopt;
261}

◆ eigenEquality()

template<typename T>
bool eonc::helpers::eigenEquality ( const Eigen::MatrixBase< T > & lhs,
const Eigen::MatrixBase< T > & rhs,
const double threshold = 1e-4 )

Check two eigen objects for equality.

Parameters
Eigen::MatrixBasethe underlying base class

Definition at line 26 of file MatrixHelpers.hpp.

28 {
29 return lhs.isApprox(rhs, threshold);
30}

◆ eon_matter_to_atmconf()

gpr::AtomsConfiguration eonc::helpers::eon_matter_to_atmconf ( Matter * matter)

Create a configuration of atoms for gpr_dimer.

Parameters
*MatterAn eOn Matter object

Remember that the atom type in eOn is the real atomic number, while in GPR Dimer it is a set of values from 0 to n-1 so this is eOn

False "atomtype" for GPR Dimer

Does a horrible to ensure that this is filled correctly. Essentially we use the Map of <eOn atomtype, GPR faketype> to generate the fully filled vectors for moving and frozen_inactive FIXME: We should really just use the eOn atomtype everywhere

Is a fixed atom Use eOn's atomtype as a key for the GPR's fake atomtype

Is moving

Special case when there's only one atom type, we can now just use the set function of the Field. Essentially now we only have one atom type

End case where we have both nonzero moving and nonzero frozen atoms

Sometimes, nothing happens

Now we will consider the case when everything is moving Everything is almost exactly the same, only we don't have frozen atoms

FIXME: Same caveats as documented above

Special case when there's only one atom type, we can now just use the set function of the Field. Essentially now we only have one atom type

Definition at line 100 of file GPRHelpers.cpp.

100 {
101 gpr::AtomsConfiguration atoms_config;
102 aux::ProblemSetUp problem_setup;
103 gpr::Index_t number_of_mov_atoms;
104 gpr::Index_t number_of_fro_atoms;
105 std::set<int> unique_atomtypes;
106 gpr::Index_t n_at;
107 std::vector<int> atomnrs;
108 std::unordered_map<int, int>
109 atype_to_gprd_atype;
112 int fake_atype;
113
114 atoms_config.clear();
115 // gpr_optim stores positions as row-major 1×(3N), matching AtomMatrix flat
116 // layout.
117 copyAtomMatrixToCoord(matter->getPositions(), atoms_config.positions);
118 const auto nAtoms = matter->numberOfAtoms();
119 atoms_config.is_frozen.resize(1, nAtoms);
120 atoms_config.id.resize(1, nAtoms);
121 atoms_config.atomicNrs.resize(1, nAtoms);
122 for (auto i = 0; i < nAtoms; i++) {
123 atomnrs.push_back(matter->getAtomicNr(i));
124 // Field matrices are 1×N; use (0, i). getFixed is bool → MOVING/FROZEN.
125 atoms_config.atomicNrs(0, i) = matter->getAtomicNr(i);
126 atoms_config.is_frozen(0, i) =
127 matter->getFixed(i) ? FROZEN_ATOM : MOVING_ATOM;
128 atoms_config.id(0, i) = static_cast<gpr::Index_t>(i + 1);
129 }
130
131 unique_atomtypes = std::set<int>(atomnrs.begin(), atomnrs.end());
132 n_at = unique_atomtypes.size();
133 fake_atype = 0;
134 for (auto uatom : unique_atomtypes) {
135 atype_to_gprd_atype.insert(
136 std::pair<int, int>(static_cast<int>(uatom), fake_atype));
137 fake_atype++;
138 }
139
140 number_of_mov_atoms = atoms_config.countMovingAtoms();
141 number_of_fro_atoms =
142 static_cast<gpr::Index_t>(atoms_config.is_frozen.size()) -
143 number_of_mov_atoms;
144
145 if (number_of_fro_atoms > 0 && number_of_mov_atoms > 0) {
146 // Resize structures for moving and frozen atoms
147 atoms_config.atoms_mov.resize(number_of_mov_atoms);
148 atoms_config.atoms_froz_inactive.resize(number_of_fro_atoms);
149
154 if (atype_to_gprd_atype.size() > 1) {
155 int mov_counter = 0;
156 int froz_inactive_counter = 0;
157 for (auto i = 0; i < nAtoms; i++) {
158 if (matter->getFixed(i)) {
161 atoms_config.atoms_froz_inactive.type(0, froz_inactive_counter) =
162 atype_to_gprd_atype.at(atomnrs[i]);
163 froz_inactive_counter++;
164 } else {
166 atoms_config.atoms_mov.type(0, mov_counter) =
167 atype_to_gprd_atype.at(atomnrs[i]);
168 mov_counter++;
169 }
170 }
171 }
174 else if (atype_to_gprd_atype.size() == 1) {
175 atoms_config.atoms_mov.type.setConstant(
176 atype_to_gprd_atype.at(atomnrs[0]));
177 atoms_config.atoms_froz_inactive.type.setConstant(
178 atype_to_gprd_atype.at(atomnrs[0]));
179 }
180 // Assign moving and frozen atoms and list all frozen atoms as inactive
181 gpr::Index_t counter_f = 0, counter_m = 0;
182 for (gpr::Index_t n = 0;
183 n < static_cast<gpr::Index_t>(atoms_config.is_frozen.size()); ++n) {
184 if (atoms_config.is_frozen(0, n) == MOVING_ATOM)
185 gpr::coord::set(atoms_config.atoms_mov.positions, 0, counter_m++,
186 gpr::coord::at(atoms_config.positions, n));
187 else
188 gpr::coord::set(atoms_config.atoms_froz_inactive.positions, 0,
189 counter_f++, gpr::coord::at(atoms_config.positions, n));
190 }
192 } else {
193 if (number_of_mov_atoms == 0) {
195 QUILL_LOG_CRITICAL(
197 " You need to have atoms move!!!\nIn stillness there is only "
198 "death\n");
199 std::exit(1);
200 }
203 atoms_config.atoms_mov.resize(number_of_mov_atoms);
204
206 if (atype_to_gprd_atype.size() > 1) {
207 int mov_counter = 0;
208 for (auto i = 0; i < nAtoms; i++) {
209 atoms_config.atoms_mov.type(0, mov_counter) =
210 atype_to_gprd_atype.at(atomnrs[i]);
211 mov_counter++;
212 }
213 }
216 else if (atype_to_gprd_atype.size() == 1) {
217 atoms_config.atoms_mov.type.setConstant(
218 atype_to_gprd_atype.at(atomnrs[0]));
219 }
220 }
221 // Pairtype indices for pairs of atomtypes (n_at x n_at)
222 // Active pairtypes are indexed as 0,1,...,n_pt-1. Inactive pairtypes are
223 // given index EMPTY.
224 atoms_config.pairtype.resize(n_at, n_at);
225 atoms_config.pairtype.setConstant(EMPTY);
226
227 // Set pairtype indices for moving+moving atom pairs (and update number of
228 // active pairtypes)
229 problem_setup.setPairtypeForMovingAtoms(
230 atoms_config.atoms_mov.type, atoms_config.n_pt, atoms_config.pairtype);
231
232 return atoms_config;
233}
long int numberOfAtoms() const
Definition Matter.cpp:209
long getAtomicNr(long int atom) const
Definition Matter.cpp:392
const AtomMatrix & getPositions() const
Definition Matter.cpp:236
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:402
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition EonLogger.h:44

◆ eon_matter_to_init_obs()

gpr::Observation eonc::helpers::eon_matter_to_init_obs ( Matter * matter)

Create an initial Observation object for gpr_dimer.

Note that this is essentially only for the setup, and it does not actually append or handle the Observation structure other than for initialization of atomic gp dimer

Parameters
*MatterAn eOn Matter object

Definition at line 235 of file GPRHelpers.cpp.

235 {
236 gpr::Observation o;
237 o.clear();
238 copyAtomMatrixToCoord(matter->getPositions(), o.R);
239 // Forces as negative gradients; same N×3 → 1×(3N) packing as positions.
240 AtomMatrix neg_forces = -matter->getForces();
241 copyAtomMatrixToCoord(neg_forces, o.G);
242 o.E.resize(1, 1);
243 o.E(0, 0) = matter->getPotentialEnergy();
244 return o;
245}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
double getPotentialEnergy() const
Definition Matter.cpp:446
const AtomMatrix & getForces() const
Definition Matter.cpp:324

◆ eon_parameters_to_gpr()

gpr::InputParameters eonc::helpers::eon_parameters_to_gpr ( const Parameters & parameters)

Create a parameters object for gpr_dimer.

TODO: Get the cell size from a Matter object

Parameters
*parametersAn eOn parameters object

Definition at line 23 of file GPRHelpers.cpp.

23 {
24 gpr::InputParameters p;
25 // Problem parameters
26 p.actdist_fro.value = parameters.gpr_dimer_options.active_radius;
27 p.dimer_sep.value = parameters.gpr_dimer_options.dimer_sep;
28 p.method_rot.value = parameters.gpr_dimer_options.rot_opt_method;
29 p.method_trans.value = parameters.gpr_dimer_options.trans_opt_method;
30 p.param_trans.value[0] = parameters.gpr_dimer_options.conv_step;
31 p.param_trans.value[1] = parameters.gpr_dimer_options.max_step;
32 // Saddle point convergence parameter
33 p.T_dimer.value = parameters.saddle_search_options.converged_force;
34 p.T_anglerot_init.value = parameters.gpr_dimer_options.converged_angle;
35 // ---
36 p.initrot_nogp.value = parameters.gpr_dimer_options.init_rot_gp;
37 p.num_iter_initrot.value = parameters.gpr_dimer_options.init_rotations_max;
38 // unused except in the capnp for now
39 // p.inittrans_nogp.value = parameters.gpr_dimer_options.init_trans_gp;
40 p.T_anglerot_gp.value = parameters.gpr_dimer_options.relax_conv_angle;
41 p.num_iter_rot_gp.value = parameters.gpr_dimer_options.relax_rotations_max;
42 p.divisor_T_dimer_gp.value = parameters.gpr_dimer_options.divisor_t_dimer_gp;
43 p.disp_max.value = parameters.gpr_dimer_options.midpoint_max_disp;
44 p.ratio_at_limit.value = parameters.gpr_dimer_options.ratio_at_limit;
45 p.num_bigiter.value = parameters.gpr_dimer_options.max_outer_iterations;
46 p.num_iter.value = parameters.gpr_dimer_options.max_inner_iterations;
47 p.islarge_num_iter.value = parameters.gpr_dimer_options.many_iterations;
48 // GPR Parameters
49 p.gp_sigma2.value = parameters.gpr_dimer_options.gpr_params.sigma2;
50 p.jitter_sigma2.value = parameters.gpr_dimer_options.gpr_params.jitter_sigma2;
51 p.sigma2.value = parameters.gpr_dimer_options.gpr_params.noise_sigma2;
52 p.prior_mu.value = parameters.gpr_dimer_options.gpr_params.prior_mu;
53 p.prior_nu.value = parameters.gpr_dimer_options.gpr_params.prior_nu;
54 p.prior_s2.value = parameters.gpr_dimer_options.gpr_params.prior_sigma2;
55 p.check_derivative.value =
57 p.max_iter.value = parameters.gpr_dimer_options.opt_params.max_iterations;
58 p.tolerance_func.value = parameters.gpr_dimer_options.opt_params.tol_func;
59 p.tolerance_sol.value = parameters.gpr_dimer_options.opt_params.tol_sol;
60 p.lambda_limit.value = parameters.gpr_dimer_options.opt_params.lambda_limit;
61 p.lambda.value = parameters.gpr_dimer_options.opt_params.lambda_init;
62 // Prune
63 p.use_prune.value = parameters.gpr_dimer_options.prune_params.use_prune;
64 p.start_prune_at.value = parameters.gpr_dimer_options.prune_params.begin;
65 p.nprune_vals.value = parameters.gpr_dimer_options.prune_params.n_vals;
66 p.prune_threshold.value = parameters.gpr_dimer_options.prune_params.threshold;
67 // Debugging
68 p.report_level.value = parameters.gpr_dimer_options.debug_params.report_level;
69 p.debug_level.value = parameters.gpr_dimer_options.debug_params.debug_level;
70 p.debug_output_dir.value = parameters.gpr_dimer_options.debug_params.out_dir;
71 p.debug_output_file_R.value =
73 p.debug_output_file_E.value =
75 p.debug_output_file_G.value =
77 p.debug_output_file_extension.value =
79 p.debug_offset_from_mid_point.value =
81 p.debug_dy.value = parameters.gpr_dimer_options.debug_params.dy;
82 p.debug_dz.value = parameters.gpr_dimer_options.debug_params.dz;
83 return p;
84}
struct eonc::Parameters::gpr_dimer_options_t gpr_dimer_options
struct eonc::Parameters::saddle_search_options_t saddle_search_options
struct eonc::Parameters::gpr_dimer_options_t::gpr_params_t gpr_params
struct eonc::Parameters::gpr_dimer_options_t::debug_params_t debug_params
struct eonc::Parameters::gpr_dimer_options_t::prune_params_t prune_params
struct eonc::Parameters::gpr_dimer_options_t::opt_params_t opt_params

◆ existsFile()

bool eonc::helpers::existsFile ( std::string filename)

Definition at line 72 of file HelperFunctions.cpp.

72 {
73 return std::filesystem::exists(filename);
74}

◆ gaussRandom()

double eonc::rng::gaussRandom ( double avg,
double std )

Definition at line 41 of file RandomNumbers.cpp.

80 {
81 double r = 2, v1, v2, l, result;
82 while (r >= 1.0 || r < 1e-300) {
83 v1 = 2.0 * randomDouble() - 1.0;
84 v2 = 2.0 * randomDouble() - 1.0;
85 r = v1 * v1 + v2 * v2;
86 }
87 l = v1 * sqrt(-2.0 * ::log(r) / r);
88 result = avg + std * l;
89 return (result);
90}
double randomDouble()

◆ get_split_strings()

std::vector< std::string > eonc::helpers::get_split_strings ( std::string_view line)

Split a string into constituent strings.

Based on https://www.fluentcpp.com/2017/04/21/how-to-split-a-string-in-c/

Parameters
lineA thing to be parsed

Definition at line 48 of file StringHelpers.cc.

48 {
49 std::istringstream ss{std::string{line}};
50 std::vector<std::string> split_strings{std::istream_iterator<std::string>{ss},
51 std::istream_iterator<std::string>()};
52 return split_strings;
53}

◆ get_val_from_string() [1/2]

template<typename T>
std::vector< T > eonc::helpers::get_val_from_string ( std::string_view line,
std::optional< size_t > nelements = std::nullopt )

Parse a string into values.

Parameters
lineA thing to be parsed

Definition at line 11 of file StringHelpers.cc.

12 {
13 assert(not line.empty());
14 std::vector<T> retval;
15 const bool b_isunsigned{std::is_unsigned<T>::value};
16 auto elements{get_split_strings(line)};
17 if (nelements.has_value()) {
18 // Used to truncate if the number of elements is given
19 assert(nelements > 0);
20 elements.resize(nelements.value());
21 }
22 // If it is unsigned then use long double else T
23 for (typename std::conditional<b_isunsigned, long double, T>::type tmp;
24 auto elem : elements) {
25 if (not isNumber(elem)) {
26 continue;
27 }
28 std::istringstream ss{
29 elem}; // instead of {ss.str(elem); ss >> tmp; ss.clear();}
30 ss >> tmp;
31 if (b_isunsigned and tmp < 0) {
32 std::cerr
33 << "Can't represent negative numbers with an unsigned type, bailing on "s
34 << tmp << "\n";
35 assert(tmp > 0);
36 }
37 retval.push_back(tmp);
38 }
39 return retval;
40}
bool isNumber(std::string_view token)
Figure out if a string has a number in it.
std::vector< std::string > get_split_strings(std::string_view line)
Split a string into constituent strings.

◆ get_val_from_string() [2/2]

template std::vector< size_t > eonc::helpers::get_val_from_string ( std::string_view ,
std::optional< size_t >  )

◆ get_value_from_env_or_param()

std::string eonc::helpers::get_value_from_env_or_param ( const char * env_variable,
const std::string & param_value,
const std::string & default_value,
const std::string & warning_message,
const bool is_mandatory )
nodiscard

Definition at line 7 of file EnvHelpers.cc.

11 {
12 const char *env_value = std::getenv(env_variable);
13 if (env_value != nullptr) {
14 return std::string(env_value);
15 }
16
17 if (!param_value.empty()) {
18 return param_value;
19 }
20
21 if (is_mandatory) {
22 throw std::runtime_error(
23 "Environment variable " + std::string(env_variable) +
24 " is not set and no parameter value provided. Please set it in the "
25 "configuration or as an environment variable.\n");
26 }
27
28 if (!default_value.empty() && !warning_message.empty()) {
29 EONC_LOG_WARNING("{}", warning_message);
30 }
31
32 return default_value;
33}
#define EONC_LOG_WARNING(...)
Definition EonLogger.h:256

◆ getRelevantFile()

string eonc::helpers::getRelevantFile ( std::string filename)

Definition at line 76 of file HelperFunctions.cpp.

76 {
77 string filenameRelevant;
78 string filenamePrefix;
79 string filenamePostfix;
80
81 // check if the _cp version of the file is present
82 int i = filename.rfind(".");
83 filenamePrefix.assign(filename, 0, i);
84 filenamePostfix.assign(filename, i, filename.size());
85 filenameRelevant = filenamePrefix + "_cp" + filenamePostfix;
86 if (existsFile(filenameRelevant)) {
87 return filenameRelevant;
88 }
89 // check if the _in version of the file is present
90 filenameRelevant = filenamePrefix + "_in" + filenamePostfix;
91 if (existsFile(filenameRelevant)) {
92 return filenameRelevant;
93 }
94 // otherwise return original filename
95 return filename;
96}
bool existsFile(std::string filename)

◆ getTime()

void eonc::helpers::getTime ( double * real,
double * user,
double * sys )

Definition at line 45 of file HelperFunctions.cpp.

45 {
46 // Wall-clock time via C++11 chrono (portable)
47 using namespace std::chrono;
48 auto now = steady_clock::now();
49 *real = duration<double>(now.time_since_epoch()).count();
50
51#ifdef _WIN32
52 if (user)
53 *user = 0.0;
54 if (sys)
55 *sys = 0.0;
56#else
57 struct rusage r_usage;
58 if (getrusage(RUSAGE_SELF, &r_usage) != 0) {
59 EONC_LOG_WARNING("problem getting usage info: {}", strerror(errno));
60 }
61 if (user) {
62 *user = static_cast<double>(r_usage.ru_utime.tv_sec) +
63 static_cast<double>(r_usage.ru_utime.tv_usec) / 1e6;
64 }
65 if (sys) {
66 *sys = static_cast<double>(r_usage.ru_stime.tv_sec) +
67 static_cast<double>(r_usage.ru_stime.tv_usec) / 1e6;
68 }
69#endif
70}

◆ identical()

bool eonc::geometry::identical ( const Matter & m1,
const Matter & m2,
const double distanceDifference )

Definition at line 37 of file GeometryAnalysis.cpp.

370 {
371
372 AtomMatrix r1 = m1.getPositions();
373 AtomMatrix r2 = m2.getPositions();
374
375 std::set<int> matched;
376 double tolerance = distanceDifference;
377
378 if (r1.rows() != r2.rows()) {
379 return false;
380 }
381 int N = r1.rows();
382
383 for (int i = 0; i < N; i++) {
384 if (std::fabs((m1.pbc(r1.row(i) - r2.row(i))).norm()) < tolerance &&
385 m1.getAtomicNr(i) == m2.getAtomicNr(i)) {
386 matched.insert(i);
387 }
388 }
389
390 for (int j = 0; j < N; j++) {
391
392 if (matched.count(j) == 1)
393 continue;
394
395 for (int k = 0; k < N; k++) {
396 if (matched.count(j) == 1)
397 break;
398
399 if (std::fabs((m1.pbc(r1.row(j) - r2.row(k))).norm()) < tolerance &&
400 m1.getAtomicNr(j) == m2.getAtomicNr(k)) {
401 matched.insert(j);
402 }
403 }
404 }
405
406 if (matched.size() == static_cast<unsigned>(N)) {
407 return true;
408 } else {
409 return false;
410 }
411}
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.h:163

◆ isNumber()

bool eonc::helpers::isNumber ( std::string_view token)

Figure out if a string has a number in it.

Based on

Definition at line 55 of file StringHelpers.cc.

55 {
56 return std::regex_match(
57 std::string{token},
58 std::regex(("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?")));
59}

◆ loadMasses()

VectorXd eonc::helpers::loadMasses ( std::string filename,
int nAtoms )

Definition at line 98 of file HelperFunctions.cpp.

98 {
99 ifstream massFile(filename.c_str());
100 if (!massFile.is_open()) {
101 EONC_LOG_CRITICAL("File {} was not found", filename);
102 throw std::runtime_error(std::format("cannot open {}", filename));
103 }
104
105 VectorXd masses(nAtoms);
106 for (int i = 0; i < nAtoms; i++) {
107 double mass;
108 if (!(massFile >> mass)) {
109 EONC_LOG_CRITICAL("Error reading {}", filename);
110 throw std::runtime_error(
111 std::format("{} ended after {} of {} masses", filename, i, nAtoms));
112 }
113 masses(i) = mass;
114 }
115
116 massFile.close();
117
118 return masses;
119}
#define EONC_LOG_CRITICAL(...)
Definition EonLogger.h:268

◆ loadMode() [1/2]

AtomMatrix eonc::helpers::loadMode ( FILE * modeFile,
int nAtoms )

Definition at line 121 of file HelperFunctions.cpp.

121 {
122 AtomMatrix mode;
123 mode.resize(nAtoms, 3);
124 mode.setZero();
125 for (int i = 0; i < nAtoms; i++) {
126 if (fscanf(modeFile, "%lf %lf %lf", &mode(i, 0), &mode(i, 1),
127 &mode(i, 2)) != 3) {
128 EONC_LOG_CRITICAL("Mode file ended after {} of {} atoms", i, nAtoms);
129 throw std::runtime_error(
130 std::format("mode file ended after {} of {} atoms", i, nAtoms));
131 }
132 }
133 return mode;
134}

◆ loadMode() [2/2]

AtomMatrix eonc::helpers::loadMode ( std::string filename,
int nAtoms )

Definition at line 136 of file HelperFunctions.cpp.

136 {
137 // Unique FILE* with RAII cleanup
138 auto closer = [](FILE *f) {
139 if (f)
140 std::fclose(f);
141 };
142 std::unique_ptr<FILE, decltype(closer)> modeFile(
143 std::fopen(filename.c_str(), "rb"), closer);
144 if (!modeFile) {
145 EONC_LOG_CRITICAL("File {} was not found", filename);
146 throw std::runtime_error(std::format("cannot open {}", filename));
147 }
148 return loadMode(modeFile.get(), nAtoms);
149}
AtomMatrix loadMode(FILE *modeFile, int nAtoms)

◆ loadOrSynthesizeDisplacement()

bool eonc::helpers::loadOrSynthesizeDisplacement ( Matter & target,
const Matter & initial,
const std::string & displacementPath,
const std::string & modePath,
double scale )

Definition at line 151 of file HelperFunctions.cpp.

153 {
154 if (eonc::io::io_ok(target.con2matter(displacementPath))) {
155 if (target.numberOfAtoms() != initial.numberOfAtoms()) {
156 EONC_LOG_ERROR("{} holds {} atoms, the initial structure has {}",
157 displacementPath, target.numberOfAtoms(),
158 initial.numberOfAtoms());
159 return false;
160 }
161 // displacement.con may carry stale fixed-atom coordinates from a prior run.
162 const AtomMatrix &initPos = initial.getPositions();
163 AtomMatrix pos = target.getPositionsCopy();
164 const long n = initial.numberOfAtoms();
165 for (long i = 0; i < n; i++) {
166 if (initial.getFixed(i)) {
167 pos.row(i) = initPos.row(i);
168 }
169 }
170 target.setPositions(pos);
171 return true;
172 }
173 if (!existsFile(modePath)) {
174 return false;
175 }
176 AtomMatrix mode =
177 loadMode(modePath, static_cast<int>(initial.numberOfAtoms()));
178 const double norm = mode.norm();
179 if (!(norm > 0.0)) {
180 return false;
181 }
182 mode *= (scale / norm);
183 target = initial;
184 AtomMatrix pos = initial.getPositionsCopy();
185 pos += mode;
186 const AtomMatrix &initPos = initial.getPositions();
187 const long n = initial.numberOfAtoms();
188 for (long i = 0; i < n; i++) {
189 if (initial.getFixed(i)) {
190 pos.row(i) = initPos.row(i);
191 }
192 }
193 target.setPositions(pos);
194 EONC_LOG_INFO("Synthesized displacement from pos.con + scale {:.6g} * unit "
195 "mode in {} (missing {})",
196 scale, modePath, displacementPath);
197 return true;
198}
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:262
#define EONC_LOG_INFO(...)
Definition EonLogger.h:250
AtomMatrix getPositionsCopy() const
Definition Matter.cpp:238
void setPositions(const AtomMatrix &pos)
Definition Matter.cpp:273
io::IoStatus con2matter(std::string filename)
Definition Matter.h:269
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ makeJob()

std::unique_ptr< Job > eonc::helpers::makeJob ( std::unique_ptr< Parameters > params)

Definition at line 39 of file Job.cpp.

39 {
40 switch (params->main_options.job) {
41 using enum JobType;
42 case Process_Search: {
43 return (std::make_unique<ProcessSearchJob>(std::move(params)));
44 break;
45 }
46 case Saddle_Search: {
47 return (std::make_unique<SaddleSearchJob>(std::move(params)));
48 break;
49 }
50 case Minimization: {
51 return (std::make_unique<MinimizationJob>(std::move(params)));
52 break;
53 }
54 case Point: {
55 return (std::make_unique<PointJob>(std::move(params)));
56 break;
57 }
58 case Parallel_Replica: {
59 return (std::make_unique<ParallelReplicaJob>(std::move(params)));
60 break;
61 }
62 case Safe_Hyperdynamics: {
63 return (std::make_unique<SafeHyperJob>(std::move(params)));
64 break;
65 }
66 case TAD: {
67 return (std::make_unique<TADJob>(std::move(params)));
68 break;
69 }
70 case Replica_Exchange: {
71 return (std::make_unique<ReplicaExchangeJob>(std::move(params)));
72 break;
73 }
74 case Basin_Hopping: {
75 return (std::make_unique<BasinHoppingJob>(std::move(params)));
76 break;
77 }
78 case Hessian: {
79 return (std::make_unique<HessianJob>(std::move(params)));
80 break;
81 }
82 case Finite_Difference: {
83 return (std::make_unique<FiniteDifferenceJob>(std::move(params)));
84 break;
85 }
87 return (std::make_unique<NudgedElasticBandJob>(std::move(params)));
88 break;
89 }
90 case Dynamics: {
91 return (std::make_unique<DynamicsJob>(std::move(params)));
92 break;
93 }
94 case Prefactor: {
95 return (std::make_unique<PrefactorJob>(std::move(params)));
96 break;
97 }
99 return (std::make_unique<GlobalOptimizationJob>(std::move(params)));
100 break;
101 }
103 return (std::make_unique<StructureComparisonJob>(std::move(params)));
104 break;
105 }
106 case Monte_Carlo: {
107 return (std::make_unique<MonteCarloJob>(std::move(params)));
108 break;
109 }
110#ifdef WITH_GP_SURROGATE
111 case GP_Surrogate: {
112 return (std::make_unique<GPSurrogateJob>(std::move(params)));
113 break;
114 }
115#endif
116 case OH_TST: {
117 return (std::make_unique<OHTSTJob>(std::move(params)));
118 }
119 default:
120 throw std::runtime_error("No known job could be constructed");
121 break;
122 }
123}

◆ makeOrthogonal()

AtomMatrix eonc::helpers::makeOrthogonal ( const AtomMatrix v1,
const AtomMatrix v2 )

Definition at line 40 of file HelperFunctions.cpp.

41 {
42 return v1 - matDot(v1, v2) * eonc::safemath::safe_normalized(v2);
43}
double matDot(const AtomMatrix &a, const AtomMatrix &b)
SIMD-optimized dot product for contiguous Eigen matrices.
Definition Eigen.h:50

◆ makePotential() [1/2]

std::shared_ptr< Potential > eonc::helpers::makePotential ( const Parameters & params)

Definition at line 118 of file Potential.cpp.

118 {
119 // Inject config-file path before any potential constructor runs
122 return makePotential(params.potential_options.potential, params);
123}
struct eonc::Parameters::potential_options_t potential_options
void add_config_paths(const std::string &colon_paths)
Inject search paths from the eOn config file.
static PluginLoader & instance()
Thread-safe singleton accessor (Meyer's pattern).
std::shared_ptr< Potential > makePotential(const Parameters &params)

◆ makePotential() [2/2]

std::shared_ptr< Potential > eonc::helpers::makePotential ( PotType ptype,
const Parameters & params )

Definition at line 124 of file Potential.cpp.

125 {
126 // Inject config-file path before any potential constructor runs.
127 // Called on every code path including Job::Job which uses this overload.
130 switch (ptype) {
131 // TODO: Every potential must know their own type
132 case PotType::EMT: {
133 return (std::make_shared<EffectiveMediumTheory>(params));
134 break;
135 }
136 case PotType::EXT_POT: {
137 return (std::make_shared<ExtPot>(params));
138 break;
139 }
140 case PotType::LJ: {
141 return makeRgpot<rgpot::LJPot>(PotType::LJ, params, rgpot::LJConfig{});
142 break;
143 }
144 case PotType::LJCLUSTER: {
146 rgpot::LJClusterConfig{});
147 break;
148 }
149 case PotType::MORSE_PT: {
151 rgpot::MorseConfig{});
152 break;
153 }
154#ifdef CUH2_POT
155 case PotType::CUH2: {
157 break;
158 }
159#endif
160#ifdef WITH_WATER
161 case PotType::TIP4P: {
162 return (std::make_shared<Tip4p>(params));
163 break;
164 }
165 case PotType::SPCE: {
166 return (std::make_shared<SpceCcl>(params));
167 break;
168 }
169#ifdef WITH_FORTRAN
170 case PotType::TIP4P_PT: {
171 return (std::make_shared<Tip4p_Pt>(params));
172 break;
173 }
174 case PotType::TIP4P_H: {
176 params);
177 break;
178 }
179#endif
180#endif
181 // Fortran potentials: always available, loaded at runtime via dlopen
182 case PotType::EAM_AL: {
184 params);
185 break;
186 }
187 case PotType::EDIP: {
189 break;
190 }
191 case PotType::FEHE: {
193 break;
194 }
195 case PotType::LENOSKY_SI: {
197 params);
198 break;
199 }
200 case PotType::SW_SI: {
202 break;
203 }
204 case PotType::TERSOFF_SI: {
206 params);
207 break;
208 }
209#ifndef _WIN32
210#ifdef WITH_VASP
211 case PotType::VASP: {
212 return (std::make_shared<VASP>(params));
213 break;
214 }
215#endif
216#endif
217 case PotType::LAMMPS: {
218 return std::make_shared<LAMMPSPot>(params);
219 }
220#ifdef EONMPI
221 case PotType::MPI: {
222 return (std::make_shared<MPIPot>(params));
223 break;
224 }
225#endif
226#ifdef EMBED_PYTHON
227#ifdef WITH_ASE_POT
228 case PotType::ASE_POT: {
229 return (std::make_shared<ASE>(params));
230 break;
231 }
232#endif
233#endif
234#ifdef WITH_AMS
235 case PotType::AMS: {
236 return (std::make_shared<AMS>(params));
237 break;
238 }
239 case PotType::AMS_IO: {
240 return (std::make_shared<AMS_IO>(params));
241 break;
242 }
243#endif
244#ifdef WITH_CATLEARN
245 case PotType::CatLearn: {
246 return (std::make_shared<CatLearnPot>(params));
247 break;
248 }
249#endif
250// TODO: Handle Fortran interaction
251#ifdef WITH_XTB
252 case PotType::XTB: {
253 return (std::make_shared<XTBPot>(params));
254 break;
255 }
256#endif
257#ifdef WITH_ASE_ORCA
258 case PotType::ASE_ORCA: {
259 return (std::make_shared<ASEOrcaPot>(params));
260 break;
261 }
262#endif
263#ifdef WITH_ASE_NWCHEM
264 case PotType::ASE_NWCHEM: {
265 return (std::make_shared<ASENwchemPot>(params));
266 break;
267 }
268#endif
269#ifdef WITH_METATOMIC
270 case PotType::METATOMIC: {
271 return (std::make_shared<MetatomicPotential>(params));
272 break;
273 }
274#endif
275 case PotType::ZBL: {
277 PotType::ZBL, params,
278 rgpot::ZBLConfig{
279 .cut_inner = params.zbl_options.cut_inner,
280 .cut_global = params.zbl_options.cut_global,
281 });
282 break;
283 }
284#ifndef IS_WINDOWS
286 return (std::make_shared<SocketNWChemPot>(params));
287 break;
288 }
289#endif
290#ifdef WITH_RGPOT
291 case PotType::RGPOT: {
292 return (std::make_shared<RgpotPot>(params));
293 break;
294 }
295#endif
296 default:
297 EONC_LOG_ERROR("No known potential could be constructed from {}",
298 magic_enum::enum_name(ptype));
299 eonc::log::get()->flush_log();
300 throw std::runtime_error("Terminating");
301 break;
302 }
303}
std::shared_ptr< Potential > makeRgpot(PotType ptype, const Parameters &params, const Cfg &cfg)
Factory arm helper: construct the kernel from its config and wrap it.
std::shared_ptr< Potential > makeRgpotDefault(PotType ptype, const Parameters &params)
Factory arm helper for kernels whose parameters are fixed tabulated data with no eOn-side configurati...
struct eonc::Parameters::zbl_options_t zbl_options

◆ maxAtomMotion()

Definition at line 29 of file GeometryAnalysis.cpp.

269 {
270 return v1.rowwise().norm().maxCoeff();
271}

◆ maxAtomMotionApplied()

Definition at line 32 of file GeometryAnalysis.cpp.

309 {
310 AtomMatrix v2(v1);
311
312 double max = maxAtomMotion(v1);
313 if (max > maxMotion) {
314 v2 *= maxMotion / max;
315 }
316 return v2;
317}
double maxAtomMotion(const AtomMatrix v1)

◆ maxAtomMotionAppliedV()

VectorXd eonc::geometry::maxAtomMotionAppliedV ( const VectorXd v1,
double maxMotion )

Definition at line 33 of file GeometryAnalysis.cpp.

320 {
321 VectorXd v2(v1);
322
323 double max = maxAtomMotionV(v1);
324 if (max > maxMotion) {
325 v2 *= maxMotion / max;
326 }
327 return v2;
328}
double maxAtomMotionV(const VectorXd v1)

◆ maxAtomMotionV()

double eonc::geometry::maxAtomMotionV ( const VectorXd v1)

Definition at line 30 of file GeometryAnalysis.cpp.

273 {
274 double max = 0.0;
275 long n = v1.rows();
276 if (n < 3) {
277 // Vector too short for 3D atom grouping; treat as single displacement
278 return v1.norm();
279 }
280 for (long i = 0; i + 3 <= n; i += 3) {
281 double norm = v1.segment<3>(i).norm();
282 if (max < norm) {
283 max = norm;
284 }
285 }
286 // Handle trailing elements (vector size not multiple of 3)
287 long rem = n % 3;
288 if (rem > 0) {
289 double norm = v1.tail(rem).norm();
290 if (max < norm) {
291 max = norm;
292 }
293 }
294 return max;
295}

◆ maxMotionApplied()

AtomMatrix eonc::geometry::maxMotionApplied ( const AtomMatrix v1,
double maxMotion )

Definition at line 34 of file GeometryAnalysis.cpp.

331 {
332 AtomMatrix v2(v1);
333
334 double max = v1.norm();
335 if (max > maxMotion) {
336 v2 *= maxMotion / max;
337 }
338 return v2;
339}

◆ maxMotionAppliedV()

VectorXd eonc::geometry::maxMotionAppliedV ( const VectorXd v1,
double maxMotion )

Definition at line 35 of file GeometryAnalysis.cpp.

342 {
343 VectorXd v2(v1);
344
345 double max = v1.norm();
346 if (max > maxMotion) {
347 v2 *= maxMotion / max;
348 }
349 return v2;
350}

◆ numAtomsMoved()

long eonc::geometry::numAtomsMoved ( const AtomMatrix v1,
double cutoff )

Definition at line 31 of file GeometryAnalysis.cpp.

297 {
298 long num = 0;
299 for (int i = 0; i < v1.rows(); i++) {
300 double norm = v1.row(i).norm();
301 if (norm >= cutoff) {
302 num += 1;
303 }
304 }
305 return num;
306}

◆ projectOutRotTrans()

void eonc::geometry::projectOutRotTrans ( Eigen::VectorXd & step,
const AtomMatrix & positions )

Definition at line 23 of file GeometryAnalysis.cpp.

133 {
134 long nAtoms = positions.rows();
135 long dof = nAtoms * 3;
136
137 // 1. Compute center of mass (unweighted geometric center)
138 Eigen::Vector3d com = Eigen::Vector3d::Zero();
139 for (long i = 0; i < nAtoms; ++i) {
140 com(0) += positions(i, 0);
141 com(1) += positions(i, 1);
142 com(2) += positions(i, 2);
143 }
144 com /= static_cast<double>(nAtoms);
145
146 // 2. Construct 6 basis vectors for rigid-body translation and rotation
147 std::vector<Eigen::VectorXd> basis;
148 basis.reserve(6);
149
150 // Translational basis vectors
151 for (int d = 0; d < 3; ++d) {
152 Eigen::VectorXd t = Eigen::VectorXd::Zero(dof);
153 for (long j = 0; j < nAtoms; ++j) {
154 t(3 * j + d) = 1.0;
155 }
156 basis.push_back(t);
157 }
158
159 // Rotational basis vectors (infinitesimal rotations around COM)
160 Eigen::VectorXd rx = Eigen::VectorXd::Zero(dof);
161 Eigen::VectorXd ry = Eigen::VectorXd::Zero(dof);
162 Eigen::VectorXd rz = Eigen::VectorXd::Zero(dof);
163
164 for (long i = 0; i < nAtoms; ++i) {
165 double x = positions(i, 0) - com(0);
166 double y = positions(i, 1) - com(1);
167 double z = positions(i, 2) - com(2);
168 // Rotation around x-axis: cross(xhat, r) = (0, -z, y)
169 rx(3 * i + 1) = -z;
170 rx(3 * i + 2) = y;
171 // Rotation around y-axis: cross(yhat, r) = (z, 0, -x)
172 ry(3 * i + 0) = z;
173 ry(3 * i + 2) = -x;
174 // Rotation around z-axis: cross(zhat, r) = (-y, x, 0)
175 rz(3 * i + 0) = -y;
176 rz(3 * i + 1) = x;
177 }
178 basis.push_back(rx);
179 basis.push_back(ry);
180 basis.push_back(rz);
181
182 // 3. Modified Gram-Schmidt orthonormalization
183 std::vector<Eigen::VectorXd> ortho;
184 ortho.reserve(6);
185
186 for (auto &v : basis) {
187 Eigen::VectorXd u = v;
188 for (const auto &e : ortho) {
189 u -= u.dot(e) * e;
190 }
191 // Handles linear molecules where one rotational mode is degenerate
192 if (u.norm() > 1e-9) {
193 u.normalize();
194 ortho.push_back(u);
195 }
196 }
197
198 // 4. Project out rigid-body components from step
199 for (const auto &e : ortho) {
200 step -= step.dot(e) * e;
201 }
202}

◆ pushApart()

void eonc::geometry::pushApart ( std::shared_ptr< Matter > m1,
double minDistance )

Definition at line 41 of file GeometryAnalysis.cpp.

485 {
486 if (minDistance <= 0)
487 return;
488
489 AtomMatrix r1 = m1->getPositions();
490 AtomMatrix Force(r1.rows(), 3);
491 double f = 0.025;
492 double cut = minDistance;
493 double pushAparts = 500;
494 for (int p = 0; p < r1.rows(); p++) {
495 for (int axis = 0; axis <= 2; axis++) {
496 Force(p, axis) = 0;
497 }
498 }
499 for (int count = 0; count < pushAparts; count++) {
500 int moved = 0;
501 for (int i = 0; i < r1.rows(); i++) {
502 for (int j = i + 1; j < r1.rows(); j++) {
503 double d = m1->distance(i, j);
504 if (d < cut) {
505 moved++;
506 for (int axis = 0; axis <= 2; axis++) {
507 double componant = f * (r1(i, axis) - r1(j, axis)) / d;
508 Force(i, axis) += componant;
509 Force(j, axis) -= componant;
510 }
511 }
512 }
513 }
514 if (moved == 0)
515 break;
516 for (int k = 0; k < r1.rows(); k++) {
517 for (int axis = 0; axis <= 2; axis++) {
518 r1(k, axis) += Force(k, axis);
519 Force(k, axis) = 0;
520 }
521 }
522 m1->setPositions(r1);
523 }
524}

◆ random()

double eonc::rng::random ( long newSeed = 0)

Definition at line 35 of file RandomNumbers.cpp.

16 {
17 static long seed = -1;
18 if (newSeed) {
19 seed = -newSeed;
20 }
21 int j;
22 long k;
23 static long seed2 = 123456789;
24 static long iy = 0;
25 static long iv[NTAB];
26 double temp;
27 if (seed <= 0) {
28 if (-(seed) < 1)
29 seed = 3;
30 else
31 seed = -(seed);
32 seed2 = (seed);
33 for (j = NTAB + 7; j >= 0; j--) {
34 k = (seed) / IQ1;
35 seed = IA1 * (seed - k * IQ1) - k * IR1;
36 if (seed < 0)
37 seed += IM1;
38 if (j < NTAB)
39 iv[j] = seed;
40 }
41 iy = iv[0];
42 }
43 k = (seed) / IQ1;
44 seed = IA1 * (seed - k * IQ1) - k * IR1;
45 if (seed < 0)
46 seed += IM1;
47 k = seed2 / IQ2;
48 seed2 = IA2 * (seed2 - k * IQ2) - k * IR2;
49 if (seed2 < 0)
50 seed2 += IM2;
51 j = int(iy / NDIV);
52 iy = iv[j] - seed2;
53 iv[j] = seed;
54 if (iy < 1)
55 iy += IMM1;
56 if ((temp = double(AM * iy)) > RNMX)
57 return RNMX;
58 else
59 return temp;
60}
constexpr double AM
constexpr int NDIV
constexpr long IA2
constexpr long IR2
constexpr long IQ1
constexpr int NTAB
constexpr long IA1
constexpr long IQ2
constexpr long IM1
constexpr long IMM1
constexpr long IM2
constexpr long IR1
constexpr double RNMX

◆ randomDouble()

Definition at line 36 of file RandomNumbers.cpp.

62{ return (random()); }
double random(long newSeed=0)

◆ randomInt()

long eonc::rng::randomInt ( int lower,
int upper )

Definition at line 40 of file RandomNumbers.cpp.

76 {
77 return lround((upper - lower) * randomDouble() + lower);
78}

◆ relaxMatter()

bool eonc::helpers::relaxMatter ( Matter & matter,
const Parameters & params,
bool quiet = false,
bool writeMovie = false,
bool checkpoint = false,
std::string prefixMovie = std::string(),
std::string prefixCheckpoint = std::string(),
std::vector< readcon::ConFrame > * outFrames = nullptr )

Definition at line 314 of file HelperFunctions.cpp.

318 {
319 eonc::log::Scoped m_log;
320 auto objf = std::make_shared<MatterObjectiveFunction>(matter, params);
322 objf, params.optimizer_options.method, params);
323
324 std::ostringstream min;
325 min << prefixMovie;
326 std::string minDatFilename = prefixMovie + ".dat";
327 auto write_movie_frame = [&](uint64_t frameIndex, bool append,
328 double stepSize) {
330 metadata.frame_index = frameIndex;
331 metadata.energy = matter.getPotentialEnergy();
332 metadata.scalars.push_back({"step_size", stepSize});
333 metadata.scalars.push_back({"convergence", objf->getConvergence()});
334 if (outFrames) {
335 outFrames->push_back(eonc::io::matterToConFrame(matter, &metadata));
336 }
337 if (writeMovie) {
338 if (!eonc::io::io_ok(matter.matter2con(min.str(), append, &metadata))) {
339 QUILL_LOG_WARNING(m_log, "Failed to write movie frame {}", min.str());
340 }
341 }
342
344 std::ofstream minDat(minDatFilename,
345 append ? (std::ios::binary | std::ios::app)
346 : std::ios::binary);
347 if (minDat) {
348 if (!append) {
349 minDat << "iteration\tstep_size\tconvergence\tenergy\n";
350 }
351 minDat << std::format("{}\t{:.5e}\t{:.5e}\t{:.6f}\n", frameIndex,
352 stepSize, objf->getConvergence(),
353 matter.getPotentialEnergy());
354 }
355 }
356 };
357 if (writeMovie || outFrames) {
358 write_movie_frame(0, false, 0.0);
359 }
360
361 int iteration = 0;
362 if (!quiet) {
363 QUILL_LOG_DEBUG(m_log, "{} {:10s} {:14s} {:18s} {:13s}\n", "[Matter]",
364 "Iter", "Step size",
366 "Energy");
367 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}\n",
368 "[Matter]", iteration, 0.0, objf->getConvergence(),
369 matter.getPotentialEnergy());
370 }
371
372 while (!objf->isConverged() &&
373 iteration < params.optimizer_options.max_iterations) {
374
375 AtomMatrix pos = matter.getPositions();
376
377 optim->step(params.optimizer_options.max_move);
378 iteration++;
379
380 double stepSize =
381 eonc::geometry::maxAtomMotion(matter.pbc(matter.getPositions() - pos));
382
383 if (!quiet) {
384 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
385 "[Matter]", iteration, stepSize, objf->getConvergence(),
386 matter.getPotentialEnergy());
387 }
388
389 if (writeMovie || outFrames) {
390 write_movie_frame(static_cast<uint64_t>(iteration), true, stepSize);
391 }
392
393 if (checkpoint) {
394 std::ostringstream chk;
395 chk << prefixCheckpoint << "_cp";
396 if (!eonc::io::io_ok(matter.matter2con(chk.str(), false))) {
397 QUILL_LOG_WARNING(m_log, "Failed to write checkpoint {}", chk.str());
398 }
399 }
400 }
401
402 if (iteration == 0) {
403 if (!quiet) {
404 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
405 "[Matter]", iteration, 0.0, objf->getConvergence(),
406 matter.getPotentialEnergy());
407 }
408 }
409 return objf->isConverged();
410}
io::IoStatus matter2con(std::string filename, bool append=false, const io::ConFrameMetadata *metadata=nullptr)
Definition Matter.h:281
struct eonc::Parameters::optimizer_options_t optimizer_options
struct eonc::Parameters::debug_options_t debug_options
double maxAtomMotion(const AtomMatrix v1)
std::unique_ptr< Optimizer > mkOptim(std::shared_ptr< ObjectiveFunction > a_objf, OptType a_otype, const Parameters &a_params)
Definition Optimizer.cpp:21
readcon::ConFrame matterToConFrame(Matter &m, const ConFrameMetadata *metadata)
Build a single stamped ConFrame from Matter (same builder as matter2con).
std::optional< uint64_t > frame_index
Definition ConFileIO.h:72
std::vector< ConMetadataValue > scalars
Definition ConFileIO.h:79
std::optional< double > energy
Definition ConFileIO.h:73
RAII helper for class-scoped logging.
Definition EonLogger.h:171

◆ requireKnownConvergenceMetric()

void eonc::helpers::requireKnownConvergenceMetric ( std::string_view metric,
std::string_view context )

Throws std::invalid_argument naming context when metric is unrecognized.

Call at construction: the metric is compared once per optimizer step, and a typo should not surface on iteration 4000.

Definition at line 263 of file HelperFunctions.cpp.

264 {
265 if (convergenceMetricLabel(metric)) {
266 return;
267 }
268 throw std::invalid_argument(
269 std::format("{} unknown convergence_metric: {}", context, metric));
270}
std::optional< std::string_view > convergenceMetricLabel(std::string_view metric)
Display label for a force-convergence metric, or nullopt when the name is none of the three the optim...

◆ rotationExtract()

Definition at line 21 of file GeometryAnalysis.cpp.

22 {
24
25 // Determine optimal rotation
26 // Horn, J. Opt. Soc. Am. A, 1987
27 Matrix3d m = r1.transpose() * r2;
28
29 double sxx = m(0, 0);
30 double sxy = m(0, 1);
31 double sxz = m(0, 2);
32 double syx = m(1, 0);
33 double syy = m(1, 1);
34 double syz = m(1, 2);
35 double szx = m(2, 0);
36 double szy = m(2, 1);
37 double szz = m(2, 2);
38
39 Matrix4d n;
40 n.setZero();
41 n(0, 1) = syz - szy;
42 n(0, 2) = szx - sxz;
43 n(0, 3) = sxy - syx;
44
45 n(1, 2) = sxy + syx;
46 n(1, 3) = szx + sxz;
47
48 n(2, 3) = syz + szy;
49
50 n += n.transpose().eval();
51
52 n(0, 0) = sxx + syy + szz;
53 n(1, 1) = sxx - syy - szz;
54 n(2, 2) = -sxx + syy - szz;
55 n(3, 3) = -sxx - syy + szz;
56
57 Eigen::SelfAdjointEigenSolver<Matrix4d> es(n);
58 Eigen::Vector4d maxv = es.eigenvectors().col(3);
59
60 double aa = maxv[0] * maxv[0];
61 double bb = maxv[1] * maxv[1];
62 double cc = maxv[2] * maxv[2];
63 double dd = maxv[3] * maxv[3];
64 double ab = maxv[0] * maxv[1];
65 double ac = maxv[0] * maxv[2];
66 double ad = maxv[0] * maxv[3];
67 double bc = maxv[1] * maxv[2];
68 double bd = maxv[1] * maxv[3];
69 double cd = maxv[2] * maxv[3];
70
71 R(0, 0) = aa + bb - cc - dd;
72 R(0, 1) = 2 * (bc - ad);
73 R(0, 2) = 2 * (bd + ac);
74 R(1, 0) = 2 * (bc + ad);
75 R(1, 1) = aa - bb + cc - dd;
76 R(1, 2) = 2 * (cd - ab);
77 R(2, 0) = 2 * (bd - ac);
78 R(2, 1) = 2 * (cd + ab);
79 R(2, 2) = aa - bb - cc + dd;
80
81 return R;
82}
Eigen::Matrix< double, 3, 3, eOnStorageOrder > RotationMatrix
Definition Eigen.h:38
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
Definition Eigen.h:35
Eigen::Matrix< double, 4, 4, eOnStorageOrder > Matrix4d
Definition Eigen.h:36

◆ rotationMatch()

bool eonc::geometry::rotationMatch ( const Matter & m1,
const Matter & m2,
const double max_diff )

Definition at line 22 of file GeometryAnalysis.cpp.

85 {
86 AtomMatrix r1 = m1.getPositions();
87 AtomMatrix r2 = m2.getPositions();
88
89 // Align centroids
90 Eigen::VectorXd c1(3);
91 Eigen::VectorXd c2(3);
92
93 c1[0] = r1.col(0).sum();
94 c1[1] = r1.col(1).sum();
95 c1[2] = r1.col(2).sum();
96 c2[0] = r2.col(0).sum();
97 c2[1] = r2.col(1).sum();
98 c2[2] = r2.col(2).sum();
99 c1 /= r1.rows();
100 c2 /= r2.rows();
101
102 for (int i = 0; i < r1.rows(); i++) {
103 r1(i, 0) -= c1[0];
104 r1(i, 1) -= c1[1];
105 r1(i, 2) -= c1[2];
106
107 r2(i, 0) -= c2[0];
108 r2(i, 1) -= c2[1];
109 r2(i, 2) -= c2[2];
110 }
111
113
114 // Eigen is transposed relative to numpy
115 r2 = r2 * R;
116
117 for (int i = 0; i < r1.rows(); i++) {
118 double diff = (r2.row(i) - r1.row(i)).norm();
119 if (diff > max_diff) {
120 return false;
121 }
122 }
123 return true;
124}
RotationMatrix rotationExtract(const AtomMatrix r1, const AtomMatrix r2)

◆ rotationRemove()

void eonc::geometry::rotationRemove ( const AtomMatrix r1,
std::shared_ptr< Matter > m2 )

Definition at line 24 of file GeometryAnalysis.cpp.

205 {
206 // Skip for extended systems (slabs/surfaces with frozen atoms).
207 // Rigid-body rotation and translation are not well-defined when the
208 // system is anchored by frozen atoms.
209 if (m2->numberOfFixedAtoms() > 0) {
210 return;
211 }
212
213 AtomMatrix r2 = m2->getPositions();
214 long n = r1_passed.size();
215
216 // Compute displacement as flat 3N vector
217 Eigen::VectorXd step(n);
218 Eigen::Map<const Eigen::VectorXd> r1_flat(r1_passed.data(), n);
219 Eigen::Map<const Eigen::VectorXd> r2_flat(r2.data(), n);
220 step = r2_flat - r1_flat;
221
222 // Project out rigid-body translation and rotation
223 projectOutRotTrans(step, r1_passed);
224
225 // Reconstruct positions: r1 + projected step
226 Eigen::VectorXd result = r1_flat + step;
227 AtomMatrix resultMat(r1_passed.rows(), 3);
228 Eigen::Map<Eigen::VectorXd>(resultMat.data(), n) = result;
229
230 m2->setPositions(resultMat);
231}
void projectOutRotTrans(Eigen::VectorXd &step, const AtomMatrix &positions)

◆ saveMode() [1/2]

void eonc::helpers::saveMode ( const std::string & filename,
std::shared_ptr< Matter > matter,
AtomMatrix mode )

Definition at line 211 of file HelperFunctions.cpp.

212 {
213 std::ofstream out(filename);
214 if (!out)
215 return;
216 const AtomMatrix free = matter->getFree();
217 long const nAtoms = matter->numberOfAtoms();
218 for (long i = 0; i < nAtoms; ++i) {
219 out << std::format("{:.17g}\t{:.17g}\t{:.17g}\n", free(i, 0) * mode(i, 0),
220 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
221 }
222}

◆ saveMode() [2/2]

void eonc::helpers::saveMode ( FILE * modeFile,
std::shared_ptr< Matter > matter,
AtomMatrix mode )

Write a mode; constrained axes are emitted as 0.

Definition at line 200 of file HelperFunctions.cpp.

201 {
202 const AtomMatrix free = matter->getFree();
203 long const nAtoms = matter->numberOfAtoms();
204 for (long i = 0; i < nAtoms; ++i) {
205 fprintf(modeFile, "%.17g\t%.17g\t%.17g\n", free(i, 0) * mode(i, 0),
206 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
207 }
208 return;
209}

◆ sortedR()

bool eonc::geometry::sortedR ( const Matter & m1,
const Matter & m2,
const double distanceDifference )

Definition at line 39 of file GeometryAnalysis.cpp.

414 {
415 EONC_LOG_INFO("In sortedR");
416 AtomMatrix r1 = m1.getPositions();
417 AtomMatrix r2 = m2.getPositions();
418 double tolerance = distanceDifference;
419 int matches = 0;
420
421 if (r1.rows() != r2.rows()) {
422 return false;
423 }
424
425 // Allocate memory for rdf1 and rdf2
426 std::vector<std::set<atom, by_atom>> rdf1(r1.rows());
427 std::vector<std::set<atom, by_atom>> rdf2(r2.rows());
428
429 for (int i2 = 0; i2 < r2.rows(); i2++) {
430 rdf2[i2].clear();
431 for (int j2 = 0; j2 < r2.rows(); j2++) {
432 if (j2 == i2)
433 continue;
434 atom a2;
435 a2.r = m2.distance(i2, j2);
436 a2.z = m2.getAtomicNr(j2);
437 rdf2[i2].insert(a2);
438 rdf2[j2].insert(a2);
439 }
440 }
441
442 for (int i1 = 0; i1 < r1.rows(); i1++) {
443 if (matches == i1 - 2) {
444 return false;
445 }
446 for (int j1 = 0; j1 < r1.rows(); j1++) {
447 if (j1 == i1)
448 continue;
449 atom a;
450 a.r = m1.distance(i1, j1);
451 a.z = m1.getAtomicNr(j1);
452 rdf1[i1].insert(a);
453 rdf1[j1].insert(a);
454 }
455 for (int x = 0; x < r2.rows(); x++) {
456 auto it2 = rdf2[x].begin();
457 auto it = rdf1[i1].begin();
458 int c = 0;
459 int counter = 0;
460 for (; c < r1.rows(); c++) {
461 if (it == rdf1[i1].end() || it2 == rdf2[x].end())
462 break;
463 atom k1 = *it;
464 atom k2 = *it2;
465 if (std::fabs(k1.r - k2.r) < tolerance && k1.z == k2.z) {
466 counter++;
467 } else {
468 EONC_LOG_INFO("No match");
469 break;
470 }
471 ++it;
472 ++it2;
473 }
474 if (counter == r1.rows()) {
475 matches++;
476 } else {
477 EONC_LOG_INFO("No match");
478 }
479 }
480 }
481
482 return matches >= r1.rows();
483}
double distance(long index1, long index2) const
Definition Matter.cpp:360

◆ split_string_int()

std::vector< int > eonc::helpers::split_string_int ( std::string s,
std::string delim )

Definition at line 224 of file HelperFunctions.cpp.

225 {
226 std::vector<int> list;
227 if (s.empty())
228 return list;
229
230 size_t start = 0;
231 size_t end = s.find_first_of(delim);
232 while (start < s.size()) {
233 auto token = s.substr(start, end - start);
234 if (!token.empty()) {
235 try {
236 list.push_back(std::stoi(token));
237 } catch (const std::exception &) {
238 return {}; // Parse error
239 }
240 }
241 if (end == std::string::npos)
242 break;
243 start = end + 1;
244 end = s.find_first_of(delim, start);
245 }
246 return list;
247}

◆ translationRemove()

Definition at line 27 of file GeometryAnalysis.cpp.

240 {
241 AtomMatrix r1 = m1.getPositions();
242 AtomMatrix r2 = r2_passed;
243
244 // net displacement
245 Eigen::VectorXd disp(3);
246 AtomMatrix r12 = m1.pbc(r2 - r1);
247
248 disp[0] = r12.col(0).sum();
249 disp[1] = r12.col(1).sum();
250 disp[2] = r12.col(2).sum();
251 disp /= r1.rows();
252
253 for (int i = 0; i < r1.rows(); i++) {
254 r1(i, 0) += disp[0];
255 r1(i, 1) += disp[1];
256 r1(i, 2) += disp[2];
257 }
258
259 m1.setPositions(r1);
260 return;
261}

Variable Documentation

◆ pi

double eonc::helpers::pi = 3.14159265358979323846
inlineconstexpr

Definition at line 28 of file HelperFunctions.h.