Scine::Readuct  6.0.0
This is the SCINE module ReaDuct.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
IntegralTask.h
Go to the documentation of this file.
1 
8 #ifndef READUCT_INTEGRALSTASK_H
9 #define READUCT_INTEGRALSTASK_H
10 
11 /* Readuct */
12 #include "Tasks/Task.h"
13 /* Scine */
15 #include <Utils/CalculatorBasics.h>
16 #include <Utils/Settings.h>
18 /* External */
19 #include "boost/exception/diagnostic_information.hpp"
20 #include <boost/filesystem.hpp>
21 /* std c++ */
22 #include <iomanip>
23 #include <string>
24 #include <vector>
25 
26 namespace Scine::Readuct {
27 
32 class IntegralTask : public Task {
33  public:
40  IntegralTask(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)) {
42  }
47  std::string name() const override {
48  return "Integral Calculation";
49  }
58  bool run(SystemsMap& systems, Utils::UniversalSettings::ValueCollection taskSettings, bool testRunOnly = false,
59  std::vector<std::function<void(const int&, const Utils::AtomCollection&, const Utils::Results&, const std::string&)>>
60  observers = {}) const final {
61  // Read and delete special settings
62  const bool stopOnError = stopOnErrorExtraction(taskSettings);
63  const bool requireHCore = taskSettings.extract("require_one_electron_integrals", true);
64  const bool silentCalculator = taskSettings.extract("silent_stdout_calculator", true);
65  if (!taskSettings.empty()) {
66  std::string keyListing = "\n";
67  auto keys = taskSettings.getKeys();
68  for (const auto& key : keys) {
69  keyListing += "'" + key + "'\n";
70  }
71  throw std::logic_error("Specified one or more task settings that are not available for this task:" + keyListing);
72  }
73  if (observers.size() > 0) {
74  throw std::logic_error("IntegralTask does not feature algorithm accepting observers, yet one was given");
75  }
76  if (testRunOnly) {
77  return true; // leave out rest in case of task chaining
78  }
79 
80  // Note: _input is guaranteed not to be empty by Task constructor
81  auto calc = copyCalculator(systems, _input.front(), name());
82  const auto previousResults = calc->results();
83  Utils::CalculationRoutines::setLog(*calc, true, true, !silentCalculator);
84  // Check for available properties
85  const bool hCoreAvailable = calc->possibleProperties().containsSubSet(Utils::Property::OneElectronMatrix);
86 
87  if (requireHCore && !hCoreAvailable) {
88  throw std::logic_error(
89  "One-electron integrals required, but chosen calculator does not provide them.\n"
90  "If you do not need one-electron integrals, set 'require_one_electron_integrals' to 'false'"
91  " in the task settings");
92  }
93  Utils::PropertyList requiredProperties;
94  if (requireHCore) {
95  requiredProperties.addProperty(Utils::Property::OneElectronMatrix);
96  }
97 
98  try {
99  calc->setRequiredProperties(requiredProperties);
100  calc->calculate(name());
101  if (!calc->results().get<Utils::Property::SuccessfulCalculation>()) {
102  throw std::runtime_error(name() + " was not successful");
103  }
104  }
105  catch (...) {
106  if (stopOnError) {
107  throw;
108  }
109  _logger->error
110  << " " + name() + " was not successful with error:\n " + boost::current_exception_diagnostic_information()
111  << Core::Log::endl;
112  calc->results() = previousResults + calc->results();
113  return false;
114  }
115 
116  if (requireHCore) {
117  const std::string& outputSystem = (!_output.empty() ? _output.front() : _input.front());
118  const boost::filesystem::path dir(outputSystem);
119  boost::filesystem::create_directory(dir);
120  const boost::filesystem::path asciiFile(outputSystem + ".hcore.dat");
121  const std::string outPath = (dir / asciiFile).string();
122  _logger->output << "Writing core Hamiltonian integrals to file " << outPath << Core::Log::endl;
123  std::ofstream outFile(outPath, std::ofstream::out);
124  const auto hCoreMatrix = calc->results().template get<Utils::Property::OneElectronMatrix>();
125  outFile << "AO core Hamiltonian integrals.\n";
126  outFile << std::scientific << std::setprecision(12) << hCoreMatrix << "\n";
127  outFile.close();
128 
129  // Store result
130  if (!_output.empty()) {
131  systems[_output[0]] = calc;
132  }
133  else {
134  systems[_input[0]] = calc;
135  }
136  }
137 
138  return true;
139  }
140 };
141 
142 } // namespace Scine::Readuct
143 
144 #endif // READUCT_INTEGRALSTASK_H
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
Run the task.
Definition: IntegralTask.h:58
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
This tasks writes integrals, such as the one-electron integrals, to file.
Definition: IntegralTask.h:32
IntegralTask(std::vector< std::string > input, std::vector< std::string > output, std::shared_ptr< Core::Log > logger=nullptr)
Construct a new IntegralTask.
Definition: IntegralTask.h:40
std::string name() const override
Getter for the task&#39;s name.
Definition: IntegralTask.h:47
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