60 std::cout << colorizer.heading(
"Compile-time features:") << std::endl;
62 std::istringstream stream(FEATURES_STRING);
64 while (std::getline(stream, line)) {
65 if (line.find(
": enabled") != std::string::npos) {
67 size_t colonPos = line.find(
": ");
68 if (colonPos != std::string::npos) {
69 std::string featureName = line.substr(0, colonPos + 2);
70 std::string status = line.substr(colonPos + 2);
71 std::cout << featureName << colorizer.warning(status) << std::endl;
73 std::cout << line << std::endl;
75 }
else if (line.find(
": disabled") != std::string::npos) {
77 size_t colonPos = line.find(
": ");
78 if (colonPos != std::string::npos) {
79 std::string featureName = line.substr(0, colonPos + 2);
80 std::string status = line.substr(colonPos + 2);
81 std::cout << featureName << colorizer.error(status) << std::endl;
83 std::cout << line << std::endl;
86 std::cout << line << std::endl;
94 bool sflag =
false, mflag =
false, pflag =
false, cflag =
false;
95 double optConvergedForce = 0.001;
96 std::string potential;
98 std::string confileout;
99 std::string optimizer(
"cg");
101#ifdef WITH_SERVE_MODE
102 std::optional<std::string> config_path;
103 std::optional<std::string> serve_spec;
106 std::optional<std::string> serve_host;
107 std::optional<uint16_t> serve_port;
108 std::optional<size_t> replicas;
109 std::optional<bool> gateway;
114 const char *progname = (argc ? argv[0] :
"eonclient");
116 Argum::Parser parser;
118 parser.add(Argum::Option(
"--help",
"-h")
119 .help(
"show this help message and exit")
122 auto helpText = parser.formatHelp(progname);
123 std::cout << colorizer.heading(
"eOn Client - Help")
125 std::cout << helpText;
126 std::exit(EXIT_SUCCESS);
129 parser.add(Argum::Option(
"--version",
"-v")
130 .help(
"Print version information")
132 std::cout << VERSION_STRING << std::endl;
133 std::exit(EXIT_SUCCESS);
136 parser.add(Argum::Option(
"--features")
137 .help(
"Print compile-time features")
140 std::exit(EXIT_SUCCESS);
143 parser.add(Argum::Option(
"--minimize",
"-m")
144 .help(
"Minimization of inputConfile saves to outputConfile")
145 .handler([&]() { mflag =
true; }));
147 parser.add(Argum::Option(
"--single",
"-s")
148 .help(
"Single point energy of inputConfile")
149 .handler([&]() { sflag =
true; }));
151 parser.add(Argum::Option(
"--compare",
"-c")
152 .help(
"Compare structures of inputConfile to outputConfile")
153 .handler([&]() { cflag =
true; }));
156 Argum::Option(
"--optimizer",
"-o")
158 .help(
"Optimization method")
159 .handler([&](
const std::string_view &value) { optimizer = value; }));
161 parser.add(Argum::Option(
"--force",
"-f")
163 .help(
"Convergence force")
164 .handler([&](
const std::string_view &value) {
165 optConvergedForce = Argum::parseFloatingPoint<double>(value);
169 Argum::Option(
"--tolerance",
"-t")
171 .help(
"Distance tolerance")
172 .handler([&](
const std::string_view &value) {
177 parser.add(Argum::Option(
"--potential",
"-p")
178 .argName(
"POTENTIAL")
179 .help(
"The potential (e.g. qsc, lj, eam_al)")
180 .handler([&](
const std::string_view &value) {
185#ifdef WITH_SERVE_MODE
187 Argum::Option(
"--serve")
189 .help(
"Serve potential(s) over rgpot Cap'n Proto RPC. "
190 "Spec: 'potential:port' or 'pot1:port1,pot2:port2'")
191 .handler([&](
const std::string_view &value) { serve_spec = value; }));
194 Argum::Option(
"--serve-host")
196 .help(
"Host to bind RPC server(s) to")
197 .handler([&](
const std::string_view &value) { serve_host = value; }));
199 parser.add(Argum::Option(
"--serve-port")
201 .help(
"Port for single-potential serve mode (used with -p)")
202 .handler([&](
const std::string_view &value) {
203 serve_port = Argum::parseIntegral<uint16_t>(value);
206 parser.add(Argum::Option(
"--replicas")
208 .help(
"Number of replicated server instances (used with -p)")
209 .handler([&](
const std::string_view &value) {
210 replicas = Argum::parseIntegral<size_t>(value);
213 parser.add(Argum::Option(
"--gateway")
214 .help(
"Run a single gateway port backed by N pool instances "
215 "(use with -p and --replicas)")
216 .handler([&]() { gateway =
true; }));
218 parser.add(Argum::Option(
"--config")
220 .help(
"Config file for potential parameters (INI format, "
221 "e.g. [Metatomic] model_path=model.pt)")
222 .handler([&](
const std::string_view &value) {
231 Argum::Positional(
"confile")
232 .help(
"Input structure file")
233 .occurs(Argum::zeroOrOneTime)
234 .handler([&](
const std::string_view &value) { confile = value; }));
237 Argum::Positional(
"confileout")
238 .help(
"Output structure file (optional)")
239 .occurs(Argum::zeroOrOneTime)
240 .handler([&](
const std::string_view &value) { confileout = value; }));
243 parser.parse(argc, argv);
244 }
catch (
const Argum::ParsingException &ex) {
245 std::cerr << colorizer.error(ex.message()) <<
'\n';
246 std::cerr << colorizer.warning(parser.formatUsage(progname)) <<
'\n';
247 std::exit(EXIT_FAILURE);
250 if (sflag && mflag) {
251 std::cerr << colorizer.error(
252 "Cannot specify both minimization and single point\n");
253 std::exit(EXIT_FAILURE);
256 if (!pflag && (sflag || mflag)) {
257 std::cerr << colorizer.error(
"Must specify a potential\n");
258 std::exit(EXIT_FAILURE);
261 if (cflag && confileout.empty()) {
262 std::cerr << colorizer.error(
263 "Comparison needs two structure files: the input con file and the "
264 "one to compare it against\n");
265 std::cerr << colorizer.warning(parser.formatUsage(progname)) <<
'\n';
266 std::exit(EXIT_FAILURE);
269#ifdef WITH_SERVE_MODE
272 if (config_path.has_value()) {
273 std::ifstream config_file(config_path.value());
274 if (!config_file.is_open()) {
275 std::cerr << colorizer.error(
"Cannot open config file: ")
276 << config_path.value() <<
'\n';
277 std::exit(EXIT_FAILURE);
279 params.load(config_path.value());
283 if (serve_spec.has_value()) {
285 if (endpoints.empty()) {
286 std::cerr << colorizer.error(
"No valid serve endpoints in spec: ")
287 << serve_spec.value() <<
'\n';
288 std::exit(EXIT_FAILURE);
291 std::exit(EXIT_SUCCESS);
296 if (pflag && !sflag && !mflag && !cflag &&
297 (serve_host.has_value() || serve_port.has_value() ||
298 replicas.has_value() || gateway.has_value())) {
299 for (
auto &ch : potential) {
300 ch = std::tolower(
static_cast<unsigned char>(ch));
303 magic_enum::enum_cast<PotType>(potential, magic_enum::case_insensitive)
305 auto host = serve_host.value_or(
"localhost");
306 auto port = serve_port.value_or(12345);
307 auto reps = replicas.value_or(1);
308 bool gw = gateway.value_or(
false);
312 }
else if (reps > 1) {
317 std::exit(EXIT_SUCCESS);
321 if (!pflag && !sflag && !mflag && !cflag && config_path.has_value() &&
322 !serve_spec.has_value() &&
327 std::exit(EXIT_SUCCESS);
332 if (confile.empty()) {
333 std::cerr << colorizer.error(
334 "At least one non-option argument is required: the con file\n");
335 std::cerr << colorizer.warning(parser.formatUsage(progname)) <<
'\n';
336 std::exit(EXIT_FAILURE);
340 for (
auto &ch : potential) {
341 ch = std::tolower(
static_cast<unsigned char>(ch));
347 magic_enum::enum_cast<PotType>(potential, magic_enum::case_insensitive)
353 magic_enum::enum_cast<OptType>(optimizer, magic_enum::case_insensitive)
367 auto matter = std::make_unique<Matter>(
pot, params);
368 auto matter2 = std::make_unique<Matter>(
pot, params);
370 std::cerr <<
"Failed to load " << confile << std::endl;
371 std::exit(EXIT_FAILURE);
377 minimize(std::move(matter), confileout);
380 std::cerr <<
"Failed to load " << confileout << std::endl;
381 std::exit(EXIT_FAILURE);
384 if (probe.
compare(*matter2,
true)) {
385 std::cout <<
"Structures match\n";
387 std::cout << colorizer.error(
"Structures do not match\n");