Scine::Readuct  4.0.0
This is the SCINE module Readuct.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
NtOptimizationTask.h
Go to the documentation of this file.
1 
7 #ifndef READUCT_NTOPTIMIZATIONTASK_H_
8 #define READUCT_NTOPTIMIZATIONTASK_H_
9 
10 /* Readuct */
11 #include "Tasks/Task.h"
12 /* Scine */
15 #include <Utils/IO/Yaml.h>
16 /* External */
17 #include <boost/exception/diagnostic_information.hpp>
18 #include <boost/filesystem.hpp>
19 /* std c++ */
20 #include <cstdio>
21 #include <fstream>
22 #include <iostream>
23 
24 namespace Scine {
25 namespace Readuct {
26 
27 class NtOptimizationTask : public Task {
28  public:
35  NtOptimizationTask(std::vector<std::string> input, std::vector<std::string> output, std::shared_ptr<Core::Log> logger = nullptr)
36  : Task(std::move(input), std::move(output), std::move(logger)) {
37  }
38 
39  std::string name() const override {
40  return "NT1 Optimization";
41  }
42 
43  bool run(SystemsMap& systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly = false) const final {
46 
47  bool silentCalculator = taskSettings.extract("silent_stdout_calculator", true);
48  std::shared_ptr<Core::Calculator> calc;
49  if (!testRunOnly) { // leave out in case of task chaining --> attention calc is NULL
50  // Note: _input is guaranteed not to be empty by Task constructor
51  calc = copyCalculator(systems, _input.front(), name());
52  Utils::CalculationRoutines::setLog(*calc, true, true, !silentCalculator);
53 
54  // Check system size
55  if (calc->getStructure()->size() == 1) {
56  throw std::runtime_error("Cannot calculate NT1 optimization for monoatomic systems.");
57  }
58  }
59 
60  // Generate optimizer
61  auto optimizer = std::make_unique<Utils::NtOptimizer>(*calc);
62  // Read and delete special settings
63  bool stopOnError = stopOnErrorExtraction(taskSettings);
64  // Apply user settings
65  auto settings = optimizer->getSettings();
66  settings.merge(taskSettings);
67  if (!settings.valid()) {
68  settings.throwIncorrectSettings();
69  }
70  optimizer->setSettings(settings);
71 
72  // If no errors encountered until here, the basic settings should be alright
73  if (testRunOnly) {
74  return true;
75  }
76 
77  // Add observer
78  // Trajectory stream
79  using Writer = Utils::XyzStreamHandler;
80  const std::string& outputSystem = ((!_output.empty()) ? _output[0] : _input[0]);
81  boost::filesystem::path dir(outputSystem);
82  boost::filesystem::create_directory(dir);
83  boost::filesystem::path trjfile(outputSystem + ".nt.trj.xyz");
84  std::ofstream trajectory((dir / trjfile).string(), std::ofstream::out);
85  double oldEnergy = 0.0;
86  Eigen::VectorXd oldParams;
87  auto func = [&](const int& cycle, const double& energy, const Eigen::VectorXd& params) {
88  if (oldParams.size() != params.size()) {
89  oldParams = params;
90  }
91  if (cycle == 1) {
92  printf("%7s %16s %16s %16s %16s\n", "Cycle", "Energy", "Energy Diff.", "Step RMS", "Max. Step");
93  }
94  auto diff = (params - oldParams).eval();
95  printf("%7d %+16.9f %+16.9f %+16.9f %+16.9f\n", cycle, energy, energy - oldEnergy,
96  sqrt(diff.squaredNorm() / diff.size()), diff.cwiseAbs().maxCoeff());
97  oldEnergy = energy;
98  oldParams = params;
99  auto structure = calc->getStructure();
100  Writer::write(trajectory, *structure, std::to_string(energy));
101  };
102  optimizer->addObserver(func);
103  auto cout = _logger->output;
104 
105  // Run optimization
106  auto structure = calc->getStructure();
107  int cycles = 0;
108  try {
109  cycles = optimizer->optimize(*structure, *_logger);
110  }
111  catch (...) {
112  trajectory.close();
113  if (stopOnError) {
114  throw;
115  }
116  // check if thrown exception corresponds to no actual calculation failures but simply no guess found
117  // --> no thrown exception intended in this case if stopOnError equals false
118  std::string noGuess = "No transition state guess was found in Newton Trajectory scan";
119  size_t found = boost::current_exception_diagnostic_information().find(noGuess);
120  if (found == std::string::npos) { // did not find harmless exception -> throw
121  throw;
122  }
123  cout << Core::Log::endl << " No TS guess found in NT1 scan." << Core::Log::endl << Core::Log::endl;
124  return false;
125  }
126 
127  trajectory.close();
128 
129  cout << Core::Log::endl
130  << " Found TS guess after " << cycles << " iterations." << Core::Log::endl
131  << Core::Log::endl;
132 
133  // Print/Store results
134  systems[outputSystem] = calc;
135  boost::filesystem::path xyzfile(outputSystem + ".xyz");
136  std::ofstream xyz((dir / xyzfile).string(), std::ofstream::out);
137  Writer::write(xyz, *(calc->getStructure()));
138  xyz.close();
139 
140  return true;
141  }
142 };
143 
144 } // namespace Readuct
145 } // namespace Scine
146 
147 #endif // READUCT_NTOPTIMIZATIONTASK_H_
Definition: NtOptimizationTask.h:27
void warningIfMultipleOutputsGiven() const
Warn if more than one output system was specified.
Definition: Task.h:99
static std::ostream & endl(std::ostream &os)
NtOptimizationTask(std::vector< std::string > input, std::vector< std::string > output, std::shared_ptr< Core::Log > logger=nullptr)
Construct a new NtOptimizationTask.
Definition: NtOptimizationTask.h:35
const std::vector< std::string > & input() const
Getter for the expected names of the input systems.
Definition: Task.h:77
bool run(SystemsMap &systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly=false) const final
Executes the actual task represented by this class.
Definition: NtOptimizationTask.h:43
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
std::string name() const override
Getter for the tasks name.
Definition: NtOptimizationTask.h:39