Scine::Readuct  4.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) const final {
50 
51  // Read and delete special settings
52  bool stopOnError = stopOnErrorExtraction(taskSettings);
53  bool silentCalculator = taskSettings.extract("silent_stdout_calculator", true);
54  if (!taskSettings.empty()) {
55  throw std::logic_error(falseTaskSettingsErrorMessage(name()));
56  }
57 
58  // If no errors encountered until here, the basic settings should be alright
59  if (testRunOnly) {
60  return true;
61  }
62 
63  // Note: _input is guaranteed not to be empty by Task constructor
64  auto calc = copyCalculator(systems, _input.front(), name());
65  Utils::CalculationRoutines::setLog(*calc, true, true, !silentCalculator);
66 
67  // Check system size
68  if (calc->getStructure()->size() == 1) {
69  throw std::runtime_error("Cannot perform Hessian task for monoatomic systems.");
70  }
71 
72  // Get/calculate Hessian
73  if (!calc->results().has<Utils::Property::Hessian>() || !calc->results().has<Utils::Property::Thermochemistry>() ||
74  !calc->results().has<Utils::Property::Energy>()) {
75  calc->setRequiredProperties(Utils::Property::Hessian | Utils::Property::Thermochemistry | Utils::Property::Energy);
76  try {
77  calc->calculate(name());
78  if (!calc->results().get<Utils::Property::SuccessfulCalculation>()) {
79  throw std::runtime_error(name() + " was not successful");
80  }
81  }
82  catch (...) {
83  if (stopOnError) {
84  throw;
85  }
86  _logger->warning
87  << " " + name() + " was not successful with error:\n " + boost::current_exception_diagnostic_information()
88  << Core::Log::endl;
89  return false;
90  }
91  }
92  auto hessian = calc->results().get<Utils::Property::Hessian>();
93 
94  // Print frequencies
95  auto system = calc->getStructure();
97  Utils::NormalModeAnalysis::calculateNormalModes(hessian, system->getElements(), system->getPositions());
98  auto wavenumbers = modes.getWaveNumbers();
99  auto cout = _logger->output;
100  cout << " Vib. Frequencies:\n";
101  cout << " [Rot. and trans. vib. removed, imaginary freq. shown as negative.]\n\n";
102  cout.printf(" %4s %8s\n", "#", "cm^-1");
103  for (unsigned int i = 0; i < wavenumbers.size(); i++) {
104  cout.printf(" %4d %+8.1f\n", i + 1, wavenumbers[i]);
105  }
106  cout << Core::Log::endl;
107 
108  const std::string& outputSystem = (!_output.empty() ? _output[0] : _input[0]);
109 
110  // Setup output directory if needed
111  boost::filesystem::path dir(outputSystem);
112  if (wavenumbers[0] < 0.0) {
113  boost::filesystem::create_directory(dir);
114  }
115  // Print Imaginary modes
116  for (unsigned int i = 0; i < wavenumbers.size() && wavenumbers[i] < 0.0; ++i) {
117  auto trj = modes.getModeAsMolecularTrajectory(i, *system, 1.0);
118  std::string filename = Utils::format("%s.vibmode-%05d.trj.xyz", outputSystem.c_str(), i + 1);
119  std::ofstream xyz((dir / filename).string(), std::ofstream::out);
121  xyz.close();
122  }
123 
124  // Store result
125  systems[outputSystem] = calc;
126 
127  // Print thermochemistry results
128  auto thermo = calc->results().get<Utils::Property::Thermochemistry>();
129  double temp = calc->settings().getDouble("temperature");
130  cout << " Thermochemical Data:\n";
131  cout.printf(" %35s %+14.9f K\n", "Temperature (T):", temp);
132  cout.printf(" %35s %14d\n", "Molecular symmetry number:", thermo.overall.symmetryNumber);
133  cout.printf(" %35s %+14.9f E_h\n", "Zero Point Vibrational Energy:", thermo.overall.zeroPointVibrationalEnergy);
134  cout.printf(" %35s %+14.9f E_h/K\n", "Entropy (S):", thermo.overall.entropy);
135  cout.printf(" %35s %+14.9f E_h\n", "Entropy (-TS):", -temp * thermo.overall.entropy);
136  cout.printf(" %35s %+14.9f E_h\n", "Enthalpy (H):", thermo.overall.enthalpy);
137  double electronicEnergy = calc->results().get<Utils::Property::Energy>();
138  cout.printf(" %35s %+14.9f E_h\n", "Gibbs Energy Correction (dG):", thermo.overall.gibbsFreeEnergy - electronicEnergy);
139  cout.printf(" %35s %+14.9f E_h\n", "Electronic Energy (E):", electronicEnergy);
140  cout.printf(" %35s %+14.9f E_h\n", "Gibbs Energy (E + dG):", thermo.overall.gibbsFreeEnergy);
141  cout << Core::Log::endl << Core::Log::endl;
142 
143  return true;
144  }
145 };
146 
147 } // namespace Readuct
148 } // namespace Scine
149 
150 #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:99
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
bool run(SystemsMap &systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly=false) const final
Executes the actual task represented by this class.
Definition: HessianTask.h:47
static void write(format f, const std::string &fileName, const MolecularTrajectory &m)
std::vector< double > getWaveNumbers() const
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
MolecularTrajectory getModeAsMolecularTrajectory(int modeIndex, const Utils::AtomCollection &structure, double scalingFactor) const
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