Loading...
Searching...
No Matches
Parameters.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12#include "ParametersImpl.h"
13#include "eon/ParametersINI.h"
14#include "eon/ParametersJSON.h"
15#include "eon/ParametersSSOT.h"
16#include "magic_enum/magic_enum.hpp"
17
18#include <INIReader.h>
19
20#include <cctype>
21#include <cerrno>
22#include <cstdio>
23#include <cstring>
24#include <string_view>
25#include <utility>
26
27#include "eon/EonLogger.h"
28
29namespace {
30
31bool ams_engine_name_is(std::string_view got, std::string_view name) {
32 if (got.size() != name.size()) {
33 return false;
34 }
35 for (std::size_t i = 0; i < got.size(); ++i) {
36 const auto left = static_cast<unsigned char>(got[i]);
37 const auto right = static_cast<unsigned char>(name[i]);
38 if (std::toupper(left) != std::toupper(right)) {
39 return false;
40 }
41 }
42 return true;
43}
44
45} // namespace
46
47namespace eonc {
48
50 : impl_(std::make_unique<Impl>()) {
51 // Covered groups: defaults originate from schema/eon_params.capnp via
52 // apply_ssot_defaults (codegen). Uncovered groups still use NSDMI.
54 // Resolve computed fields via validate_and_link.
56}
57
58int Parameters::load(std::string_view filename) {
59 INIReader ini{std::string(filename)};
60 if (ini.ParseError() != 0) {
61 EONC_LOG_ERROR("Can't load INI file: {}", filename);
62 record_load(filename, 1);
63 return 1;
64 }
65
66 int error = eonc::config::load_ini(ini, *this);
67
68 // Sanity Checks
69 if (impl_->parallel_replica_options_.state_check_interval >
70 impl_->dynamics_options_.time &&
71 magic_enum::enum_name<JobType>(impl_->main_options_.job) ==
72 "parallel_replica") {
73 EONC_LOG_ERROR("[Parallel Replica] state_check_interval must be <= time");
74 error = 1;
75 }
76
77 if (!impl_->neb_options_.initialization.input_path.empty() &&
78 impl_->neb_options_.initialization.method == NEBInit::LINEAR) {
80 "[Nudged Elastic Band] 'initial_path_in' is provided, but "
81 "'initializer' defaults to linear. "
82 "Ensure this is intentional, as the loaded path will not be "
83 "used without initializer set to file.");
84 }
85
86 if (impl_->saddle_search_options_.dynamics.record_interval_input >
87 impl_->saddle_search_options_.dynamics.state_check_interval_input) {
88 EONC_LOG_ERROR("[Saddle Search] dynamics_record_interval must be <= "
89 "dynamics_state_check_interval");
90 error = 1;
91 }
92
93 if (impl_->potential_options_.potential == PotType::AMS ||
94 impl_->potential_options_.potential == PotType::AMS_IO) {
95 // generate_run allows DFTB with resources and FORCEFIELD alone.
96 const bool dftb_with_resources =
97 ams_engine_name_is(impl_->ams_options_.engine, "DFTB") &&
98 !impl_->ams_options_.resources.empty();
99 const bool forcefield_engine =
100 ams_engine_name_is(impl_->ams_options_.engine, "FORCEFIELD");
101 if (impl_->ams_options_.forcefield.empty() &&
102 impl_->ams_options_.model.empty() && impl_->ams_options_.xc.empty() &&
103 !dftb_with_resources && !forcefield_engine) {
104 EONC_LOG_ERROR("[AMS] Must provide atleast forcefield or model or xc");
105 error = 1;
106 }
107
108 if (!impl_->ams_options_.forcefield.empty() &&
109 !impl_->ams_options_.model.empty() && !impl_->ams_options_.xc.empty()) {
110 EONC_LOG_ERROR("[AMS] Must provide either forcefield or model");
111 error = 1;
112 }
113 }
114
115 record_load(filename, error);
116 return error;
117}
118
120 constexpr std::string_view kFileSource{"<FILE*>"};
121 if (!file) {
122 EONC_LOG_ERROR("Can't load INI from a null FILE*");
123 record_load(kFileSource, 1);
124 return 1;
125 }
126 if (fseek(file, 0, SEEK_END) != 0) {
127 EONC_LOG_ERROR("Can't seek INI FILE*");
128 record_load(kFileSource, 1);
129 return 1;
130 }
131 const long size = ftell(file);
132 if (size < 0) {
133 EONC_LOG_ERROR("Can't tell INI FILE* size");
134 record_load(kFileSource, 1);
135 return 1;
136 }
137 if (fseek(file, 0, SEEK_SET) != 0) {
138 EONC_LOG_ERROR("Can't rewind INI FILE*");
139 record_load(kFileSource, 1);
140 return 1;
141 }
142
143 std::string buffer(static_cast<size_t>(size), '\0');
144 if (fread(buffer.data(), 1, static_cast<size_t>(size), file) !=
145 static_cast<size_t>(size)) {
146 EONC_LOG_ERROR("Couldn't read the ini file from FILE*");
147 record_load(kFileSource, 1);
148 return 1;
149 }
150
151 INIReader ini(buffer.c_str(), buffer.size());
152 if (ini.ParseError() != 0) {
153 EONC_LOG_ERROR("Couldn't parse the ini file from FILE*");
154 record_load(kFileSource, 1);
155 return 1;
156 }
157
158 int error = eonc::config::load_ini(ini, *this);
159 // Same validation as the filename overload
160 // (duplicated intentionally for now; will be extracted to validate())
161 if (impl_->parallel_replica_options_.state_check_interval >
162 impl_->dynamics_options_.time &&
163 magic_enum::enum_name<JobType>(impl_->main_options_.job) ==
164 "parallel_replica") {
165 EONC_LOG_ERROR("[Parallel Replica] state_check_interval must be <= time");
166 error = 1;
167 }
168 if (impl_->saddle_search_options_.dynamics.record_interval_input >
169 impl_->saddle_search_options_.dynamics.state_check_interval_input) {
170 EONC_LOG_ERROR("[Saddle Search] dynamics_record_interval must be <= "
171 "dynamics_state_check_interval");
172 error = 1;
173 }
174 record_load(kFileSource, error);
175 return error;
176}
177
178int Parameters::load_ini_text(std::string_view ini_text) {
179 constexpr std::string_view kIniSource{"<ini>"};
180 INIReader ini(ini_text.data(), ini_text.size());
181 if (ini.ParseError() != 0) {
182 EONC_LOG_ERROR("Couldn't parse INI from memory");
183 record_load(kIniSource, 1);
184 return 1;
185 }
186 const int error = eonc::config::load_ini(ini, *this);
187 record_load(kIniSource, error);
188 return error;
189}
190
191int Parameters::load_json(std::string_view json_str) {
192 constexpr std::string_view kJsonSource{"<json>"};
193 const int error = eonc::config::load_json(json_str, *this);
194 record_load(kJsonSource, error);
195 return error;
196}
197
198std::string Parameters::to_json() const {
199 return eonc::config::to_json(*this).dump(2);
200}
201
202} // namespace eonc
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:261
#define EONC_LOG_WARNING(...)
Definition EonLogger.h:255
std::unique_ptr< Impl > impl_
Definition Parameters.h:157
std::string to_json() const
void record_load(std::string_view source, int error)
int load_ini_text(std::string_view ini_text)
int load(std::string_view filename)
int load_json(std::string_view json_str)
int load_ini(INIReader &ini, Parameters &params)
Parse all INI sections into the Parameters struct.
void apply_ssot_defaults(Parameters &p)
Apply SSoT defaults for covered groups (Main, Potential, Optimizer, Structure Comparison,...
int load_json(std::string_view json_str, Parameters &params)
Load Parameters from a JSON string. Returns 0 on success.
json to_json(const Parameters &p)
Serialize all Parameters to JSON.
void validate_and_link(Parameters &params)
Resolve cross-group defaults and time unit conversions.
RAII resource manager for the ARTn C library with global synchronization.