7 #ifndef READUCT_HESSIANTASK_H_
8 #define READUCT_HESSIANTASK_H_
20 #include <Utils/Properties/Thermochemistry/ThermochemistryCalculator.h>
22 #include "boost/exception/diagnostic_information.hpp"
23 #include <boost/filesystem.hpp>
40 HessianTask(std::vector<std::string>
input, std::vector<std::string>
output, std::shared_ptr<Core::Log> logger =
nullptr)
41 :
Task(std::move(input), std::move(output), std::move(logger)) {
44 std::string
name()
const override {
45 return "Hessian Calculation";
50 observers = {})
const final {
55 bool stopOnError = stopOnErrorExtraction(taskSettings);
56 bool silentCalculator = taskSettings.extract(
"silent_stdout_calculator",
true);
57 if (!taskSettings.empty()) {
58 throw std::logic_error(falseTaskSettingsErrorMessage(
name()));
60 if (observers.size() > 0) {
61 throw std::logic_error(
"HessianTask does not feature algorithm accepting observers, yet one was given");
70 auto calc = copyCalculator(systems, _input.front(),
name());
71 auto previousResults = calc->results();
72 Utils::CalculationRoutines::setLog(*calc,
true,
true, !silentCalculator);
75 const bool singleAtom = calc->getStructure()->size() == 1;
76 if (calc->getStructure()->size() == 1) {
77 const auto hessian = Eigen::MatrixXd::Zero(3, 3);
78 calc->results().set<Utils::Property::Hessian>(hessian);
79 calc->results().set<Utils::Property::PartialHessian>(Utils::PartialHessian(hessian, {0}));
81 previousResults.set<Utils::Property::Hessian>(hessian);
82 previousResults.set<Utils::Property::PartialHessian>(Utils::PartialHessian(hessian, {0}));
85 if (!(calc->results().has<Utils::Property::Hessian>() || calc->results().has<Utils::Property::PartialHessian>()) ||
86 !calc->results().has<Utils::Property::Energy>()) {
88 Utils::PropertyList requiredProperties = Utils::Property::Energy;
89 if (!calc->results().has<Utils::Property::Thermochemistry>() &&
90 calc->possibleProperties().containsSubSet(Utils::Property::Thermochemistry) && !singleAtom) {
91 requiredProperties.addProperty(Utils::Property::Thermochemistry);
94 if (calc->possibleProperties().containsSubSet(Utils::Property::PartialHessian)) {
95 requiredProperties.addProperty(Utils::Property::PartialHessian);
97 else if (calc->possibleProperties().containsSubSet(Utils::Property::Hessian)) {
98 requiredProperties.addProperty(Utils::Property::Hessian);
101 else if (!calc->results().has<Utils::Property::PartialHessian>() &&
102 calc->possibleProperties().containsSubSet(Utils::Property::PartialHessian)) {
103 requiredProperties.addProperty(Utils::Property::PartialHessian);
105 else if (!calc->results().has<Utils::Property::Hessian>() &&
106 calc->possibleProperties().containsSubSet(Utils::Property::Hessian)) {
107 requiredProperties.addProperty(Utils::Property::Hessian);
109 calc->setRequiredProperties(requiredProperties);
111 calc->calculate(
name());
112 if (!calc->results().get<Utils::Property::SuccessfulCalculation>()) {
113 throw std::runtime_error(
name() +
" was not successful");
121 <<
" " +
name() +
" was not successful with error:\n " + boost::current_exception_diagnostic_information()
123 calc->results() = previousResults + calc->results();
127 calc->results() = previousResults + calc->results();
128 Utils::NormalModesContainer modes;
129 auto system = calc->getStructure();
131 if (calc->results().has<Utils::Property::Hessian>()) {
132 auto hessian = calc->results().get<Utils::Property::Hessian>();
133 modes = Utils::NormalModeAnalysis::calculateNormalModes(hessian, system->getElements(), system->getPositions());
135 else if (calc->results().has<Utils::Property::PartialHessian>()) {
136 auto partialHessian = calc->results().get<Utils::Property::PartialHessian>();
137 modes = Utils::NormalModeAnalysis::calculateNormalModes(partialHessian, system->getElements(), system->getPositions());
140 throw std::runtime_error(
"Hessian or partial Hessian properties not available in results!");
142 auto wavenumbers = modes.getWaveNumbers();
144 auto cout = _logger->output;
145 cout <<
" Vib. Frequencies:\n";
146 cout <<
" [Rot. and trans. vib. removed, imaginary freq. shown as negative.]\n\n";
147 cout.printf(
" %4s %8s\n",
"#",
"cm^-1");
149 for (
unsigned int i = 0; i < wavenumbers.size(); i++) {
150 if (std::fabs(wavenumbers[i]) < 1e-6) {
154 cout.printf(
" %4d %+8.1f\n", i + 1, wavenumbers[i]);
157 cout <<
" Skipped " << skipped <<
" modes with zero frequency." <<
Core::Log::endl;
161 const std::string& outputSystem = (!_output.empty() ? _output[0] : _input[0]);
164 boost::filesystem::path dir(outputSystem);
165 if (!singleAtom && wavenumbers[0] < 0.0) {
166 boost::filesystem::create_directory(dir);
169 for (
unsigned int i = 0; i < wavenumbers.size() && wavenumbers[i] < 0.0; ++i) {
170 auto trj = modes.getModeAsMolecularTrajectory(i, *system, 1.0);
171 std::string filename = Utils::format(
"%s.vibmode-%05d.trj.xyz", outputSystem.c_str(), i + 1);
172 std::ofstream xyz((dir / filename).
string(), std::ofstream::out);
178 systems[outputSystem] = calc;
181 const auto hessian = calc->results().get<Utils::Property::Hessian>();
183 hessian, *calc->getStructure(), calc->settings().getInt(Utils::SettingsNames::spinMultiplicity),
184 calc->results().get<Utils::Property::Energy>());
185 calc->results().set<Utils::Property::Thermochemistry>(thermoCalc.calculate());
189 if (calc->results().has<Utils::Property::Thermochemistry>()) {
190 auto thermo = calc->results().get<Utils::Property::Thermochemistry>();
191 double temp = calc->settings().getDouble(
"temperature");
192 double pressure = calc->settings().getDouble(
"pressure");
193 cout <<
" Thermochemical Data:\n";
194 cout.printf(
" %35s %+14.9f K\n",
"Temperature (T):", temp);
195 cout.printf(
" %35s %+14.6f Pa\n",
"Pressure (P):", pressure);
196 cout.printf(
" %35s %14d\n",
"Molecular symmetry number:", thermo.overall.symmetryNumber);
197 cout.printf(
" %35s %+14.9f E_h\n",
"Zero Point Vibrational Energy:", thermo.overall.zeroPointVibrationalEnergy);
198 cout.printf(
" %35s %+14.9f E_h/K\n",
"Entropy (S):", thermo.overall.entropy);
199 cout.printf(
" %35s %+14.9f E_h\n",
"Entropy (-TS):", -temp * thermo.overall.entropy);
200 cout.printf(
" %35s %+14.9f E_h\n",
"Enthalpy (H):", thermo.overall.enthalpy);
201 double electronicEnergy = calc->results().get<Utils::Property::Energy>();
202 cout.printf(
" %35s %+14.9f E_h\n",
"Gibbs Energy Correction (dG):", thermo.overall.gibbsFreeEnergy - electronicEnergy);
203 cout.printf(
" %35s %+14.9f E_h\n",
"Electronic Energy (E):", electronicEnergy);
204 cout.printf(
" %35s %+14.9f E_h\n",
"Gibbs Energy (E + dG):", thermo.overall.gibbsFreeEnergy);
214 #endif // READUCT_HESSIANTASK_H_
Definition: HessianTask.h:32
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:40
void warningIfMultipleOutputsGiven() const
Warn if more than one output system was specified.
Definition: Task.h:107
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:85
static void write(format f, const std::string &fileName, const MolecularTrajectory &m, const BondOrderCollection &bondOrders)
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:48
void warningIfMultipleInputsGiven() const
Warn if more than one input system was specified.
Definition: Task.h:98
const std::vector< std::string > & output() const
Getter for the names of the output systems generated by this task.
Definition: Task.h:92
The base class for all tasks in Readuct.
Definition: Task.h:29
std::string name() const override
Getter for the tasks name.
Definition: HessianTask.h:44