Scine::Readuct  5.0.0
This is the SCINE module ReaDuct.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
HessianTask.h
Go to the documentation of this file.
1 
7 #ifndef READUCT_HESSIANTASK_H_
8 #define READUCT_HESSIANTASK_H_
9 
10 /* Readuct */
11 #include "Tasks/Task.h"
12 /* Scine */
19 #include <Utils/Properties/Thermochemistry/ThermochemistryCalculator.h>
20 /* External */
21 #include "boost/exception/diagnostic_information.hpp"
22 #include <boost/filesystem.hpp>
23 /* std c++ */
24 #include <cstdio>
25 #include <fstream>
26 #include <iostream>
27 
28 namespace Scine {
29 namespace Readuct {
30 
31 class HessianTask : public Task {
32  public:
39  HessianTask(std::vector<std::string> input, std::vector<std::string> output, std::shared_ptr<Core::Log> logger = nullptr)
40  : Task(std::move(input), std::move(output), std::move(logger)) {
41  }
42 
43  std::string name() const override {
44  return "Hessian Calculation";
45  }
46 
47  bool run(SystemsMap& systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly = false,
48  std::vector<std::function<void(const int&, const Utils::AtomCollection&, const Utils::Results&, const std::string&)>>
49  observers = {}) const final {
52 
53  // Read and delete special settings
54  bool stopOnError = stopOnErrorExtraction(taskSettings);
55  bool silentCalculator = taskSettings.extract("silent_stdout_calculator", true);
56  if (!taskSettings.empty()) {
57  throw std::logic_error(falseTaskSettingsErrorMessage(name()));
58  }
59  if (observers.size() > 0) {
60  throw std::logic_error("HessianTask does not feature algorithm accepting observers, yet one was given");
61  }
62 
63  // If no errors encountered until here, the basic settings should be alright
64  if (testRunOnly) {
65  return true;
66  }
67 
68  // Note: _input is guaranteed not to be empty by Task constructor
69  auto calc = copyCalculator(systems, _input.front(), name());
70  Utils::CalculationRoutines::setLog(*calc, true, true, !silentCalculator);
71 
72  // Check system size
73  // ToDo: Remove as soon as all calculators are able to handle single atom systems.
74  if (calc->getStructure()->size() == 1) {
75  throw std::runtime_error("Cannot perform Hessian task for monoatomic systems.");
76  }
77 
78  // Get/calculate Hessian
79  if (!calc->results().has<Utils::Property::Hessian>() || !calc->results().has<Utils::Property::Thermochemistry>() ||
80  !calc->results().has<Utils::Property::Energy>()) {
81  calc->setRequiredProperties(Utils::Property::Hessian | Utils::Property::Thermochemistry | Utils::Property::Energy);
82  try {
83  calc->calculate(name());
84  if (!calc->results().get<Utils::Property::SuccessfulCalculation>()) {
85  throw std::runtime_error(name() + " was not successful");
86  }
87  }
88  catch (...) {
89  if (stopOnError) {
90  throw;
91  }
92  _logger->warning
93  << " " + name() + " was not successful with error:\n " + boost::current_exception_diagnostic_information()
94  << Core::Log::endl;
95  return false;
96  }
97  }
98  auto hessian = calc->results().get<Utils::Property::Hessian>();
99 
100  // Print frequencies
101  auto system = calc->getStructure();
102  Utils::NormalModesContainer modes =
103  Utils::NormalModeAnalysis::calculateNormalModes(hessian, system->getElements(), system->getPositions());
104  auto wavenumbers = modes.getWaveNumbers();
105  auto cout = _logger->output;
106  cout << " Vib. Frequencies:\n";
107  cout << " [Rot. and trans. vib. removed, imaginary freq. shown as negative.]\n\n";
108  cout.printf(" %4s %8s\n", "#", "cm^-1");
109  for (unsigned int i = 0; i < wavenumbers.size(); i++) {
110  cout.printf(" %4d %+8.1f\n", i + 1, wavenumbers[i]);
111  }
112  cout << Core::Log::endl;
113 
114  const std::string& outputSystem = (!_output.empty() ? _output[0] : _input[0]);
115 
116  // Setup output directory if needed
117  boost::filesystem::path dir(outputSystem);
118  if (wavenumbers[0] < 0.0) {
119  boost::filesystem::create_directory(dir);
120  }
121  // Print Imaginary modes
122  for (unsigned int i = 0; i < wavenumbers.size() && wavenumbers[i] < 0.0; ++i) {
123  auto trj = modes.getModeAsMolecularTrajectory(i, *system, 1.0);
124  std::string filename = Utils::format("%s.vibmode-%05d.trj.xyz", outputSystem.c_str(), i + 1);
125  std::ofstream xyz((dir / filename).string(), std::ofstream::out);
127  xyz.close();
128  }
129 
130  // Store result
131  systems[outputSystem] = calc;
132 
133  // Print thermochemistry results
134  auto thermo = calc->results().get<Utils::Property::Thermochemistry>();
135  double temp = calc->settings().getDouble("temperature");
136  double pressure = calc->settings().getDouble("pressure");
137  cout << " Thermochemical Data:\n";
138  cout.printf(" %35s %+14.9f K\n", "Temperature (T):", temp);
139  cout.printf(" %35s %+14.6f Pa\n", "Pressure (P):", pressure);
140  cout.printf(" %35s %14d\n", "Molecular symmetry number:", thermo.overall.symmetryNumber);
141  cout.printf(" %35s %+14.9f E_h\n", "Zero Point Vibrational Energy:", thermo.overall.zeroPointVibrationalEnergy);
142  cout.printf(" %35s %+14.9f E_h/K\n", "Entropy (S):", thermo.overall.entropy);
143  cout.printf(" %35s %+14.9f E_h\n", "Entropy (-TS):", -temp * thermo.overall.entropy);
144  cout.printf(" %35s %+14.9f E_h\n", "Enthalpy (H):", thermo.overall.enthalpy);
145  double electronicEnergy = calc->results().get<Utils::Property::Energy>();
146  cout.printf(" %35s %+14.9f E_h\n", "Gibbs Energy Correction (dG):", thermo.overall.gibbsFreeEnergy - electronicEnergy);
147  cout.printf(" %35s %+14.9f E_h\n", "Electronic Energy (E):", electronicEnergy);
148  cout.printf(" %35s %+14.9f E_h\n", "Gibbs Energy (E + dG):", thermo.overall.gibbsFreeEnergy);
149  cout << Core::Log::endl << Core::Log::endl;
150 
151  return true;
152  }
153 };
154 
155 } // namespace Readuct
156 } // namespace Scine
157 
158 #endif // READUCT_HESSIANTASK_H_
Definition: HessianTask.h:31
HessianTask(std::vector< std::string > input, std::vector< std::string > output, std::shared_ptr< Core::Log > logger=nullptr)
Construct a new HessianTask.
Definition: HessianTask.h:39
void warningIfMultipleOutputsGiven() const
Warn if more than one output system was specified.
Definition: Task.h:104
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:82
static void write(format f, const std::string &fileName, const MolecularTrajectory &m)
bool run(SystemsMap &systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly=false, std::vector< std::function< void(const int &, const Utils::AtomCollection &, const Utils::Results &, const std::string &)>> observers={}) const final
Executes the actual task represented by this class.
Definition: HessianTask.h:47
void warningIfMultipleInputsGiven() const
Warn if more than one input system was specified.
Definition: Task.h:95
const std::vector< std::string > & output() const
Getter for the names of the output systems generated by this task.
Definition: Task.h:89
The base class for all tasks in Readuct.
Definition: Task.h:28
std::string name() const override
Getter for the tasks name.
Definition: HessianTask.h:43