Scine::Readuct  6.0.0
This is the SCINE module ReaDuct.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
io.h
Go to the documentation of this file.
1 
7 #ifndef READUCT_IO_H_
8 #define READUCT_IO_H_
9 
10 /* Readuct */
11 #include "Tasks/TaskFactory.h"
12 /* Scine */
14 #include <Core/Log.h>
15 #include <Core/ModuleManager.h>
17 #include <Utils/Geometry.h>
19 #include <Utils/IO/Yaml.h>
20 
21 /* Boost program arguments */
22 #include "boost/exception/diagnostic_information.hpp"
23 
24 /* C++ std */
25 #include <iostream>
26 #include <map>
27 #include <memory>
28 #include <string>
29 #include <vector>
30 
31 namespace Scine {
32 namespace Readuct {
33 
34 std::tuple<std::map<std::string, std::tuple<std::string, std::string, std::shared_ptr<Core::Calculator>>>,
35  std::vector<std::shared_ptr<Task>>, std::vector<Utils::UniversalSettings::ValueCollection>>
36 loadYamlFile(const std::string& filename) {
37  // Initialize map for all systems (name - their calculators)
38  std::map<std::string, std::tuple<std::string, std::string, std::shared_ptr<Core::Calculator>>> systems;
39 
40  // Initialize Logger
41  auto logger = std::make_shared<Core::Log>();
42 
43  auto input = YAML::LoadFile(filename);
44  // Check for invalid top level input sections
45  std::vector<std::string> keywords{"systems", "tasks"};
46  Utils::checkYamlKeyRecognition(input, keywords);
47 
48  // Load systems
49  auto systemsInput = input["systems"];
50  for (size_t i = 0; i < systemsInput.size(); i++) {
51  // Check for invalid system input sections
52  std::vector<std::string> keywords{"name", "method_family", "path", "program", "settings"};
53  Utils::checkYamlKeyRecognition(systemsInput[i], keywords);
54 
55  auto current = systemsInput[i];
56  if (!current["name"]) {
57  throw std::logic_error("System no. " + std::to_string(i + 1) + " is missing a name.\n");
58  }
59  std::string name = current["name"].as<std::string>();
60  if (!current["method_family"]) {
61  throw std::logic_error("A method_family is missing for the system: '" + name + "'.\n");
62  }
63  std::string methodFamily = current["method_family"].as<std::string>();
64  if (!current["path"]) {
65  throw std::logic_error("An input path is missing for the system: '" + name + "'.\n");
66  }
67  std::string path = current["path"].as<std::string>();
68  std::string program;
69  if (auto node = current["program"]) {
70  program = current["program"].as<std::string>();
71  }
72  // Load molecule
73  auto readResults = Utils::ChemicalFileHandler::read(path);
74 
75  // Generate Calculator
76  auto calc = Utils::CalculationRoutines::getCalculator(methodFamily, program);
77  // Apply settings to Calculator
78  if (auto settingsnode = current["settings"]) {
79  nodeToSettings(calc->settings(), settingsnode);
80  }
81  // Set initial structure
82  calc->setStructure(readResults.first);
83  if (!calc->settings().valid()) {
84  calc->settings().throwIncorrectSettings();
85  }
86  if (program.empty()) {
87  program = "Any";
88  }
89  Utils::CalculationRoutines::inputPreparation(methodFamily, program);
90  systems[name] = std::make_tuple(methodFamily, program, calc);
91  }
92 
93  // Generate Tasks
94  std::vector<std::shared_ptr<Task>> tasks;
95  std::vector<Utils::UniversalSettings::ValueCollection> tasksettings;
96  auto tasksInput = input["tasks"];
97  for (auto current : tasksInput) {
98  // Check for invalid task input sections
99  std::vector<std::string> keywords{"type", "input", "output", "settings"};
100  Utils::checkYamlKeyRecognition(current, keywords);
101  std::string type = current["type"].as<std::string>();
102  // Parse inputs
103  std::vector<std::string> inputs;
104  auto inputnames = current["input"];
105  if (inputnames.size() == 0) {
106  throw std::logic_error("Missing system (input name) in task " + type + "\n");
107  }
108  for (auto inputname : inputnames) {
109  inputs.push_back(inputname.as<std::string>());
110  }
111  // Parse outputs if present
112  std::vector<std::string> outputs;
113  if (auto outputsnames = current["output"]) {
114  for (auto outputname : outputsnames) {
115  outputs.push_back(outputname.as<std::string>());
116  }
117  }
118  // Generate task
119  tasks.emplace_back(TaskFactory::produce(type, inputs, outputs, logger));
120  // Get task settings
121  if (current["settings"]) {
122  tasksettings.push_back(Utils::deserializeValueCollection(current["settings"]));
123  }
124  else {
125  tasksettings.emplace_back();
126  }
127  }
128 
129  // Test task dependencies
130  std::vector<std::string> existing;
131  existing.reserve(systems.size());
132  for (const auto& s : systems) {
133  existing.push_back(s.first);
134  }
135  for (size_t i = 0; i < tasks.size(); i++) {
136  for (const auto& required : tasks[i]->input()) {
137  if (std::find(existing.begin(), existing.end(), required) == existing.end()) {
138  throw std::logic_error("Task No. " + std::to_string(i + 1) + " requires a system named '" + required +
139  "' which won't be present at that stage.\n");
140  }
141  }
142  for (const auto& generated : tasks[i]->output()) {
143  existing.push_back(generated);
144  }
145  }
146 
147  // Run tasks in testing mode to check all settings without calculations and writing files
148  // if this goes through all basic settings are correct, otherwise we hopefully have a meaningful error in task
149  std::map<std::string, std::shared_ptr<Core::Calculator>> calcs;
150  for (const auto& s : systems) {
151  calcs[s.first] = std::get<2>(s.second);
152  }
153  for (size_t i = 0; i < tasks.size(); i++) {
154  auto name = tasks[i]->name();
155  try {
156  tasks[i]->run(calcs, tasksettings[i], true);
157  }
158  catch (...) {
159  throw std::logic_error("Encountered the following error in task " + name + ":\n" +
160  boost::current_exception_diagnostic_information());
161  }
162  }
163  return std::make_tuple(systems, tasks, tasksettings);
164 }
165 
166 } // namespace Readuct
167 } // namespace Scine
168 
169 #endif // READUCT_IO_H_
static std::unique_ptr< Task > produce(std::string name, const std::vector< std::string > &input, const std::vector< std::string > &output, std::shared_ptr< Core::Log > logger=nullptr)
Contstructs a Task with a given set of input and output systems.
Definition: TaskFactory.h:46
static std::pair< AtomCollection, BondOrderCollection > read(const std::string &filename)