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< Job > makeJob (std::unique_ptr< Parameters > params, Runtime &runtime)
 Borrow: caller keeps Runtime alive.
std::unique_ptr< Job > makeJob (std::unique_ptr< Parameters > params, std::unique_ptr< Runtime > runtime)
 Own the unique_ptr Runtime.
std::unique_ptr< Job > makeJob (std::unique_ptr< Parameters > params, Runtime &&runtime)
 Own the rvalue Runtime.
std::unique_ptr< Job > makeJob (std::unique_ptr< Parameters > params)
 One-shot: Job owns a default Runtime.
std::shared_ptr< Potential > makePotential (const Parameters &params)
std::shared_ptr< Potential > makePotential (PotType ptype, const Parameters &params, Runtime &runtime)
std::shared_ptr< Potential > makePotential (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::optional< std::string > enterJobDirectory (std::string_view jobPath)
 Enter jobPath as the working directory.
bool stageReturnLog (std::string_view logHome, std::string_view name)
 Copy name from logHome into the current directory when that file is not already this directory's copy.
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)
bool applyClientDisplacement (Matter &target, const Matter &initial, const Parameters &params, AtomMatrix *modeOut)
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 four the optimizer-driven searches understand (norm, rms, max_atom, max_component).
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.

Variables

constexpr double pi = 3.14159265358979323846

Function Documentation

◆ applyClientDisplacement()

bool eonc::helpers::applyClientDisplacement ( Matter & target,
const Matter & initial,
const Parameters & params,
AtomMatrix * modeOut )

Definition at line 246 of file HelperFunctions.cpp.

249 {
250 using namespace eonc::EpiCenters;
251 const auto &opt = params.saddle_search_options();
252 const std::string &dtype = opt.displace_type;
253 if (dtype == DISP_LOAD) {
254 return false;
255 }
256
257 long epicenter = -1;
258 const double cutoff = params.structure_comparison_options().neighbor_cutoff;
259 if (dtype == DISP_LISTED_ATOMS) {
260 epicenter = listedAtomEpiCenter(&initial, opt.displace_atom_list);
261 } else if (dtype == DISP_RANDOM) {
262 epicenter = randomFreeAtomEpiCenter(&initial);
263 } else if (dtype == DISP_LAST_ATOM) {
264 epicenter = lastAtom(&initial);
265 } else if (dtype == DISP_MIN_COORDINATED) {
266 epicenter = minCoordinatedEpiCenter(&initial, cutoff);
267 } else if (dtype == DISP_NOT_FCC_OR_HCP) {
268 epicenter = cnaEpiCenter(&initial, cutoff);
269 } else {
270 return false;
271 }
272
273 target = initial;
274 const long n = initial.numberOfAtoms();
275 const double radius = opt.displace_radius;
276 const double mag = opt.displace_magnitude;
277 AtomMatrix pos = initial.getPositionsCopy();
278 AtomMatrix mode = AtomMatrix::Zero(n, 3);
279 for (long i = 0; i < n; ++i) {
280 if (initial.getFixed(i)) {
281 continue;
282 }
283 const double dist = (i == epicenter) ? 0.0 : initial.distance(epicenter, i);
284 if (dist <= radius) {
285 for (int a = 0; a < 3; ++a) {
286 mode(i, a) = eonc::rng::gaussRandom(0.0, mag);
287 }
288 }
289 }
290 const double norm = mode.norm();
291 if (norm > 0.0) {
292 pos += mode;
293 mode /= norm;
294 } else if (epicenter >= 0 && epicenter < n && !initial.getFixed(epicenter)) {
295 mode(epicenter, 0) = 1.0;
296 pos(epicenter, 0) += mag;
297 }
298 target.setPositions(pos);
299 if (modeOut != nullptr) {
300 *modeOut = std::move(mode);
301 }
302 return true;
303}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
void setPositions(const AtomMatrix &pos)
Definition Matter.cpp:350
long int numberOfAtoms() const
Definition Matter.cpp:273
AtomMatrix getPositionsCopy() const
Definition Matter.cpp:310
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:505
const saddle_search_options_t & saddle_search_options() const
const structure_comparison_options_t & structure_comparison_options() const
const char DISP_RANDOM[]
Definition EpiCenters.h:24
long lastAtom(const Matter *matter)
const char DISP_LISTED_ATOMS[]
Definition EpiCenters.h:25
long cnaEpiCenter(const Matter *matter, double neighborCutoff)
const char DISP_LOAD[]
Definition EpiCenters.h:20
long randomFreeAtomEpiCenter(const Matter *matter)
long listedAtomEpiCenter(const Matter *matter, const std::vector< long > &atomList)
long minCoordinatedEpiCenter(const Matter *matter, double neighborCutoff)
double gaussRandom(double avg, double std)

◆ 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 four the optimizer-driven searches understand (norm, rms, max_atom, max_component).

Single source of the accepted spellings.

Definition at line 355 of file HelperFunctions.cpp.

355 {
356 if (metric == "max_atom") {
357 return "Max atom force";
358 }
359 if (metric == "max_component") {
360 return "Max force comp";
361 }
362 if (metric == "norm") {
363 return "||Force||";
364 }
365 if (metric == "rms") {
366 return "RMS force";
367 }
368 return std::nullopt;
369}

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

◆ enterJobDirectory()

std::optional< std::string > eonc::helpers::enterJobDirectory ( std::string_view jobPath)

Enter jobPath as the working directory.

Returns nullopt on success. On failure the working directory is unchanged and the string is the filesystem error, so the caller must not run the job or report the path as finished.

Definition at line 80 of file HelperFunctions.cpp.

80 {
81 try {
82 std::filesystem::current_path(std::filesystem::path{jobPath});
83 } catch (const std::filesystem::filesystem_error &err) {
84 return std::string{err.what()};
85 }
86 return std::nullopt;
87}

◆ 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

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

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

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 112 of file GPRHelpers.cpp.

112 {
113 if (!matter) {
114 throw std::invalid_argument("eon_matter_to_atmconf: null Matter");
115 }
116 gpr::AtomsConfiguration atoms_config;
117 aux::ProblemSetUp problem_setup;
118 gpr::Index_t number_of_mov_atoms;
119 gpr::Index_t number_of_fro_atoms;
120 std::set<int> unique_atomtypes;
121 gpr::Index_t n_at;
122 std::vector<int> atomnrs;
123 std::unordered_map<int, int>
124 atype_to_gprd_atype;
127 int fake_atype;
128
129 atoms_config.clear();
130 // gpr_optim stores positions as row-major 1×(3N), matching AtomMatrix flat
131 // layout.
132 copyAtomMatrixToCoord(matter->getPositions(), atoms_config.positions);
133 const auto nAtoms = matter->numberOfAtoms();
134 atoms_config.is_frozen.resize(1, nAtoms);
135 atoms_config.id.resize(1, nAtoms);
136 atoms_config.atomicNrs.resize(1, nAtoms);
137 for (auto i = 0; i < nAtoms; i++) {
138 atomnrs.push_back(matter->getAtomicNr(i));
139 // Field matrices are 1×N; use (0, i). getFixed is bool → MOVING/FROZEN.
140 atoms_config.atomicNrs(0, i) = matter->getAtomicNr(i);
141 atoms_config.is_frozen(0, i) =
142 matter->getFixed(i) ? FROZEN_ATOM : MOVING_ATOM;
143 atoms_config.id(0, i) = static_cast<gpr::Index_t>(i + 1);
144 }
145
146 unique_atomtypes = std::set<int>(atomnrs.begin(), atomnrs.end());
147 n_at = unique_atomtypes.size();
148 fake_atype = 0;
149 for (auto uatom : unique_atomtypes) {
150 atype_to_gprd_atype.insert(
151 std::pair<int, int>(static_cast<int>(uatom), fake_atype));
152 fake_atype++;
153 }
154
155 number_of_mov_atoms = atoms_config.countMovingAtoms();
156 number_of_fro_atoms =
157 static_cast<gpr::Index_t>(atoms_config.is_frozen.size()) -
158 number_of_mov_atoms;
159
160 if (number_of_fro_atoms > 0 && number_of_mov_atoms > 0) {
161 // Resize structures for moving and frozen atoms
162 atoms_config.atoms_mov.resize(number_of_mov_atoms);
163 atoms_config.atoms_froz_inactive.resize(number_of_fro_atoms);
164
165 // Dense GPR types from the Z→0..n-1 map.
166 if (atype_to_gprd_atype.size() > 1) {
167 int mov_counter = 0;
168 int froz_inactive_counter = 0;
169 for (auto i = 0; i < nAtoms; i++) {
170 if (matter->getFixed(i)) {
173 atoms_config.atoms_froz_inactive.type(0, froz_inactive_counter) =
174 atype_to_gprd_atype.at(atomnrs[i]);
175 froz_inactive_counter++;
176 } else {
178 atoms_config.atoms_mov.type(0, mov_counter) =
179 atype_to_gprd_atype.at(atomnrs[i]);
180 mov_counter++;
181 }
182 }
183 }
186 else if (atype_to_gprd_atype.size() == 1) {
187 atoms_config.atoms_mov.type.setConstant(
188 atype_to_gprd_atype.at(atomnrs[0]));
189 atoms_config.atoms_froz_inactive.type.setConstant(
190 atype_to_gprd_atype.at(atomnrs[0]));
191 }
192 // Assign moving and frozen atoms and list all frozen atoms as inactive
193 gpr::Index_t counter_f = 0, counter_m = 0;
194 for (gpr::Index_t n = 0;
195 n < static_cast<gpr::Index_t>(atoms_config.is_frozen.size()); ++n) {
196 if (atoms_config.is_frozen(0, n) == MOVING_ATOM)
197 gpr::coord::set(atoms_config.atoms_mov.positions, 0, counter_m++,
198 gpr::coord::at(atoms_config.positions, n));
199 else
200 gpr::coord::set(atoms_config.atoms_froz_inactive.positions, 0,
201 counter_f++, gpr::coord::at(atoms_config.positions, n));
202 }
204 } else {
205 if (number_of_mov_atoms == 0) {
206 throw std::runtime_error("eon_matter_to_atmconf: no moving atoms");
207 }
210 atoms_config.atoms_mov.resize(number_of_mov_atoms);
211
212 // Dense GPR types from the Z→0..n-1 map.
213 if (atype_to_gprd_atype.size() > 1) {
214 int mov_counter = 0;
215 for (auto i = 0; i < nAtoms; i++) {
216 atoms_config.atoms_mov.type(0, mov_counter) =
217 atype_to_gprd_atype.at(atomnrs[i]);
218 mov_counter++;
219 }
220 }
223 else if (atype_to_gprd_atype.size() == 1) {
224 atoms_config.atoms_mov.type.setConstant(
225 atype_to_gprd_atype.at(atomnrs[0]));
226 }
227 }
228 // Pairtype indices for pairs of atomtypes (n_at x n_at)
229 // Active pairtypes are indexed as 0,1,...,n_pt-1. Inactive pairtypes are
230 // given index EMPTY.
231 atoms_config.pairtype.resize(n_at, n_at);
232 atoms_config.pairtype.setConstant(EMPTY);
233
234 // Set pairtype indices for moving+moving atom pairs (and update number of
235 // active pairtypes)
236 problem_setup.setPairtypeForMovingAtoms(
237 atoms_config.atoms_mov.type, atoms_config.n_pt, atoms_config.pairtype);
238
239 return atoms_config;
240}
const AtomMatrix & getPositions() const
Definition Matter.cpp:308
long getAtomicNr(long int atom) const
Definition Matter.cpp:495

◆ 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

◆ 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 26 of file GPRHelpers.cpp.

26 {
27 gpr::InputParameters p;
28 // Problem parameters
29 p.actdist_fro.value = parameters.gpr_dimer_options().active_radius;
30 p.dimer_sep.value = parameters.gpr_dimer_options().dimer_sep;
31 p.method_rot.value = parameters.gpr_dimer_options().rot_opt_method;
32 p.method_trans.value = parameters.gpr_dimer_options().trans_opt_method;
33 p.param_trans.value[0] = parameters.gpr_dimer_options().conv_step;
34 p.param_trans.value[1] = parameters.gpr_dimer_options().max_step;
35 // Saddle point convergence parameter
36 p.T_dimer.value = parameters.saddle_search_options().converged_force;
37 p.T_anglerot_init.value = parameters.gpr_dimer_options().converged_angle;
38 // ---
39 p.initrot_nogp.value = parameters.gpr_dimer_options().init_rot_gp;
40 p.num_iter_initrot.value = parameters.gpr_dimer_options().init_rotations_max;
41 // unused except in the capnp for now
42 // p.inittrans_nogp.value = parameters.gpr_dimer_options().init_trans_gp;
43 p.T_anglerot_gp.value = parameters.gpr_dimer_options().relax_conv_angle;
44 p.num_iter_rot_gp.value = parameters.gpr_dimer_options().relax_rotations_max;
45 p.divisor_T_dimer_gp.value =
47 p.disp_max.value = parameters.gpr_dimer_options().midpoint_max_disp;
48 p.ratio_at_limit.value = parameters.gpr_dimer_options().ratio_at_limit;
49 p.num_bigiter.value = parameters.gpr_dimer_options().max_outer_iterations;
50 p.num_iter.value = parameters.gpr_dimer_options().max_inner_iterations;
51 p.islarge_num_iter.value = parameters.gpr_dimer_options().many_iterations;
52 // GPR Parameters
53 p.gp_sigma2.value = parameters.gpr_dimer_options().gpr_params.sigma2;
54 p.jitter_sigma2.value =
56 p.sigma2.value = parameters.gpr_dimer_options().gpr_params.noise_sigma2;
57 p.prior_mu.value = parameters.gpr_dimer_options().gpr_params.prior_mu;
58 p.prior_nu.value = parameters.gpr_dimer_options().gpr_params.prior_nu;
59 p.prior_s2.value = parameters.gpr_dimer_options().gpr_params.prior_sigma2;
60 // gpr_optim enables the check only when this string equals "true".
61 // A bool assigns as one char, so the flag never turns on.
62 p.check_derivative.value =
64 : "false";
65 p.max_iter.value = parameters.gpr_dimer_options().opt_params.max_iterations;
66 p.tolerance_func.value = parameters.gpr_dimer_options().opt_params.tol_func;
67 p.tolerance_sol.value = parameters.gpr_dimer_options().opt_params.tol_sol;
68 p.lambda_limit.value = parameters.gpr_dimer_options().opt_params.lambda_limit;
69 p.lambda.value = parameters.gpr_dimer_options().opt_params.lambda_init;
70 // Prune
71 p.use_prune.value = parameters.gpr_dimer_options().prune_params.use_prune;
72 p.start_prune_at.value = parameters.gpr_dimer_options().prune_params.begin;
73 p.nprune_vals.value = parameters.gpr_dimer_options().prune_params.n_vals;
74 p.prune_threshold.value =
76 // Debugging
77 p.report_level.value =
79 p.debug_level.value = parameters.gpr_dimer_options().debug_params.debug_level;
80 p.debug_output_dir.value =
82 p.debug_output_file_R.value =
84 p.debug_output_file_E.value =
86 p.debug_output_file_G.value =
88 p.debug_output_file_extension.value =
90 p.debug_offset_from_mid_point.value =
92 p.debug_dy.value = parameters.gpr_dimer_options().debug_params.dy;
93 p.debug_dz.value = parameters.gpr_dimer_options().debug_params.dz;
94 return p;
95}
const gpr_dimer_options_t & gpr_dimer_options() const
struct eonc::gpr_dimer_options_t::prune_params_t prune_params
struct eonc::gpr_dimer_options_t::gpr_params_t gpr_params
struct eonc::gpr_dimer_options_t::debug_params_t debug_params
struct eonc::gpr_dimer_options_t::opt_params_t opt_params

◆ existsFile()

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

Definition at line 75 of file HelperFunctions.cpp.

75 {
76 return std::filesystem::exists(filename);
77}

◆ 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 46 of file StringHelpers.cc.

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

◆ 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 9 of file StringHelpers.cc.

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

◆ getRelevantFile()

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

Definition at line 122 of file HelperFunctions.cpp.

122 {
123 const auto dot = filename.rfind('.');
124 const std::string prefix =
125 (dot == std::string::npos) ? filename : filename.substr(0, dot);
126 const std::string postfix =
127 (dot == std::string::npos) ? std::string{} : filename.substr(dot);
128 std::string filenameRelevant = prefix + "_cp" + postfix;
129 if (existsFile(filenameRelevant)) {
130 return filenameRelevant;
131 }
132 filenameRelevant = prefix + "_in" + postfix;
133 if (existsFile(filenameRelevant)) {
134 return filenameRelevant;
135 }
136 return filename;
137}
bool existsFile(std::string filename)

◆ getTime()

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

Definition at line 47 of file HelperFunctions.cpp.

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

◆ isNumber()

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

Figure out if a string has a number in it.

Based on

Definition at line 53 of file StringHelpers.cc.

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

◆ loadMasses()

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

Definition at line 139 of file HelperFunctions.cpp.

139 {
140 std::ifstream massFile(filename.c_str());
141 if (!massFile.is_open()) {
142 EONC_LOG_CRITICAL("File {} was not found", filename);
143 throw std::runtime_error(std::format("cannot open {}", filename));
144 }
145
146 VectorXd masses(nAtoms);
147 for (int i = 0; i < nAtoms; i++) {
148 double mass;
149 if (!(massFile >> mass)) {
150 EONC_LOG_CRITICAL("Error reading {}", filename);
151 throw std::runtime_error(
152 std::format("{} ended after {} of {} masses", filename, i, nAtoms));
153 }
154 masses(i) = mass;
155 }
156
157 massFile.close();
158
159 return masses;
160}
#define EONC_LOG_CRITICAL(...)
Definition EonLogger.h:267

◆ loadMode() [1/2]

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

Definition at line 162 of file HelperFunctions.cpp.

162 {
163 AtomMatrix mode;
164 mode.resize(nAtoms, 3);
165 mode.setZero();
166 for (int i = 0; i < nAtoms; i++) {
167 if (fscanf(modeFile, "%lf %lf %lf", &mode(i, 0), &mode(i, 1),
168 &mode(i, 2)) != 3) {
169 EONC_LOG_CRITICAL("Mode file ended after {} of {} atoms", i, nAtoms);
170 throw std::runtime_error(
171 std::format("mode file ended after {} of {} atoms", i, nAtoms));
172 }
173 }
174 return mode;
175}

◆ loadMode() [2/2]

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

Definition at line 177 of file HelperFunctions.cpp.

177 {
178 // Unique FILE* with RAII cleanup
179 auto closer = [](FILE *f) {
180 if (f)
181 std::fclose(f);
182 };
183 std::unique_ptr<FILE, decltype(closer)> modeFile(
184 std::fopen(filename.c_str(), "rb"), closer);
185 if (!modeFile) {
186 EONC_LOG_CRITICAL("File {} was not found", filename);
187 throw std::runtime_error(std::format("cannot open {}", filename));
188 }
189 return loadMode(modeFile.get(), nAtoms);
190}
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 192 of file HelperFunctions.cpp.

194 {
195 if (eonc::io::io_ok(target.con2matter(displacementPath))) {
196 if (target.numberOfAtoms() != initial.numberOfAtoms()) {
197 EONC_LOG_ERROR("{} holds {} atoms, the initial structure has {}",
198 displacementPath, target.numberOfAtoms(),
199 initial.numberOfAtoms());
200 return false;
201 }
202 // displacement.con may carry stale fixed-atom coordinates from a prior run.
203 // It also usually has sequential column-5 ids; keep the reactant's.
204 const AtomMatrix &initPos = initial.getPositions();
205 AtomMatrix pos = target.getPositionsCopy();
206 const long n = initial.numberOfAtoms();
207 std::vector<long> fileMap(static_cast<size_t>(n));
208 for (long i = 0; i < n; i++) {
209 if (initial.getFixed(i)) {
210 pos.row(i) = initPos.row(i);
211 }
212 target.setAtomIndex(i, initial.getAtomIndex(i));
213 fileMap[static_cast<size_t>(i)] = initial.mapFileRow(i);
214 }
215 target.setFileToMatter(std::move(fileMap));
216 target.setPositions(pos);
217 return true;
218 }
219 if (!existsFile(modePath)) {
220 return false;
221 }
222 AtomMatrix mode =
223 loadMode(modePath, static_cast<int>(initial.numberOfAtoms()));
224 const double norm = mode.norm();
225 if (!(norm > 0.0)) {
226 return false;
227 }
228 mode *= (scale / norm);
229 target = initial;
230 AtomMatrix pos = initial.getPositionsCopy();
231 pos += mode;
232 const AtomMatrix &initPos = initial.getPositions();
233 const long n = initial.numberOfAtoms();
234 for (long i = 0; i < n; i++) {
235 if (initial.getFixed(i)) {
236 pos.row(i) = initPos.row(i);
237 }
238 }
239 target.setPositions(pos);
240 EONC_LOG_INFO("Synthesized displacement from pos.con + scale {:.6g} * unit "
241 "mode in {} (missing {})",
242 scale, modePath, displacementPath);
243 return true;
244}
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:261
#define EONC_LOG_INFO(...)
Definition EonLogger.h:249
void setAtomIndex(long int atom, std::int64_t index)
Definition Matter.cpp:830
long mapFileRow(long file_row) const
Map a CON file-order row onto the Matter row after matter_order.
Definition Matter.h:293
std::int64_t getAtomIndex(long int atom) const
.con column-5 index (pre-grouping); public for I/O / bindings.
Definition Matter.cpp:826
void setFileToMatter(std::vector< long > map)
Definition Matter.h:300
io::IoStatus con2matter(std::string filename)
Definition Matter.h:256
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ makeJob() [1/4]

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

One-shot: Job owns a default Runtime.

Definition at line 65 of file JobRegistry.cpp.

65 {
66 return makeJob(std::move(params), std::make_unique<Runtime>());
67}
std::unique_ptr< Job > makeJob(std::unique_ptr< Parameters > params, Runtime &runtime)
Borrow: caller keeps Runtime alive.

◆ makeJob() [2/4]

std::unique_ptr< Job > eonc::helpers::makeJob ( std::unique_ptr< Parameters > params,
Runtime && runtime )

Own the rvalue Runtime.

Definition at line 59 of file JobRegistry.cpp.

60 {
61 return makeJob(std::move(params),
62 std::make_unique<Runtime>(std::move(runtime)));
63}

◆ makeJob() [3/4]

std::unique_ptr< Job > eonc::helpers::makeJob ( std::unique_ptr< Parameters > params,
Runtime & runtime )

Borrow: caller keeps Runtime alive.

Definition at line 43 of file JobRegistry.cpp.

44 {
45 return makeJobFromFactory(std::move(params), runtime);
46}

◆ makeJob() [4/4]

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

Own the unique_ptr Runtime.

Definition at line 48 of file JobRegistry.cpp.

49 {
50 if (!runtime) {
51 throw std::logic_error("makeJob: null Runtime");
52 }
53 Runtime &ref = *runtime;
54 auto job = makeJobFromFactory(std::move(params), ref);
55 job->adoptRuntime(std::move(runtime));
56 return job;
57}
Move-only composition root for process resources (dlopen loaders and the potential registry).
Definition Runtime.h:27

◆ makeOrthogonal()

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

Definition at line 42 of file HelperFunctions.cpp.

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

◆ makePotential() [1/3]

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

Definition at line 246 of file Potential.cpp.

246 {
247 return makePotential(params.potential_options().potential, params);
248}
const potential_options_t & potential_options() const
std::shared_ptr< Potential > makePotential(const Parameters &params)

◆ makePotential() [2/3]

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

Definition at line 255 of file Potential.cpp.

256 {
257 // Inject config-file path before any potential constructor runs.
258 // Called on every code path including Job::Job which uses this overload.
261 switch (ptype) {
262 // TODO: Every potential must know their own type
263 case PotType::EMT: {
264 return (std::make_shared<EffectiveMediumTheory>(params));
265 break;
266 }
267 case PotType::EXT_POT: {
268 return (std::make_shared<ExtPot>(params));
269 break;
270 }
271 case PotType::LJ: {
272 return makeRgpot<rgpot::LJPot>(PotType::LJ, params, rgpot::LJConfig{});
273 break;
274 }
275 case PotType::LJCLUSTER: {
277 rgpot::LJClusterConfig{});
278 break;
279 }
280 case PotType::MORSE_PT: {
282 rgpot::MorseConfig{});
283 break;
284 }
285#ifdef CUH2_POT
286 case PotType::CUH2: {
288 break;
289 }
290#endif
291#ifdef WITH_WATER
292 case PotType::TIP4P: {
293 return (std::make_shared<Tip4p>(params));
294 break;
295 }
296 case PotType::SPCE: {
297 return (std::make_shared<SpceCcl>(params));
298 break;
299 }
300#ifdef WITH_FORTRAN
301 case PotType::TIP4P_PT: {
302 return (std::make_shared<Tip4p_Pt>(params));
303 break;
304 }
305 case PotType::TIP4P_H: {
307 params);
308 break;
309 }
310#endif
311#endif
312 // Fortran potentials: always available, loaded at runtime via dlopen
313 case PotType::EAM_AL: {
315 params);
316 break;
317 }
318 case PotType::EDIP: {
320 break;
321 }
322 case PotType::FEHE: {
324 break;
325 }
326 case PotType::LENOSKY_SI: {
328 params);
329 break;
330 }
331 case PotType::SW_SI: {
333 break;
334 }
335 case PotType::TERSOFF_SI: {
337 params);
338 break;
339 }
340#ifndef _WIN32
341#ifdef WITH_VASP
342 case PotType::VASP: {
343 return (std::make_shared<VASP>(params));
344 break;
345 }
346#endif
347#endif
348 case PotType::LAMMPS: {
349 return std::make_shared<LAMMPSPot>(params);
350 }
351#ifdef EONMPI
352 case PotType::MPI: {
353 return (std::make_shared<MPIPot>(params));
354 break;
355 }
356#endif
357#ifdef EMBED_PYTHON
358#ifdef WITH_ASE_POT
359 case PotType::ASE_POT: {
360 return (std::make_shared<ASE>(params));
361 break;
362 }
363#endif
364#endif
365#ifdef WITH_AMS
366 case PotType::AMS: {
367 return (std::make_shared<AMS>(params));
368 break;
369 }
370 case PotType::AMS_IO: {
371 return (std::make_shared<AMS_IO>(params));
372 break;
373 }
374#endif
375#ifdef WITH_CATLEARN
376 case PotType::CatLearn: {
377 return (std::make_shared<CatLearnPot>(params));
378 break;
379 }
380#endif
381// TODO: Handle Fortran interaction
382#ifdef WITH_XTB
383 case PotType::XTB: {
384 return (std::make_shared<XTBPot>(params));
385 break;
386 }
387#endif
388#ifdef WITH_ASE_ORCA
389 case PotType::ASE_ORCA: {
390 return (std::make_shared<ASEOrcaPot>(params));
391 break;
392 }
393#endif
394#ifdef WITH_ASE_NWCHEM
395 case PotType::ASE_NWCHEM: {
396 return (std::make_shared<ASENwchemPot>(params));
397 break;
398 }
399#endif
400#ifdef WITH_METATOMIC
401 case PotType::METATOMIC: {
402 return (std::make_shared<MetatomicPotential>(params));
403 break;
404 }
405#endif
406#ifdef RGPOT_HAS_DFTD3
407 case PotType::DFTD3: {
408 rgpot::D3Damping damp = rgpot::D3Damping::BJ;
409 std::string dname = params.dftd_options().d3_damping;
410 for (char &c : dname) {
411 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
412 }
413 if (dname == "zero") {
414 damp = rgpot::D3Damping::Zero;
415 }
417 PotType::DFTD3, params,
418 rgpot::D3Config{.damping = damp,
419 .functional = params.dftd_options().functional,
420 .atm = params.dftd_options().atm});
421 break;
422 }
423#endif
424#ifdef RGPOT_HAS_DFTD4
425 case PotType::DFTD4: {
427 PotType::DFTD4, params,
428 rgpot::D4Config{.functional = params.dftd_options().functional,
429 .charge = params.dftd_options().d4_charge,
430 .atm = params.dftd_options().atm});
431 break;
432 }
433#endif
434 case PotType::ZBL: {
436 PotType::ZBL, params,
437 rgpot::ZBLConfig{
438 .cut_inner = params.zbl_options().cut_inner,
439 .cut_global = params.zbl_options().cut_global,
440 });
441 break;
442 }
443#ifndef IS_WINDOWS
445 return (std::make_shared<SocketNWChemPot>(params));
446 break;
447 }
448#endif
449#ifdef WITH_RGPOT
450 case PotType::RGPOT: {
451 return (std::make_shared<RgpotPot>(params));
452 break;
453 }
454#endif
455 case PotType::MOPAC: {
457 PotType::MOPAC, params,
458 rgpot::MOPACPot::Config{
459 .charge = params.mopac_options().charge,
460 .spin = params.mopac_options().spin,
461 .model = params.mopac_options().model,
462 .engine_path = params.mopac_options().engine_path,
463 });
464 break;
465 }
466#ifdef RGPOT_HAS_EXPR
467 case PotType::EXPR: {
468 if (params.expr_options().expression.empty()) {
469 throw std::runtime_error(
470 "ExprPot needs [ExprPot] expression, e.g. 0.5*lj + d3");
471 }
472 rgpot::ExprPot expr(params.expr_options().expression,
473 parse_expr_terms(params));
474 return std::make_shared<RgpotAdapter<rgpot::ExprPot>>(PotType::EXPR, params,
475 std::move(expr));
476 break;
477 }
478#endif
479 default:
480 EONC_LOG_ERROR("No known potential could be constructed from {}",
481 magic_enum::enum_name(ptype));
482 eonc::log::get()->flush_log();
483 throw std::runtime_error("Terminating");
484 break;
485 }
486}
std::shared_ptr< eonc::Potential > makeRgpotDefault(eonc::PotType ptype, const eonc::Parameters &params)
Factory arm helper for kernels whose parameters are fixed tabulated data with no eOn-side configurati...
std::shared_ptr< eonc::Potential > makeRgpot(eonc::PotType ptype, const eonc::Parameters &params, const Cfg &cfg)
Factory arm helper: construct the kernel from its config and wrap it.
const expr_options_t & expr_options() const
const zbl_options_t & zbl_options() const
const mopac_options_t & mopac_options() const
const dftd_options_t & dftd_options() const
void add_config_paths(const std::string &colon_paths) override
Inject search paths from the eOn config file.
static PluginLoader & instance()
Thread-safe singleton accessor (Meyer's pattern).
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition EonLogger.h:44

◆ makePotential() [3/3]

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

Definition at line 250 of file Potential.cpp.

250 {
251 PotentialConstructionScope scope(runtime.pots());
253 return makePotential(ptype, params);
254}
RAII: Potential default construction records on this registry instead of PotRegistry::get().
Definition Potential.h:30
PotRegistry & pots() noexcept
Definition Runtime.cpp:33
PluginLoader & plugins() noexcept
Definition Runtime.cpp:39

◆ 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 447 of file HelperFunctions.cpp.

451 {
452 eonc::log::Scoped m_log;
453 auto objf = std::make_shared<MatterObjectiveFunction>(matter, params);
455 objf, params.optimizer_options().method, params);
456
457 std::ostringstream min;
458 min << prefixMovie;
459 std::string minDatFilename = prefixMovie + ".dat";
460 auto write_movie_frame = [&](uint64_t frameIndex, bool append,
461 double stepSize) {
463 metadata.frame_index = frameIndex;
464 metadata.energy = matter.getPotentialEnergy();
465 metadata.scalars.push_back({"step_size", stepSize});
466 metadata.scalars.push_back({"convergence", objf->getConvergence()});
467 if (outFrames) {
468 outFrames->push_back(eonc::io::matterToConFrame(matter, &metadata));
469 }
470 if (writeMovie) {
471 if (!eonc::io::io_ok(matter.matter2con(min.str(), append, &metadata))) {
472 QUILL_LOG_WARNING(m_log, "Failed to write movie frame {}", min.str());
473 }
474 }
475
477 std::ofstream minDat(minDatFilename,
478 append ? (std::ios::binary | std::ios::app)
479 : std::ios::binary);
480 if (minDat) {
481 if (!append) {
482 minDat << "iteration\tstep_size\tconvergence\tenergy\n";
483 }
484 minDat << std::format("{}\t{:.5e}\t{:.5e}\t{:.6f}\n", frameIndex,
485 stepSize, objf->getConvergence(),
486 matter.getPotentialEnergy());
487 }
488 }
489 };
490 if (writeMovie || outFrames) {
491 write_movie_frame(0, false, 0.0);
492 }
493
494 int iteration = 0;
495 if (!quiet) {
496 QUILL_LOG_DEBUG(m_log, "{} {:10s} {:14s} {:18s} {:13s}\n", "[Matter]",
497 "Iter", "Step size",
499 "Energy");
500 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}\n",
501 "[Matter]", iteration, 0.0, objf->getConvergence(),
502 matter.getPotentialEnergy());
503 }
504
505 while (!objf->isConverged() &&
506 iteration < params.optimizer_options().max_iterations) {
507
508 AtomMatrix pos = matter.getPositions();
509
510 optim->step(params.optimizer_options().max_move);
511 iteration++;
512
513 double stepSize =
514 eonc::geometry::maxAtomMotion(matter.pbc(matter.getPositions() - pos));
515
516 if (!quiet) {
517 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
518 "[Matter]", iteration, stepSize, objf->getConvergence(),
519 matter.getPotentialEnergy());
520 }
521
522 if (writeMovie || outFrames) {
523 write_movie_frame(static_cast<uint64_t>(iteration), true, stepSize);
524 }
525
526 if (checkpoint) {
527 std::ostringstream chk;
528 chk << prefixCheckpoint << "_cp";
529 if (!eonc::io::io_ok(matter.matter2con(chk.str(), false))) {
530 QUILL_LOG_WARNING(m_log, "Failed to write checkpoint {}", chk.str());
531 }
532 }
533 }
534
535 if (iteration == 0) {
536 if (!quiet) {
537 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
538 "[Matter]", iteration, 0.0, objf->getConvergence(),
539 matter.getPotentialEnergy());
540 }
541 }
542 return objf->isConverged();
543}
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.cpp:810
double getPotentialEnergy() const
Definition Matter.cpp:554
io::IoStatus matter2con(std::string filename, bool append=false, const io::ConFrameMetadata *metadata=nullptr)
Definition Matter.h:268
const debug_options_t & debug_options() const
const optimizer_options_t & optimizer_options() const
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:24
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 371 of file HelperFunctions.cpp.

372 {
373 if (convergenceMetricLabel(metric)) {
374 return;
375 }
376 throw std::invalid_argument(
377 std::format("{} unknown convergence_metric: {}", context, metric));
378}
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 four the optimi...

◆ saveMode() [1/2]

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

Definition at line 316 of file HelperFunctions.cpp.

317 {
318 std::ofstream out(filename);
319 if (!out)
320 return;
321 const AtomMatrix free = matter->getFree();
322 long const nAtoms = matter->numberOfAtoms();
323 for (long i = 0; i < nAtoms; ++i) {
324 out << std::format("{:.17g}\t{:.17g}\t{:.17g}\n", free(i, 0) * mode(i, 0),
325 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
326 }
327}

◆ 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 305 of file HelperFunctions.cpp.

306 {
307 const AtomMatrix free = matter->getFree();
308 long const nAtoms = matter->numberOfAtoms();
309 for (long i = 0; i < nAtoms; ++i) {
310 fprintf(modeFile, "%.17g\t%.17g\t%.17g\n", free(i, 0) * mode(i, 0),
311 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
312 }
313 return;
314}

◆ split_string_int()

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

Definition at line 329 of file HelperFunctions.cpp.

330 {
331 std::vector<int> list;
332 if (s.empty())
333 return list;
334
335 size_t start = 0;
336 size_t end = s.find_first_of(delim);
337 while (start < s.size()) {
338 auto token = s.substr(start, end - start);
339 if (!token.empty()) {
340 try {
341 list.push_back(std::stoi(token));
342 } catch (const std::exception &) {
343 return {}; // Parse error
344 }
345 }
346 if (end == std::string::npos)
347 break;
348 start = end + 1;
349 end = s.find_first_of(delim, start);
350 }
351 return list;
352}

◆ stageReturnLog()

bool eonc::helpers::stageReturnLog ( std::string_view logHome,
std::string_view name )

Copy name from logHome into the current directory when that file is not already this directory's copy.

True only when a regular file of that name is then present.

Definition at line 89 of file HelperFunctions.cpp.

90 {
91 namespace fs = std::filesystem;
92 if (name.empty() || name == "." || name == ".." ||
93 name.find('/') != std::string_view::npos ||
94 name.find('\\') != std::string_view::npos) {
95 return false;
96 }
97 const fs::path dest{std::string{name}};
98 std::error_code ec;
99 const bool destFile = fs::is_regular_file(dest, ec);
100 if (logHome.empty()) {
101 return destFile;
102 }
103 const fs::path src = fs::path{std::string{logHome}} / dest.filename();
104 ec.clear();
105 if (!fs::is_regular_file(src, ec)) {
106 return destFile;
107 }
108 ec.clear();
109 if (destFile && fs::equivalent(src, dest, ec)) {
110 return true;
111 }
112 ec.clear();
113 fs::copy_file(src, dest, fs::copy_options::overwrite_existing, ec);
114 if (ec) {
115 EONC_LOG_ERROR("stageReturnLog: cannot copy {} to {}: {}", src.string(),
116 dest.string(), ec.message());
117 return fs::is_regular_file(dest);
118 }
119 return true;
120}

Variable Documentation

◆ pi

double eonc::helpers::pi = 3.14159265358979323846
inlineconstexpr

Definition at line 29 of file HelperFunctions.h.