Loading...
Searching...
No Matches
Hessian Class Reference

#include <Hessian.h>

Public Member Functions

 Hessian (const Parameters &params, Matter *matter)
 ~Hessian ()=default
MatrixXd getHessian (Matter *matterIn, const VectorXi &atomsIn)
VectorXd getFreqs (Matter *matterIn, const VectorXi &atomsIn)
VectorXd removeZeroFreqs (const VectorXd &freqs)

Private Member Functions

bool calculate ()

Private Attributes

Mattermatter
const Parametersparameters
MatrixXd hessian
VectorXd freqs
VectorXi atoms
eonc::log::Scoped log

Detailed Description

Definition at line 21 of file Hessian.h.

Constructor & Destructor Documentation

◆ Hessian()

Hessian::Hessian ( const Parameters & params,
Matter * matter )

Definition at line 78 of file Hessian.cpp.

79 : matter{matter},
80 parameters{params} {
81 hessian.resize(0, 0);
82 freqs.resize(0);
83}
Matter * matter
Definition Hessian.h:32
VectorXd freqs
Definition Hessian.h:36
const Parameters & parameters
Definition Hessian.h:33
MatrixXd hessian
Definition Hessian.h:35

◆ ~Hessian()

Member Function Documentation

◆ calculate()

bool Hessian::calculate ( )
private

Definition at line 113 of file Hessian.cpp.

113 {
114 int nAtoms = matter->numberOfAtoms();
115
116 int size = static_cast<int>(atoms.rows()) * 3;
117 QUILL_LOG_DEBUG(log, "[Hessian] Hessian size: {}\n", size);
118 if (size == 0) {
119 return false;
120 }
121
122 // Mobile-atom polarity: indices in `atoms` are FD-displaced DOF owners.
123 for (int a = 0; a < atoms.rows(); ++a) {
124 const long idx = atoms(a);
125 if (idx < 0 || idx >= nAtoms) {
126 QUILL_LOG_ERROR(log,
127 "[Hessian] atom index {} out of range [0, {}) at list "
128 "entry {}; aborting FD Hessian",
129 idx, nAtoms, a);
130 return false;
131 }
132 }
133
134 Matter matterTemp(*matter);
135 double dr = parameters.main_options.finiteDifference;
136 if (!(dr > 0.0) || !std::isfinite(dr)) {
137 QUILL_LOG_ERROR(log, "[Hessian] invalid finiteDifference dr={}\n", dr);
138 return false;
139 }
140
141 const bool useCentral = isCentralScheme(parameters.hessian_options.fd_scheme);
142 const std::string &ckptPath = parameters.hessian_options.checkpoint_path;
143 const bool wantResume =
144 parameters.hessian_options.resume && !ckptPath.empty();
145
146 AtomMatrix pos = matter->getPositions();
147 AtomMatrix posDisplace(nAtoms, 3);
148 AtomMatrix posTemp(nAtoms, 3);
149 AtomMatrix force0(nAtoms, 3);
150 AtomMatrix forcePlus(nAtoms, 3);
151 AtomMatrix forceMinus(nAtoms, 3);
152
153 hessian.resize(size, size);
154 hessian.setZero();
155
156 int startCol = 0;
157 if (wantResume && loadColumnCheckpoint(ckptPath, size, startCol, hessian)) {
158 QUILL_LOG_DEBUG(log, "[Hessian] resume from column {} / {}\n", startCol,
159 size);
160 } else {
161 startCol = 0;
162 hessian.setZero();
163 }
164
165 force0 = matterTemp.getForces();
166 if (!force0.allFinite()) {
167 QUILL_LOG_ERROR(log, "[Hessian] non-finite forces at undisplaced geometry; "
168 "aborting FD Hessian");
169 return false;
170 }
171
172 for (int i = startCol; i < size; i++) {
173 posDisplace.setZero();
174 posDisplace(atoms(i / 3), i % 3) = dr;
175
176 posTemp = pos + posDisplace;
177 matterTemp.setPositions(posTemp);
178 forcePlus = matterTemp.getForces();
179 if (!forcePlus.allFinite()) {
180 QUILL_LOG_ERROR(log,
181 "[Hessian] non-finite forces for FD column {} (+); "
182 "aborting FD Hessian",
183 i);
184 return false;
185 }
186
187 if (useCentral) {
188 posTemp = pos - posDisplace;
189 matterTemp.setPositions(posTemp);
190 forceMinus = matterTemp.getForces();
191 if (!forceMinus.allFinite()) {
192 QUILL_LOG_ERROR(log,
193 "[Hessian] non-finite forces for FD column {} (-); "
194 "aborting FD Hessian",
195 i);
196 return false;
197 }
198 // Central: H_ij ≈ -(F+(xj) - F-(xj)) / (2 dr), mass-weighted
199 for (int j = 0; j < size; j++) {
200 const double dF =
201 forcePlus(atoms(j / 3), j % 3) - forceMinus(atoms(j / 3), j % 3);
202 hessian(i, j) = -dF / (2.0 * dr);
203 const double effMass = std::sqrt(matter->getMass(atoms(j / 3)) *
204 matter->getMass(atoms(i / 3)));
205 hessian(i, j) = eonc::safemath::safe_div(hessian(i, j), effMass, 0.0);
206 }
207 } else {
208 // One-sided (forward): H_ij ≈ -(F+(xj) - F0(xj)) / dr [default; cheaper]
209 for (int j = 0; j < size; j++) {
210 const double dF =
211 forcePlus(atoms(j / 3), j % 3) - force0(atoms(j / 3), j % 3);
212 hessian(i, j) = -dF / dr;
213 const double effMass = std::sqrt(matter->getMass(atoms(j / 3)) *
214 matter->getMass(atoms(i / 3)));
215 hessian(i, j) = eonc::safemath::safe_div(hessian(i, j), effMass, 0.0);
216 }
217 }
218
219 if (!ckptPath.empty()) {
220 // next column to compute after a clean interrupt
221 saveColumnCheckpoint(ckptPath, size, i + 1, hessian);
222 }
223 }
224
225 // Symmetrize (FD noise breaks H=H^T; required for vib analysis)
226 for (int i = 0; i < size; i++) {
227 for (int j = 0; j < i; j++) {
228 hessian(i, j) = (hessian(i, j) + hessian(j, i)) / 2;
229 hessian(j, i) = hessian(i, j);
230 }
231 }
232
233 if (!hessian.allFinite()) {
234 QUILL_LOG_ERROR(log, "[Hessian] non-finite entries after FD assembly; "
235 "aborting eigen solve");
236 return false;
237 }
238
239 if (!parameters.main_options.quiet) {
240 QUILL_LOG_DEBUG(log, "[Hessian] writing hessian\n");
241 std::ofstream hessfile;
242 hessfile.open("hessian.dat");
243 hessfile << hessian;
244 hessfile.close();
245 }
246
247 // Completed run: remove checkpoint so a later job does not resume stale cols
248 if (!ckptPath.empty()) {
249 std::remove(ckptPath.c_str());
250 }
251
252 double t0, t1;
253 eonc::helpers::getTime(&t0, nullptr, nullptr);
254 QUILL_LOG_DEBUG(log, "[Hessian] calculating eigen values of the hessian\n");
255 // ColMajor copy for SelfAdjointEigenSolver (eOn MatrixXd is RowMajor)
256 using ColMajorXd =
257 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
258 ColMajorXd hessianCol = hessian;
259 Eigen::SelfAdjointEigenSolver<ColMajorXd> es(hessianCol,
260 Eigen::EigenvaluesOnly);
261 eonc::helpers::getTime(&t1, nullptr, nullptr);
262 QUILL_LOG_DEBUG(log, "[Hessian] eigenvalue problem took {:.4e} seconds\n",
263 t1 - t0);
264 if (es.info() != Eigen::Success) {
265 QUILL_LOG_ERROR(log,
266 "[Hessian] SelfAdjointEigenSolver failed (info={}); "
267 "aborting",
268 static_cast<int>(es.info()));
269 return false;
270 }
271 freqs = es.eigenvalues();
272 if (!freqs.allFinite()) {
273 QUILL_LOG_ERROR(log, "[Hessian] non-finite eigenvalues; aborting");
274 return false;
275 }
276
277 return true;
278}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
eonc::log::Scoped log
Definition Hessian.h:40
VectorXi atoms
Definition Hessian.h:38
VectorXi atoms
Definition Hessian.h:38
MatrixXd hessian
Definition Hessian.h:35
void getTime(double *real, double *user, double *sys)
constexpr double safe_div(double num, double denom, double fallback=0.0)
Definition SafeMath.h:21

◆ getFreqs()

VectorXd Hessian::getFreqs ( Matter * matterIn,
const VectorXi & atomsIn )

Definition at line 99 of file Hessian.cpp.

99 {
100 if ((matter != matterIn) || (atoms.size() != atomsIn.size()) ||
101 (atoms != atomsIn) || (hessian.rows() == 0)) {
102 hessian.resize(0, 0);
103 matter = matterIn;
104 atoms = atomsIn;
105
106 if (!calculate()) {
107 freqs.resize(0);
108 }
109 }
110 return freqs;
111}
bool calculate()
Definition Hessian.cpp:113

◆ getHessian()

MatrixXd Hessian::getHessian ( Matter * matterIn,
const VectorXi & atomsIn )

Definition at line 85 of file Hessian.cpp.

85 {
86 if ((matter != matterIn) || (atoms.size() != atomsIn.size()) ||
87 (atoms != atomsIn) || (hessian.rows() == 0)) {
88 hessian.resize(0, 0);
89 matter = matterIn;
90 atoms = atomsIn;
91
92 if (!calculate()) {
93 hessian.resize(0, 0);
94 }
95 }
96 return hessian;
97}

◆ removeZeroFreqs()

VectorXd Hessian::removeZeroFreqs ( const VectorXd & freqs)

Definition at line 280 of file Hessian.cpp.

280 {
281 QUILL_LOG_DEBUG(log, "[Hessian] removing zero frequency modes");
282 int size = freqs.size();
283 if (size != 3 * matter->numberOfAtoms()) {
284 return freqs;
285 }
286 VectorXd newfreqs;
287 newfreqs.resize(size);
288 int nremoved = 0;
289 for (int i = 0; i < size; i++) {
290 if (std::abs(freqs(i)) > parameters.hessian_options.zero_freq_value) {
291 newfreqs(i - nremoved) = freqs(i);
292 } else {
293 nremoved++;
294 }
295 }
296
297 if (nremoved != 6) {
298 QUILL_LOG_ERROR(
299 log, "[Hessian] [error] Found {} trivial eigenmodes instead of 6",
300 nremoved);
301 }
302 return newfreqs.head(size - nremoved);
303}
VectorXd freqs
Definition Hessian.h:36

Member Data Documentation

◆ atoms

VectorXi eonc::Hessian::atoms
private

Definition at line 38 of file Hessian.h.

◆ freqs

VectorXd eonc::Hessian::freqs
private

Definition at line 36 of file Hessian.h.

◆ hessian

Definition at line 35 of file Hessian.h.

◆ log

Definition at line 40 of file Hessian.h.

◆ matter

Definition at line 32 of file Hessian.h.

◆ parameters

Definition at line 33 of file Hessian.h.


The documentation for this class was generated from the following files: