votca 2026-dev
Loading...
Searching...
No Matches
podcouplingtool.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#include "podcouplingtool.h"
21#include "votca/xtp/qmstate.h"
22#include <sstream>
23
24using std::flush;
25
26namespace votca {
27namespace xtp {
28
30
31 log_.setReportLevel(Log::current_level);
32 log_.setMultithreading(true);
33 log_.setCommonPreface("\n...");
34
35 tools::Property options = user_options;
36
37 orb_file_ = options.get(".orb_file").as<std::string>();
38
39 // Same index-list syntax as CDFT's own cdft.indices and
40 // diabatization.xml's own fragment indices (space-separated
41 // indices and/or ranges, e.g. "1 3 13:17") -- deliberately reusing
42 // the SAME, already-established IndexParser utility both of those
43 // already use, rather than introducing yet another parsing
44 // convention for what is, at its core, the exact same kind of
45 // input (an atom-index list defining a fragment).
46 std::string fragment_A_str = options.get(".fragment_A").as<std::string>();
47 std::string fragment_B_str = options.get(".fragment_B").as<std::string>();
48 if (fragment_A_str.empty() || fragment_B_str.empty()) {
49 throw std::runtime_error(
50 "PodCouplingTool: fragment_A and fragment_B must both be given, "
51 "e.g. '0:5' and '6:11' -- same syntax as cdft.indices and "
52 "diabatization.xml's own fragment indices.");
53 }
56
57 // Matching DFTcoupling's own numberofstatesA_/numberofstatesB_
58 // convention exactly (same XML option names, levA/levB) -- covers
59 // BOTH occupied and virtual orbitals for each fragment in a single
60 // call, per direct agreement with the user to mirror DFTcoupling's
61 // own, established behavior here rather than this tool's own,
62 // earlier, single-orbital-pair-only interface.
65
66 XTP_LOG(Log::error, log_) << "Fragment A: " << fragment_A_atoms_.size()
67 << " atoms, levA=" << numberofstatesA_ << flush;
68 XTP_LOG(Log::error, log_) << "Fragment B: " << fragment_B_atoms_.size()
69 << " atoms, levB=" << numberofstatesB_ << flush;
70
71 // Optional cube-file export -- option names (xsteps/ysteps/zsteps/
72 // padding) deliberately matching gencube.xml's own exactly, since
73 // these are the same underlying quantities (a real-space grid for
74 // writing an orbital to a .cube file), not something specific to
75 // this tool that would warrant its own, different naming.
77 options.ifExistsReturnElseReturnDefault<bool>("write_cube_files", false);
79 cube_steps_.x() =
80 options.ifExistsReturnElseReturnDefault<Index>("xsteps", 25);
81 cube_steps_.y() =
82 options.ifExistsReturnElseReturnDefault<Index>("ysteps", 25);
83 cube_steps_.z() =
84 options.ifExistsReturnElseReturnDefault<Index>("zsteps", 25);
86 options.ifExistsReturnElseReturnDefault<double>("padding", 6.5);
87 }
88}
89
91
93
94 log_.setReportLevel(Log::current_level);
95 log_.setMultithreading(true);
96 log_.setCommonPreface("\n...");
97
99 << TimeStamp() << " Reading orbitals from: " << orb_file_ << flush;
100
101 Orbitals orbitals;
102 orbitals.ReadFromCpt(orb_file_);
103
106
107 Index homoA = pod.getFragmentAHomoIndex();
108 Index lumoA = pod.getFragmentALumoIndex();
109 Index homoB = pod.getFragmentBHomoIndex();
110 Index lumoB = pod.getFragmentBLumoIndex();
111
112 // The full, pairwise coupling matrix across the requested range,
113 // covering both hole (occupied) and electron (virtual) orbitals for
114 // each fragment -- matching DFTcoupling's own output style of
115 // reporting the whole JAB matrix, not just a single pair, per direct
116 // agreement with the user. Rows/columns are labeled by each
117 // orbital's own, absolute (fragment-local) index -- see
118 // PODCoupling::getFragmentAHomoIndex/etc.'s own header comment for
119 // what "absolute" means here.
121 << " Full coupling matrix [eV] (fragment A orbital "
122 "index -> fragment B orbital index):"
123 << flush;
124 for (Index levelA = homoA - numberofstatesA_ + 1;
125 levelA <= lumoA + numberofstatesA_ - 1; ++levelA) {
126 std::ostringstream row;
127 row << " A[" << levelA << (levelA == homoA ? "=HOMO" : "")
128 << (levelA == lumoA ? "=LUMO" : "") << "]:";
129 for (Index levelB = homoB - numberofstatesB_ + 1;
130 levelB <= lumoB + numberofstatesB_ - 1; ++levelB) {
131 double coupling_ev =
133 row << boost::format(" B[%1%]=%2$+1.6f") % levelB % coupling_ev;
134 }
135 XTP_LOG(Log::error, log_) << row.str() << flush;
136 }
137
138 // The two, most commonly-needed values highlighted directly --
139 // matching the paper's own default focus on hole transport
140 // (HOMO-HOMO), plus its own, direct electron-transport analog
141 // (LUMO-LUMO) -- so a caller does not need to parse the full matrix
142 // above just to get the single, most likely value of interest.
143 double homo_homo_ev =
145 double lumo_lumo_ev =
148 << boost::format("POD2 Coupling, HOMO-HOMO (hole): %1$+1.12f eV") %
149 homo_homo_ev
150 << flush;
152 << boost::format("POD2 Coupling, LUMO-LUMO (electron): %1$+1.12f eV") %
153 lumo_lumo_ev
154 << flush;
155
156 // Optional cube-file export of the fragment orbitals actually
157 // computed, per direct user request: reuses the existing
158 // CubeFile_Writer unmodified -- it only ever needs
159 // orb.MOs().eigenvectors().col(index) to contain the right
160 // coefficient vector (confirmed directly by reading
161 // CubeFile_Writer::CalculateValues' own implementation before
162 // relying on this), so each fragment orbital, once embedded into
163 // the full AO basis via PODCoupling::GetFragmentOrbital, is written
164 // into a throwaway COPY of the original orbitals object (never the
165 // original itself, which the rest of this function must not have
166 // mutated out from under it) as a single-column MOs() matrix, then
167 // handed to CubeFile_Writer exactly as gencube.cc's own Run()
168 // already does for an ordinary MO.
169 if (write_cube_files_) {
171 << TimeStamp()
172 << " Writing cube files for the computed fragment "
173 "orbitals..."
174 << flush;
176 auto WriteFragmentOrbitalCube = [&](bool fragment_A, Index level,
177 const std::string& label) {
178 Eigen::VectorXd orbital = pod.GetFragmentOrbital(fragment_A, level);
179 Orbitals orbitals_copy = orbitals;
180 orbitals_copy.MOs().eigenvectors() = orbital;
181 orbitals_copy.MOs().eigenvalues() = Eigen::VectorXd::Zero(1);
182 std::string filename =
183 "podcoupling_" + label + "_orb" + std::to_string(level) + ".cube";
184 writer.WriteFile(filename, orbitals_copy,
185 QMState(QMStateType::KSstate, 0, false), false);
186 XTP_LOG(Log::error, log_) << " wrote " << filename << flush;
187 // Printed alongside every cube file, not behind a separate
188 // option -- cheap to compute (only ever sorts this fragment's
189 // own, modest-sized AO set), and directly explains what the
190 // cube file itself shows: which specific AO, on which atom,
191 // actually dominates this orbital, since large density visible
192 // on the OTHER fragment's own physical space in the rendered
193 // isosurface does NOT mean a nonzero coefficient there (there
194 // never is one) -- it means a spatial tail from an AO on THIS
195 // fragment, identified here directly.
197 << pod.DescribeFragmentOrbitalComposition(fragment_A, level) << flush;
198 };
199 for (Index levelA = homoA - numberofstatesA_ + 1;
200 levelA <= lumoA + numberofstatesA_ - 1; ++levelA) {
201 WriteFragmentOrbitalCube(true, levelA, "fragA");
202 }
203 for (Index levelB = homoB - numberofstatesB_ + 1;
204 levelB <= lumoB + numberofstatesB_ - 1; ++levelB) {
205 WriteFragmentOrbitalCube(false, levelB, "fragB");
206 }
207 }
208
209 std::cout << log_;
210 // Explicit trailing newline: confirmed directly, from the user's
211 // own real run, that xtp_tools.cc's own execute() ends right after
212 // tool_->Evaluate() with no final newline anywhere in the shared
213 // framework -- the shell's own next prompt was running directly
214 // into this tool's own last line of output as a result. This is a
215 // local, low-risk fix within this tool's own Run() specifically,
216 // NOT a fix to the shared framework itself (which affects every
217 // existing tool, not just this one, and would need its own,
218 // separate, deliberate change and testing before touching).
219 std::cout << std::endl;
220
221 return true;
222}
223
224} // namespace xtp
225} // namespace votca
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
const Eigen::MatrixXd & eigenvectors() const
Definition eigensystem.h:33
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
T as() const
return value as type
Definition property.h:283
T ifExistsReturnElseReturnDefault(const std::string &key, T defaultvalue) const
Definition property.h:321
void WriteFile(const std::string &filename, const Orbitals &orb, QMState state, bool dostateonly) const
std::vector< Index > CreateIndexVector(const std::string &Ids) const
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
const tools::EigenSystem & MOs() const
Return read-only access to alpha/restricted molecular orbitals.
Definition orbitals.h:192
void ReadFromCpt(const std::string &filename)
Read the orbital container from a checkpoint file on disk.
Definition orbitals.cc:1201
Index getFragmentAHomoIndex() const
void CalculateCouplings(Index numberofstatesA, Index numberofstatesB)
double getCouplingElement(Index levelA, Index levelB) const
Eigen::VectorXd GetFragmentOrbital(bool fragment_A, Index level) const
Index getFragmentBLumoIndex() const
Index getFragmentALumoIndex() const
Index getFragmentBHomoIndex() const
std::string DescribeFragmentOrbitalComposition(bool fragment_A, Index level, Index top_n=5) const
Eigen::Array< Index, 3, 1 > cube_steps_
std::vector< Index > fragment_B_atoms_
std::vector< Index > fragment_A_atoms_
void ParseOptions(const tools::Property &user_options) final
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
Definition qmstate.h:135
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
#define XTP_LOG(level, log)
Definition logger.h:40
const double hrt2ev
Definition constants.h:53
void setMaxThreads(Index)
Definition eigen.h:158
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
static Level current_level
Definition globals.h:30