7 #ifndef READUCT_AFIROPTIMIZATIONTASK_H_
8 #define READUCT_AFIROPTIMIZATIONTASK_H_
21 #include <boost/exception/diagnostic_information.hpp>
22 #include <boost/filesystem.hpp>
40 :
Task(std::move(input), std::move(output), std::move(logger)) {
43 std::string
name()
const override {
44 return "AFIR Optimization";
51 bool silentCalculator = taskSettings.extract(
"silent_stdout_calculator",
true);
52 std::shared_ptr<Core::Calculator> calc;
55 calc = copyCalculator(systems, _input.front(),
name());
56 Utils::CalculationRoutines::setLog(*calc,
true,
true, !silentCalculator);
59 if (calc->getStructure()->size() == 1) {
60 throw std::runtime_error(
"Cannot calculate AFIR for monoatomic systems.");
65 auto optimizertype = taskSettings.extract(
"optimizer", std::string{
"BFGS"});
66 std::transform(optimizertype.begin(), optimizertype.end(), optimizertype.begin(), ::toupper);
67 std::shared_ptr<Utils::AfirOptimizerBase> optimizer;
68 if (optimizertype ==
"LBFGS") {
69 auto tmp = std::make_shared<Utils::AfirOptimizer<Utils::Lbfgs>>(*calc);
70 tmp->optimizer.useTrustRadius =
true;
71 tmp->optimizer.trustRadius = 0.1;
72 optimizer = std::move(tmp);
74 else if (optimizertype ==
"BFGS") {
75 auto tmp = std::make_shared<Utils::AfirOptimizer<Utils::Bfgs>>(*calc);
76 tmp->optimizer.useTrustRadius =
true;
77 tmp->optimizer.trustRadius = 0.1;
78 optimizer = std::move(tmp);
80 else if (optimizertype ==
"SD" || optimizertype ==
"STEEPESTDESCENT") {
81 auto tmp = std::make_shared<Utils::AfirOptimizer<Utils::SteepestDescent>>(*calc);
82 optimizer = std::move(tmp);
85 throw std::runtime_error(
"Unknown Optimizer requested for AFIR, available are: SD, BFGS and LBFGS!");
89 bool stopOnError = stopOnErrorExtraction(taskSettings);
92 auto settings = optimizer->getSettings();
93 settings.merge(taskSettings);
94 if (!settings.valid()) {
95 settings.throwIncorrectSettings();
97 optimizer->setSettings(settings);
98 if (!testRunOnly && !Utils::GeometryOptimization::settingsMakeSense(*optimizer)) {
99 throw std::logic_error(
"The given calculator settings are too inaccurate for the given convergence criteria of "
100 "this optimization Task");
111 const std::string& outputSystem = (!_output.empty() ? _output.front() : _input.front());
112 boost::filesystem::path dir(outputSystem);
113 boost::filesystem::create_directory(dir);
114 boost::filesystem::path trjfile(outputSystem +
".afir.trj.xyz");
115 std::ofstream trajectory((dir / trjfile).
string(), std::ofstream::out);
116 double oldEnergy = 0.0;
117 Eigen::VectorXd oldParams;
118 auto cout = _logger->output;
119 auto func = [&](
const int& cycle,
const double& energy,
const Eigen::VectorXd& params) {
120 if (oldParams.size() != params.size()) {
124 cout.printf(
"%7s %16s %16s %16s %16s\n",
"Cycle",
"Energy",
"Energy Diff.",
"Step RMS",
"Max. Step");
126 auto diff = (params - oldParams).eval();
127 cout.printf(
"%7d %+16.9f %+16.9f %+16.9f %+16.9f\n", cycle, energy, energy - oldEnergy,
128 sqrt(diff.squaredNorm() / diff.size()), diff.cwiseAbs().maxCoeff());
131 auto structure = calc->getStructure();
132 Writer::write(trajectory, *structure, std::to_string(energy));
134 optimizer->addObserver(func);
137 auto structure = calc->getStructure();
140 cycles = optimizer->optimize(*structure, *_logger);
143 Writer::write(trajectory, *calc->getStructure());
145 _logger->error <<
"AFIR Optimization failed with error!" <<
Core::Log::endl;
149 _logger->error << boost::current_exception_diagnostic_information() <<
Core::Log::endl;
154 int maxiter = settings.getInt(
"convergence_max_iterations");
155 if (maxiter > cycles) {
165 throw std::runtime_error(
"Problem: AFIR optimization did not converge.");
170 boost::filesystem::path xyzfile(outputSystem +
".xyz");
171 std::ofstream xyz((dir / xyzfile).
string(), std::ofstream::out);
172 Writer::write(xyz, *(calc->getStructure()));
174 systems[outputSystem] = std::move(calc);
176 return cycles < maxiter;
183 #endif // READUCT_AFIROPTIMIZATIONTASK_H_
std::string name() const override
Getter for the tasks name.
Definition: AfirOptimizationTask.h:43
void warningIfMultipleOutputsGiven() const
Warn if more than one output system was specified.
Definition: Task.h:99
bool run(SystemsMap &systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly=false) const final
Executes the actual task represented by this class.
Definition: AfirOptimizationTask.h:47
AfirOptimizationTask(std::vector< std::string > input, std::vector< std::string > output, std::shared_ptr< Core::Log > logger=nullptr)
Construct a new AfirOptimizationTask.
Definition: AfirOptimizationTask.h:39
static std::ostream & endl(std::ostream &os)
const std::vector< std::string > & input() const
Getter for the expected names of the input systems.
Definition: Task.h:77
Definition: AfirOptimizationTask.h:31
void warningIfMultipleInputsGiven() const
Warn if more than one input system was specified.
Definition: Task.h:90
const std::vector< std::string > & output() const
Getter for the names of the output systems generated by this task.
Definition: Task.h:84
The base class for all tasks in Readuct.
Definition: Task.h:28