votca 2026-dev
Loading...
Searching...
No Matches
orca.cc
Go to the documentation of this file.
1
2/*
3 * Copyright 2009-2024 The VOTCA Development Team
4 * (http://www.votca.org)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License")
7 *
8 * You may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */
20
21// Standard includes
22#include <cstdio>
23#include <filesystem>
24#include <iomanip>
25
26// Third party includes
27#include <boost/algorithm/string.hpp>
28#include <boost/format.hpp>
29
30// VOTCA includes
31#include <stdexcept>
32#include <string>
34#include <votca/tools/getline.h>
35
36// Local VOTCA includes
37#include "votca/tools/globals.h"
39#include "votca/xtp/basisset.h"
41#include "votca/xtp/molden.h"
42#include "votca/xtp/orbitals.h"
43
44// trying posix_spwan
45#include <spawn.h>
46#include <stdexcept>
47#include <sys/wait.h>
48#include <unistd.h>
49
50extern char** environ;
51
52// Local private VOTCA includes
53#include "orca.h"
54
55namespace votca {
56namespace xtp {
57using namespace std;
58
60
61 // Orca file names
62 std::string fileName = options.get("temporary_file").as<std::string>();
63
64 input_file_name_ = fileName + ".inp";
65 log_file_name_ = fileName + ".log";
66 shell_file_name_ = fileName + ".sh";
67 mo_file_name_ = fileName + ".gbw";
68}
69
70/* Custom basis sets are written on a per-element basis to
71 * the system.bas/aux file(s), which are then included in the
72 * Orca input file using GTOName = "system.bas/aux"
73 */
74void Orca::WriteBasisset(const QMMolecule& qmatoms, std::string& bs_name,
75 std::string& el_file_name) {
76
77 std::vector<std::string> UniqueElements = qmatoms.FindUniqueElements();
78
79 tools::Elements elementInfo;
80 BasisSet bs;
81 bs.Load(bs_name);
82 XTP_LOG(Log::error, *pLog_) << "Loaded Basis Set " << bs_name << flush;
83 ofstream el_file;
84
85 el_file.open(el_file_name);
86 el_file << "$DATA" << endl;
87
88 for (const std::string& element_name : UniqueElements) {
89 const Element& element = bs.getElement(element_name);
90 el_file << elementInfo.getEleFull(element_name) << endl;
91 for (const Shell& shell : element) {
92 el_file << xtp::EnumToString(shell.getL()) << " " << shell.getSize()
93 << endl;
94 Index sh_idx = 0;
95 for (const GaussianPrimitive& gaussian : shell) {
96 sh_idx++;
97 el_file << " " << sh_idx << " " << indent(gaussian.decay());
98 el_file << " " << indent(gaussian.contraction());
99 el_file << endl;
100 }
101 }
102 }
103 el_file << "STOP\n";
104 el_file.close();
105
106 return;
107}
108
109/* Coordinates are written in standard Element,x,y,z format to the
110 * input file.
111 */
112void Orca::WriteCoordinates(std::ofstream& inp_file,
113 const QMMolecule& qmatoms) {
114
115 for (const QMAtom& atom : qmatoms) {
116 Eigen::Vector3d pos = atom.getPos() * tools::conv::bohr2ang;
117 inp_file << setw(3) << atom.getElement() << setw(12)
118 << setiosflags(ios::fixed) << setprecision(6) << pos.x()
119 << setw(12) << setiosflags(ios::fixed) << setprecision(6)
120 << pos.y() << setw(12) << setiosflags(ios::fixed)
121 << setprecision(6) << pos.z() << endl;
122 }
123 inp_file << "* \n" << endl;
124 return;
125}
126
127/* If custom ECPs are used, they need to be specified in the input file
128 * in a section following the basis set includes.
129 */
130void Orca::WriteECP(std::ofstream& inp_file, const QMMolecule& qmatoms) {
131
132 inp_file << endl;
133 std::vector<std::string> UniqueElements = qmatoms.FindUniqueElements();
134
135 ECPBasisSet ecp;
136 ecp.Load(options_.get("ecp").as<std::string>());
137
138 XTP_LOG(Log::error, *pLog_) << "Loaded Pseudopotentials "
139 << options_.get("ecp").as<std::string>() << flush;
140
141 for (const std::string& element_name : UniqueElements) {
142 try {
143 ecp.getElement(element_name);
144 } catch (std::runtime_error& error) {
146 << "No pseudopotential for " << element_name << " available" << flush;
147 continue;
148 }
149 const ECPElement& element = ecp.getElement(element_name);
150
151 inp_file << "\n"
152 << "NewECP"
153 << " " << element_name << endl;
154 inp_file << "N_core"
155 << " " << element.getNcore() << endl;
156 inp_file << "lmax"
157 << " " << EnumToString(element.getLmax()) << endl;
158 // For Orca the order doesn't matter but let's write it in ascending order
159 // write remaining shells in ascending order s,p,d...
160 for (Index i = 0; i <= Index(element.getLmax()); i++) {
161 for (const ECPShell& shell : element) {
162 if (Index(shell.getL()) == i) {
163 // shell type, number primitives, scale factor
164 inp_file << xtp::EnumToString(shell.getL()) << " " << shell.getSize()
165 << endl;
166 Index sh_idx = 0;
167 for (const ECPGaussianPrimitive& gaussian : shell) {
168 sh_idx++;
169 inp_file << sh_idx << " " << gaussian.decay_ << " "
170 << gaussian.contraction_ << " " << gaussian.power_ << endl;
171 }
172 }
173 }
174 }
175 inp_file << "end\n "
176 << "\n"
177 << endl;
178 }
179 return;
180}
181
183 this->options_.addTree("orca.pointcharges", "\"background.crg\"");
184}
185
186/* For QM/MM the molecules in the MM environment are represented by
187 * their atomic partial charge distributions. ORCA expects them in
188 * q,x,y,z format in a separate file "background.crg"
189 */
191
192 std::ofstream crg_file;
193 std::string crg_file_name_full_ = run_dir_ + "/background.crg";
194 crg_file.open(crg_file_name_full_);
195 Index total_background = 0;
196
197 for (const std::unique_ptr<StaticSite>& site : externalsites_) {
198 if (site->getCharge() != 0.0) {
199 total_background++;
200 }
201 total_background += SplitMultipoles(*site).size();
202 } // counting only
203
204 crg_file << total_background << endl;
205 boost::format fmt("%1$+1.7f %2$+1.7f %3$+1.7f %4$+1.7f");
206 // now write
207 for (const std::unique_ptr<StaticSite>& site : externalsites_) {
208 Eigen::Vector3d pos = site->getPos() * tools::conv::bohr2ang;
209 string sitestring =
210 boost::str(fmt % site->getCharge() % pos.x() % pos.y() % pos.z());
211 if (site->getCharge() != 0.0) {
212 crg_file << sitestring << endl;
213 }
214 std::vector<MinimalMMCharge> split_multipoles = SplitMultipoles(*site);
215 for (const auto& mpoles : split_multipoles) {
216 Eigen::Vector3d pos2 = mpoles.pos_ * tools::conv::bohr2ang;
217 string multipole =
218 boost::str(fmt % mpoles.q_ % pos2.x() % pos2.y() % pos2.z());
219 crg_file << multipole << endl;
220 }
221 }
222
223 return;
224}
225
231bool Orca::WriteInputFile(const Orbitals& orbitals) {
232
233 std::vector<std::string> results;
234 std::string temp_suffix = "/id";
235 std::string scratch_dir_backup = scratch_dir_;
236 std::ofstream inp_file;
237 std::string inp_file_name_full = run_dir_ + "/" + input_file_name_;
238 inp_file.open(inp_file_name_full);
239
240 Index threads = OPENMP::getMaxThreads();
241 const QMMolecule& qmatoms = orbitals.QMAtoms();
242 Index Znuc = 0;
243 for (const QMAtom& atom : orbitals.QMAtoms()) {
244 Znuc += atom.getNuccharge();
245 }
246 if ((charge_ == 0) && (Znuc % 2 != 0)) {
247 spin_ = 2;
248 }
249 // header
250 inp_file << "* xyz " << charge_ << " " << spin_ << endl;
251 // put coordinates
252 WriteCoordinates(inp_file, qmatoms);
253 // add parallelization info
254 inp_file << "%pal\n"
255 << "nprocs " << threads << "\nend"
256 << "\n"
257 << endl;
258 // basis set info
259 std::string el_file_name = run_dir_ + "/" + "system.bas";
260 WriteBasisset(qmatoms, basisset_name_, el_file_name);
261 inp_file << "%basis\n";
262 inp_file << "GTOName"
263 << " "
264 << "="
265 << "\"system.bas\";" << endl;
266 if (options_.exists("auxbasisset")) {
267 std::string aux_file_name = run_dir_ + "/" + "system.aux";
268 std::string auxbasisset_name =
269 options_.get("auxbasisset").as<std::string>();
270 WriteBasisset(qmatoms, auxbasisset_name, aux_file_name);
271 inp_file << "GTOAuxName"
272 << " "
273 << "="
274 << "\"system.aux\";" << endl;
275 } // write_auxbasis set
276
277 // ECPs
278 if (options_.exists("ecp")) {
279 WriteECP(inp_file, qmatoms);
280 }
281 inp_file << "end\n "
282 << "\n"
283 << endl; // This end is for the basis set block
284 if (!externalsites_.empty()) {
286 }
287
288 // External Electric field
289 if (options_.exists("externalfield")) {
290 Eigen::Vector3d field = options_.get("externalfield").as<Eigen::Vector3d>();
291 inp_file << "%scf\n ";
292 inp_file << " efield " << field.x() << ", " << field.y() << ", "
293 << field.z() << "\n";
294 inp_file << "end\n";
295 inp_file << std::endl;
296 }
297 std::string input_options;
298 // Write Orca section specified by the user
299 for (const auto& prop : this->options_.get("orca")) {
300 const std::string& prop_name = prop.name();
301 if (prop_name == "pointcharges") {
302 input_options += this->CreateInputSection("orca.pointcharges");
303 } else if (prop_name != "method") {
304 input_options += this->CreateInputSection("orca." + prop_name);
305 }
306 }
307 // Write main DFT method
308 input_options += this->WriteMethod();
309 inp_file << input_options;
310 inp_file << '\n';
311 inp_file.close();
312 // and now generate a shell script to run both jobs, if neccessary
313
315 << "Setting the scratch dir to " << scratch_dir_ + temp_suffix << flush;
316 scratch_dir_ = scratch_dir_backup + temp_suffix;
318 scratch_dir_ = scratch_dir_backup;
319 return true;
320}
321
323 ofstream shell_file;
324 std::string shell_file_name_full = run_dir_ + "/" + shell_file_name_;
325 shell_file.open(shell_file_name_full);
326 shell_file << "#!/usr/bin/env bash" << endl;
327 if (run_dir_ != ".") {
328 const std::string key = "molecule";
329 std::string path = run_dir_;
330 auto pos = path.find(key);
331
332 if (pos != std::string::npos) {
333 scratch_dir_ += "/" + path.erase(0, pos);
334 }
335 }
336 shell_file << "mkdir -p " << scratch_dir_ << endl;
337 shell_file << "export TMPDIR=" << scratch_dir_ << endl;
338 std::string base_name = mo_file_name_.substr(0, mo_file_name_.size() - 4);
339
340 if (options_.get("initial_guess").as<std::string>() == "orbfile") {
341 if (!(std::filesystem::exists(run_dir_ + "/molA.gbw") &&
342 std::filesystem::exists(run_dir_ + "/molB.gbw"))) {
343 throw runtime_error(
344 "Using guess relies on a molA.gbw and a molB.gbw file being in the "
345 "directory.");
346 }
347 shell_file << options_.get("executable").as<std::string>()
348 << "_mergefrag molA.gbw molB.gbw " << base_name
349 << ".gbw > merge.log" << endl;
350 }
351 shell_file << options_.get("executable").as<std::string>() << " "
352 << input_file_name_ << " > " << log_file_name_ << endl;
353
354 shell_file << options_.get("executable").as<std::string>() << "_2mkl "
355 << base_name << " -molden > molden.log" << endl;
356 shell_file.close();
357 return true;
358}
359
360int run_command_spawn(const std::string& command) {
361 pid_t pid;
362
363 // system() implicitly does: /bin/sh -c "command"
364 std::vector<char*> argv = {const_cast<char*>("/bin/sh"),
365 const_cast<char*>("-c"),
366 const_cast<char*>(command.c_str()), nullptr};
367
368 int rc = posix_spawn(&pid, "/bin/sh", nullptr, nullptr, argv.data(), environ);
369
370 if (rc != 0) {
371 throw std::runtime_error("posix_spawn failed: " + std::to_string(rc));
372 }
373
374 int status;
375 waitpid(pid, &status, 0);
376
377 if (WIFEXITED(status)) return WEXITSTATUS(status);
378
379 return -1; // abnormal termination
380}
381
386
387 XTP_LOG(Log::error, *pLog_) << "Running Orca job\n" << flush;
388
389 if (std::system(nullptr)) {
390
391 std::string command = "cd " + run_dir_ + "; sh " + shell_file_name_;
392 Index check = run_command_spawn(command);
393 if (check == -1) {
395 << input_file_name_ << " failed to start" << flush;
396 return false;
397 }
398 if (CheckLogFile()) {
399 XTP_LOG(Log::error, *pLog_) << "Finished Orca job" << flush;
400 return true;
401 } else {
402 XTP_LOG(Log::error, *pLog_) << "Orca job failed" << flush;
403 }
404 } else {
406 << input_file_name_ << " failed to start" << flush;
407 return false;
408 }
409
410 return true;
411}
412
417
418 if (options_.get("initial_guess").as<std::string>() == "orbfile") {
419 remove((run_dir_ + "/" + "molA.gbw").c_str());
420 remove((run_dir_ + "/" + "molB.gbw").c_str());
421 remove((run_dir_ + "/" + "dimer.gbw").c_str());
422 }
423 // cleaning up the generated files
424 if (!cleanup_.empty()) {
425 tools::Tokenizer tok_cleanup(cleanup_, ",");
426 for (const std::string& substring : tok_cleanup) {
427 if (substring == "inp") {
428 std::string file_name = run_dir_ + "/" + input_file_name_;
429 remove(file_name.c_str());
430 }
431
432 if (substring == "bas") {
433 std::string file_name = run_dir_ + "/system.bas";
434 remove(file_name.c_str());
435 }
436
437 if (substring == "log") {
438 std::string file_name = run_dir_ + "/" + log_file_name_;
439 remove(file_name.c_str());
440 }
441
442 if (substring == "gbw") {
443 std::string file_name = run_dir_ + "/" + mo_file_name_;
444 remove(file_name.c_str());
445 }
446
447 if (substring == "ges") {
448 std::string file_name = run_dir_ + "/system.ges";
449 remove(file_name.c_str());
450 }
451 if (substring == "prop") {
452 std::string file_name = run_dir_ + "/system.prop";
453 remove(file_name.c_str());
454 }
455 }
456 }
457 return;
458}
459
461
462 StaticSegment result("charges", 0);
463
464 XTP_LOG(Log::error, *pLog_) << "Parsing " << log_file_name_ << flush;
465 std::string log_file_name_full = run_dir_ + "/" + log_file_name_;
466 std::string line;
467
468 std::ifstream input_file(log_file_name_full);
469 while (input_file) {
470 tools::getline(input_file, line);
471 boost::trim(line);
472 GetCoordinates(result, line, input_file);
473
474 std::string::size_type charge_pos = line.find("CHELPG Charges");
475
476 if (charge_pos != std::string::npos) {
477 XTP_LOG(Log::error, *pLog_) << "Getting charges" << flush;
478 tools::getline(input_file, line);
479 std::vector<std::string> row = GetLineAndSplit(input_file, "\t ");
480 Index nfields = Index(row.size());
481 bool hasAtoms = result.size() > 0;
482 while (nfields == 4) {
483 Index atom_id = boost::lexical_cast<Index>(row.at(0));
484 std::string atom_type = row.at(1);
485 double atom_charge = boost::lexical_cast<double>(row.at(3));
486 row = GetLineAndSplit(input_file, "\t ");
487 nfields = Index(row.size());
488 if (hasAtoms) {
489 StaticSite& temp = result.at(atom_id);
490 if (temp.getElement() != atom_type) {
491 throw std::runtime_error(
492 "Getting charges failed. Mismatch in elemts:" +
493 temp.getElement() + " vs " + atom_type);
494 }
495 temp.setCharge(atom_charge);
496 } else {
497 StaticSite temp =
498 StaticSite(atom_id, atom_type, Eigen::Vector3d::Zero());
499 temp.setCharge(atom_charge);
500 result.push_back(temp);
501 }
502 }
503 }
504 }
505 return result;
506}
507
508Eigen::Matrix3d Orca::GetPolarizability() const {
509 std::string line;
510 ifstream input_file((run_dir_ + "/" + log_file_name_));
511 bool has_pol = false;
512
513 Eigen::Matrix3d pol = Eigen::Matrix3d::Zero();
514 while (input_file) {
515 tools::getline(input_file, line);
516 boost::trim(line);
517
518 std::string::size_type pol_pos = line.find("POLARIZABILITY TENSOR");
519
520 if (pol_pos != std::string::npos) {
521
522 XTP_LOG(Log::error, *pLog_) << "Getting polarizability" << flush;
523 for (Index i = 0; i < 10; i++) {
524 tools::getline(input_file, line);
525 if (line.find("The raw cartesian tensor (atomic units)") !=
526 std::string::npos) {
527 break;
528 }
529 if (i == 9) {
530 throw std::runtime_error(
531 "Could not find cartesian polarization tensor");
532 }
533 }
534
535 for (Index i = 0; i < 3; i++) {
536 tools::getline(input_file, line);
537 std::vector<double> values =
538 tools::Tokenizer(line, " ").ToVector<double>();
539 if (values.size() != 3) {
540 throw std::runtime_error("polarization line " + line +
541 " cannot be parsed");
542 }
543 Eigen::Vector3d row;
544 row << values[0], values[1], values[2];
545 pol.row(i) = row;
546 }
547
548 has_pol = true;
549 }
550 }
551 if (!has_pol) {
552 throw std::runtime_error("Could not find polarization in logfile");
553 }
554 return pol;
555}
556
558 bool found_success = false;
559 orbitals.setQMpackage(getPackageName());
560
561 orbitals.setXCGrid("xfine"); // TODO find a better approximation for the
562 // orca grid.
563 orbitals.setXCFunctionalName(options_.get("functional").as<std::string>());
564
565 XTP_LOG(Log::error, *pLog_) << "Parsing " << log_file_name_ << flush;
566 std::string log_file_name_full = run_dir_ + "/" + log_file_name_;
567 // check if LOG file is complete
568 if (!CheckLogFile()) {
569 return false;
570 }
571 std::map<Index, double> energies;
572 std::map<Index, double> energies_beta;
573
574 std::map<Index, double> occupancy;
575 std::map<Index, double> occupancy_beta;
576
577 std::string line;
578 std::string orca_version;
579 Index orca_major_version = 0;
580
581 Index levels = 0;
582 Index number_of_electrons = 0;
583 Index number_of_electrons_beta = 0;
584 Index number_of_virtuals = 0;
585 Index number_of_virtuals_beta = 0;
586
587 std::vector<std::string> results;
588
589 std::ifstream input_file(log_file_name_full);
590
591 if (input_file.fail()) {
593 << "File " << log_file_name_full << " not found " << flush;
594 return false;
595 } else {
597 << "Reading basic ORCA output from " << log_file_name_full << flush;
598 }
599 // Coordinates of the final configuration depending on whether it is an
600 // optimization or not
601
602 QMMolecule& mol = orbitals.QMAtoms();
603 orbitals.setChargeAndSpin(charge_, spin_);
604 while (input_file) {
605 tools::getline(input_file, line);
606 boost::trim(line);
607
608 GetCoordinates(mol, line, input_file);
609
610 std::string::size_type version_pos = line.find("Program Version");
611 if (version_pos != std::string::npos) {
612 results = tools::Tokenizer(line, " ").ToVector();
613 orca_version = results[2];
614 boost::trim(orca_version);
615 XTP_LOG(Log::error, *pLog_) << "ORCA Version " << orca_version << flush;
616 results = tools::Tokenizer(orca_version, ".").ToVector();
617 orca_major_version = boost::lexical_cast<Index>(results[0]);
619 << "ORCA Major Version " << orca_major_version << flush;
620 }
621
622 std::string::size_type energy_pos = line.find("FINAL SINGLE");
623 if (energy_pos != std::string::npos) {
624 results = tools::Tokenizer(line, " ").ToVector();
625 std::string energy = results[4];
626 boost::trim(energy);
627 orbitals.setQMEnergy(boost::lexical_cast<double>(energy));
628 XTP_LOG(Log::error, *pLog_) << (boost::format("QM energy[Hrt]: %4.6f ") %
629 orbitals.getDFTTotalEnergy())
630 .str()
631 << flush;
632 }
633
634 std::string::size_type HFX_pos = line.find("Fraction HF Exchange ScalHFX");
635
636 if (HFX_pos != std::string::npos) {
637 results = tools::Tokenizer(line, " ").ToVector();
638 double ScaHFX = boost::lexical_cast<double>(results.back());
639
640 orbitals.setScaHFX(ScaHFX);
642 << "DFT with " << ScaHFX << " of HF exchange!" << flush;
643 }
644
645 std::string::size_type dim_pos = line.find("Basis Dimension");
646 if (dim_pos != std::string::npos) {
647 results = tools::Tokenizer(line, " ").ToVector();
648 std::string dim =
649 results[4]; // The 4th element of results vector is the Basis Dim
650 boost::trim(dim);
651 levels = boost::lexical_cast<Index>(dim);
652 XTP_LOG(Log::info, *pLog_) << "Basis Dimension: " << levels << flush;
653 XTP_LOG(Log::info, *pLog_) << "Energy levels: " << levels << flush;
654 }
655
656 std::string::size_type OE_pos = line.find("ORBITAL ENERGIES");
657 if (OE_pos != std::string::npos) {
658
659 number_of_electrons = 0;
660 tools::getline(input_file, line);
661 tools::getline(input_file, line); // for open shell systems, this line
662 // will have "SPIN UP ORBITALS"
663 if (orbitals.isOpenShell() &&
664 line.find("SPIN UP ORBITALS") == std::string::npos) {
665 throw runtime_error(
666 "Expected to read an open-shell system but found no spin orbitals");
667 }
668 tools::getline(input_file, line);
669 if (line.find("E(Eh)") == std::string::npos) {
671 << "Warning: Orbital Energies not found in log file" << flush;
672 }
673 for (Index i = 0; i < levels; i++) {
674 if (number_of_virtuals == 10 && orca_major_version > 5) {
675 break;
676 }
677 results = GetLineAndSplit(input_file, " ");
678 std::string no = results[0];
679 boost::trim(no);
680 Index levelnumber = boost::lexical_cast<Index>(no);
681 if (levelnumber != i) {
682 XTP_LOG(Log::error, *pLog_) << "Have a look at the orbital energies "
683 "something weird is going on"
684 << flush;
685 }
686 std::string oc = results[1];
687 boost::trim(oc);
688 double occ = boost::lexical_cast<double>(oc);
689 // We only count alpha electrons, each orbital must be empty or doubly
690 // occupied
691 if (occ == 2 || occ == 1) {
692 number_of_electrons++;
693 occupancy[i] = occ;
694 } else if (occ == 0) {
695 number_of_virtuals++;
696 occupancy[i] = occ;
697 }
698 std::string e = results[2];
699 boost::trim(e);
700 energies[i] = boost::lexical_cast<double>(e);
701 }
702
703 // now read spin down energies, if needed
704 if (orbitals.isOpenShell()) {
705 number_of_electrons_beta = 0;
706 number_of_virtuals_beta = 0;
707 tools::getline(input_file, line);
708 tools::getline(input_file, line);
709 tools::getline(input_file, line);
710 for (Index i = 0; i < levels; i++) {
711 if (number_of_virtuals == 10 && orca_major_version > 5) {
712 break;
713 }
714 results = GetLineAndSplit(input_file, " ");
715 std::string no = results[0];
716 boost::trim(no);
717 Index levelnumber = boost::lexical_cast<Index>(no);
718 if (levelnumber != i) {
720 << "Have a look at the orbital energies "
721 "something weird is going on"
722 << flush;
723 }
724 std::string oc = results[1];
725 boost::trim(oc);
726 double occ = boost::lexical_cast<double>(oc);
727 // These occupations can only be 1 or 0
728 if (occ == 1) {
729 number_of_electrons_beta++;
730 occupancy_beta[i] = occ;
731 } else if (occ == 0) {
732 number_of_virtuals_beta++;
733 occupancy_beta[i] = occ;
734 } else {
735 throw runtime_error(
736 "Encountered spin down orbital with occupancy != 0 or 1");
737 }
738 std::string e = results[2];
739 boost::trim(e);
740 energies_beta[i] = boost::lexical_cast<double>(e);
741 }
742 }
743 }
744
745 std::string::size_type success =
746 line.find("* SUCCESS *");
747 if (success != std::string::npos) {
748 found_success = true;
749 }
750 }
751
753 if (options_.exists("ecp")) {
754 orbitals.setECPName(options_.get("ecp").as<std::string>());
755 }
756
758 << "Alpha electrons: " << number_of_electrons << flush;
759 Index occupied_levels = number_of_electrons;
760 Index unoccupied_levels = levels - occupied_levels;
762 << "Occupied Alpha levels: " << occupied_levels << flush;
764 << "Unoccupied levels: " << unoccupied_levels << flush;
765
766 /************************************************************/
767
768 // copying information to the orbitals object
769 orbitals.setNumberOfAlphaElectrons(number_of_electrons);
770 orbitals.setNumberOfOccupiedLevels(occupied_levels);
771
772 // copying energies to a vector
773 orbitals.MOs().eigenvalues().resize(levels);
774 // level_ = 1;
775 for (Index i = 0; i < number_of_electrons + number_of_virtuals; i++) {
776 orbitals.MOs().eigenvalues()[i] = energies[i];
777 }
778
779 if (orbitals.isOpenShell()) {
781 << "Beta electrons: " << number_of_electrons_beta << flush;
783 << "Occupied Beta levels: " << number_of_electrons_beta << flush;
785 << "Unoccupied Beta levels: " << levels - number_of_electrons_beta
786 << flush;
787
788 orbitals.setNumberOfBetaElectrons(number_of_electrons_beta);
789 orbitals.setNumberOfOccupiedLevelsBeta(number_of_electrons_beta);
790 orbitals.MOs_beta().eigenvalues().resize(levels);
791 for (Index i = 0; i < number_of_electrons_beta + number_of_virtuals_beta;
792 i++) {
793 orbitals.MOs_beta().eigenvalues()[i] = energies_beta[i];
794 }
795 }
796
797 XTP_LOG(Log::error, *pLog_) << "Done reading Log file" << flush;
798
799 return found_success;
800}
801template <class T>
802void Orca::GetCoordinates(T& mol, string& line, ifstream& input_file) const {
803 std::string::size_type coordinates_pos =
804 line.find("CARTESIAN COORDINATES (ANGSTROEM)");
805
806 using Atom = typename T::Atom_Type;
807
808 if (coordinates_pos != std::string::npos) {
809 XTP_LOG(Log::error, *pLog_) << "Getting the coordinates" << flush;
810 bool has_QMAtoms = mol.size() > 0;
811 // three garbage lines
812 tools::getline(input_file, line);
813 // now starts the data in format
814 // id_ type Qnuc x y z
815 vector<string> row = GetLineAndSplit(input_file, "\t ");
816 Index nfields = Index(row.size());
817 Index atom_id = 0;
818 while (nfields == 4) {
819 string atom_type = row.at(0);
820 double x = boost::lexical_cast<double>(row.at(1));
821 double y = boost::lexical_cast<double>(row.at(2));
822 double z = boost::lexical_cast<double>(row.at(3));
823 row = GetLineAndSplit(input_file, "\t ");
824 nfields = Index(row.size());
825 Eigen::Vector3d pos(x, y, z);
827 if (has_QMAtoms == false) {
828 mol.push_back(Atom(atom_id, atom_type, pos));
829 } else {
830 Atom& pAtom = mol.at(atom_id);
831 pAtom.setPos(pos);
832 }
833 atom_id++;
834 }
835 }
836}
837
839 // check if the log file exists
840 ifstream input_file(run_dir_ + "/" + log_file_name_);
841
842 if (input_file.fail()) {
843 XTP_LOG(Log::error, *pLog_) << "Orca LOG is not found" << flush;
844 return false;
845 };
846
847 std::string line;
848 while (input_file) {
849 tools::getline(input_file, line);
850 boost::trim(line);
851 std::string::size_type error = line.find("FATAL ERROR ENCOUNTERED");
852 if (error != std::string::npos) {
853 XTP_LOG(Log::error, *pLog_) << "ORCA encountered a fatal error, maybe a "
854 "look in the log file may help."
855 << flush;
856 return false;
857 }
858 error = line.find(
859 "mpirun detected that one or more processes exited with non-zero "
860 "status");
861 if (error != std::string::npos) {
863 << "ORCA had an mpi problem, maybe your openmpi version is not good."
864 << flush;
865 return false;
866 }
867 }
868 return true;
869}
870
871// Parses the molden file from orca and stores data in the Orbitals object
873 if (!CheckLogFile()) {
874 return false;
875 }
876 std::vector<double> coefficients;
877 Index basis_size = orbitals.getBasisSetSize();
878 if (basis_size == 0) {
879 throw runtime_error(
880 "Basis size not set, calculator does not parse log file first");
881 }
882
883 XTP_LOG(Log::error, *pLog_) << "Reading Molden file" << flush;
884
885 Molden molden(*pLog_);
886
887 if (orbitals.getDFTbasisName() == "") {
888 throw runtime_error(
889 "Basisset names should be set before reading the molden file.");
890 }
892
893 std::string file_name = run_dir_ + "/" +
894 mo_file_name_.substr(0, mo_file_name_.size() - 4) +
895 ".molden.input";
896 XTP_LOG(Log::error, *pLog_) << "Molden file: " << file_name << flush;
897 std::ifstream molden_file(file_name);
898 if (!molden_file.good()) {
899 throw std::runtime_error(
900 "Could not find the molden input file for the MO coefficients.\nIf you "
901 "have run the orca calculation manually or use data from an old\n"
902 "calculation, make sure that besides the .gbw file a .molden.input is\n"
903 "present. If not, convert the .gbw file to a .molden.input file with\n"
904 "the orca_2mkl tool from orca.\nAn example, if you have a benzene.gbw "
905 "file run:\n orca_2mkl benzene -molden\n");
906 }
907 molden.parseMoldenFile(file_name, orbitals);
908
909 XTP_LOG(Log::error, *pLog_) << "Done parsing" << flush;
910
911 // ECP charge correction is only applied in Fill() of ECPAOBasis
912 if (orbitals.getECPName() != "") {
913 ECPBasisSet ecpbasisset;
914 ecpbasisset.Load(orbitals.getECPName());
915 ECPAOBasis ecp;
916 ecp.Fill(ecpbasisset, orbitals.QMAtoms());
917 }
918
919 return true;
920}
921
922std::string Orca::indent(const double& number) {
923 std::stringstream ssnumber;
924 if (number >= 0) {
925 ssnumber << " ";
926 } else {
927 ssnumber << " ";
928 }
929 ssnumber << setiosflags(ios::fixed) << setprecision(15) << std::scientific
930 << number;
931 std::string snumber = ssnumber.str();
932 return snumber;
933}
934
935std::string Orca::CreateInputSection(const std::string& key) const {
936 std::stringstream stream;
937 std::string section = key.substr(key.find(".") + 1);
938 stream << "%" << section;
939 if (KeywordIsSingleLine(key)) {
940 stream << " " << options_.get(key).as<std::string>() << "\n";
941 } else {
942 stream << "\n"
943 << options_.get(key).as<std::string>() << "\n"
944 << "end\n";
945 }
946
947 return stream.str();
948}
949
950bool Orca::KeywordIsSingleLine(const std::string& key) const {
951 tools::Tokenizer values(this->options_.get(key).as<std::string>(), " ");
952 std::vector<std::string> words = values.ToVector();
953 return ((words.size() <= 1) ? true : false);
954}
955
956std::string Orca::WriteMethod() const {
957 std::stringstream stream;
958 std::string opt = (options_.get("optimize").as<bool>()) ? "Opt" : "";
959 const tools::Property& orca = options_.get("orca");
960 std::string user_method =
961 (orca.exists("method")) ? orca.get("method").as<std::string>() : "";
962 std::string convergence = "";
963 if (!orca.exists("scf")) {
964 convergence = this->convergence_map_.at(
965 options_.get("convergence_tightness").as<std::string>());
966 }
967 stream << "! DFT " << this->GetOrcaFunctionalName() << " " << convergence
968 << " " << opt
969 << " "
970 // additional properties provided by the user
971 << user_method << "\n";
972 return stream.str();
973}
974
975std::string Orca::GetOrcaFunctionalName() const {
976
977 std::map<std::string, std::string> votca_to_orca;
978
979 votca_to_orca["XC_HYB_GGA_XC_B1LYP"] = "B1LYP";
980 votca_to_orca["XC_HYB_GGA_XC_B3LYP"] = "B3LYP";
981 votca_to_orca["XC_HYB_GGA_XC_PBEH"] = "PBE0";
982 votca_to_orca["XC_GGA_C_PBE"] = "PBE";
983 votca_to_orca["XC_GGA_X_PBE"] = "PBE";
984
985 std::string votca_functional =
986 options_.get("functional").as<std::vector<std::string>>()[0];
987
988 std::string orca_functional;
989 if (votca_to_orca.count(votca_functional)) {
990 orca_functional = votca_to_orca.at(votca_functional);
991 } else if (options_.exists("orca." + votca_functional)) {
992 orca_functional =
993 options_.get("orca." + votca_functional).as<std::string>();
994 } else {
995 throw std::runtime_error(
996 "Cannot translate " + votca_functional +
997 " to orca functional names. Please add a <" + votca_functional +
998 "> to your orca input options with the functional orca should use.");
999 }
1000 return orca_functional;
1001}
1002
1003} // namespace xtp
1004} // namespace votca
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
information about an element
Definition elements.h:42
std::string getEleFull(std::string eleshort)
Definition elements.cc:137
class to manage program options with xml serialization functionality
Definition property.h:55
Property & get(const std::string &key)
get existing property
Definition property.cc:79
bool exists(const std::string &key) const
check whether property exists
Definition property.cc:122
T as() const
return value as type
Definition property.h:283
break string into words
Definition tokenizer.h:72
std::vector< T > ToVector()
store all words in a vector of type T, does type conversion.
Definition tokenizer.h:109
void push_back(const T &atom)
const T & at(Index index) const
std::vector< std::string > FindUniqueElements() const
void setPos(const Eigen::Vector3d &r)
Definition atom.h:82
const Element & getElement(std::string element_type) const
Definition basisset.cc:212
void Load(const std::string &name)
Definition basisset.cc:149
Container to hold ECPs for all atoms.
Definition ecpaobasis.h:43
std::vector< std::string > Fill(const ECPBasisSet &bs, QMMolecule &atoms)
Definition ecpaobasis.cc:69
void Load(const std::string &name)
const ECPElement & getElement(std::string element_type) const
void parseMoldenFile(const std::string &filename, Orbitals &orbitals) const
Definition molden.cc:245
void setBasissetInfo(const std::string &basisset_name, const std::string &aux_basisset_name="")
Definition molden.h:41
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
void setScaHFX(double ScaHFX)
Store the fraction of exact exchange associated with the functional.
Definition orbitals.h:436
double getDFTTotalEnergy() const
Return the stored total DFT energy.
Definition orbitals.h:292
const tools::EigenSystem & MOs_beta() const
Return read-only access to beta-spin molecular orbitals.
Definition orbitals.h:202
void setNumberOfAlphaElectrons(Index electrons)
Store the total number of alpha electrons.
Definition orbitals.h:139
void setNumberOfBetaElectrons(Index electrons)
Store the total number of beta electrons.
Definition orbitals.h:144
void setECPName(const std::string &ECP)
Store the effective core potential label.
Definition orbitals.h:170
void setXCGrid(std::string grid)
Store the numerical XC grid quality label.
Definition orbitals.h:283
void setNumberOfOccupiedLevels(Index occupied_levels)
Definition orbitals.h:122
Index getBasisSetSize() const
Return the number of AO basis functions in the DFT basis.
Definition orbitals.h:72
void setQMEnergy(double qmenergy)
Store the total DFT energy.
Definition orbitals.h:295
const tools::EigenSystem & MOs() const
Return read-only access to alpha/restricted molecular orbitals.
Definition orbitals.h:192
void setQMpackage(const std::string &qmpackage)
Store the name of the QM package that produced these orbitals.
Definition orbitals.h:181
const QMMolecule & QMAtoms() const
Return read-only access to the molecular geometry.
Definition orbitals.h:262
void setNumberOfOccupiedLevelsBeta(Index occupied_levels_beta)
Store the number of occupied beta-spin orbitals.
Definition orbitals.h:134
void setChargeAndSpin(Index charge, Index spin)
Definition orbitals.h:246
const std::string & getECPName() const
Return the effective core potential label.
Definition orbitals.h:167
const std::string & getDFTbasisName() const
Return the DFT basis-set name.
Definition orbitals.h:318
void SetupDftBasis(std::string basis_name)
Build and attach the DFT AO basis from the stored molecular geometry.
Definition orbitals.cc:99
bool isOpenShell() const
Report whether the stored state corresponds to an open-shell system.
Definition orbitals.h:256
void setXCFunctionalName(std::string functionalname)
Definition orbitals.h:276
void GetCoordinates(T &mol, std::string &line, std::ifstream &input_file) const
Definition orca.cc:802
void WriteCoordinates(std::ofstream &inp_file, const QMMolecule &)
Definition orca.cc:112
void CleanUp() override
Definition orca.cc:416
void WriteECP(std::ofstream &inp_file, const QMMolecule &)
Definition orca.cc:130
bool WriteShellScript()
Definition orca.cc:322
void WriteBasisset(const QMMolecule &qmatoms, std::string &bs_name, std::string &el_file_name)
Definition orca.cc:74
std::string GetOrcaFunctionalName() const
Definition orca.cc:975
std::string indent(const double &number)
Definition orca.cc:922
std::string getPackageName() const override
Definition orca.h:40
Eigen::Matrix3d GetPolarizability() const override
Definition orca.cc:508
void WriteChargeOption() override
Definition orca.cc:182
std::map< std::string, std::string > convergence_map_
Definition orca.h:114
std::string CreateInputSection(const std::string &key) const
Definition orca.cc:935
StaticSegment GetCharges() const override
Definition orca.cc:460
std::string WriteMethod() const
Definition orca.cc:956
void WriteBackgroundCharges()
Definition orca.cc:190
bool CheckLogFile()
Definition orca.cc:838
bool RunDFT() override
Definition orca.cc:385
bool ParseLogFile(Orbitals &orbitals) override
Definition orca.cc:557
void ParseSpecificOptions(const tools::Property &options) final
Definition orca.cc:59
bool ParseMOsFile(Orbitals &orbitals) override
Definition orca.cc:872
bool KeywordIsSingleLine(const std::string &key) const
Definition orca.cc:950
bool WriteInputFile(const Orbitals &orbitals) override
Definition orca.cc:231
container for QM atoms
Definition qmatom.h:37
std::string log_file_name_
Definition qmpackage.h:150
std::vector< std::string > GetLineAndSplit(std::ifstream &input_file, const std::string separators) const
Definition qmpackage.cc:144
std::string run_dir_
Definition qmpackage.h:152
std::vector< std::unique_ptr< StaticSite > > externalsites_
Definition qmpackage.h:159
std::vector< MinimalMMCharge > SplitMultipoles(const StaticSite &site) const
Definition qmpackage.cc:109
std::string mo_file_name_
Definition qmpackage.h:151
std::string basisset_name_
Definition qmpackage.h:147
std::string cleanup_
Definition qmpackage.h:148
tools::Property options_
Definition qmpackage.h:155
std::string shell_file_name_
Definition qmpackage.h:154
std::string scratch_dir_
Definition qmpackage.h:153
std::string input_file_name_
Definition qmpackage.h:149
Class to represent Atom/Site in electrostatic.
Definition staticsite.h:37
const std::string & getElement() const
Definition staticsite.h:79
void setCharge(double q)
Definition staticsite.h:104
#define XTP_LOG(level, log)
Definition logger.h:40
const double ang2bohr
Definition constants.h:48
const double bohr2ang
Definition constants.h:49
std::istream & getline(std::istream &is, std::string &str)
Wrapper for a getline function.
Definition getline.h:35
Index getMaxThreads()
Definition eigen.h:128
Charge transport classes.
Definition ERIs.h:28
std::string EnumToString(L l)
Definition basisset.cc:60
ClassicalSegment< StaticSite > StaticSegment
int run_command_spawn(const std::string &command)
Definition orca.cc:360
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
char ** environ