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