-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Surface forces (after rebasing #488) #497
Changes from 103 commits
437b563
ff8f386
1e9fb06
a5af9de
d60ff3c
3364258
2207f58
b5de572
f70e6f2
8ab1f27
d99c387
b268225
261a974
70f426e
992d06d
c1d2e3a
58aabc7
de741c2
9e8539a
31c90be
81bd73d
a28b7b6
4cd817e
e8a73c8
cf5f561
38be4f1
02f9890
f48edba
767f7f4
7d30a9c
568103a
dbff4dd
b7aab7f
7189059
f9c8967
6eddf4d
f4ac2a6
1d4bc20
5b6fca2
83b7e15
3e728ee
2f94d98
ea137c8
b4bacab
8f81ecd
c2cb775
7167246
95eceb6
8d52878
5435552
bb1a651
5955cab
5517f5b
86497a0
3ac0018
d244b9c
fed683f
24d80df
542e071
8527418
1f03edc
cf4b6e7
1edb31e
9f32c9f
03a6280
a6894c0
66bc391
f4e78a9
d270102
c239c0e
02e719a
2165872
92e693d
11e7842
b7f7a5a
6684133
ac6fde6
92f955c
a16ce05
91217e0
4222d22
a7384c1
5175b38
cf6b73f
e08ea9d
945d9b0
dbd5a72
2cd611e
5464d55
1594679
22ec0eb
db37881
980fe03
99d0357
f7a2523
d4a7820
ecb8023
74fc083
d4640b7
92c7ce3
dc430cf
c3b7122
412a80c
da85b58
b822448
2e0fb62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -416,6 +416,34 @@ sections: | |
default: false | ||
docstring: | | ||
Compute Hirshfeld charges. | ||
- name: Forces | ||
docstring: | | ||
Define parameters for the computation of forces. | ||
keywords: | ||
- name: method | ||
type: str | ||
default: surface_integrals | ||
predicates: | ||
- value.lower() in ['surface_integrals', 'hellmann_feynman'] | ||
docstring: | | ||
Method for computing forces. ``surface_integrals`` (more accurate) uses surface | ||
integrals over the quantum mechanical stress tensor, while ``hellmann_feynman`` uses the Hellmann-Feynman | ||
theorem. | ||
- name: surface_integral_precision | ||
type: str | ||
default: medium | ||
predicates: | ||
- value.lower() in ['low', 'medium', 'high'] | ||
docstring: | | ||
Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the | ||
surface integration. | ||
- name: radius_factor | ||
type: float | ||
default: 0.6 | ||
docstring: | | ||
Sets the radius of the surface used in the computation of forces. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, the default is also not 0.5 did you run the parameter update script? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fixed that too now :-) Thanks for pointing that out! |
||
The radius is given by this factor times the distance to the neariest neighbour. Must be between 0.1 and 0.9. | ||
This should rarely need to be changed. Different values can change the accuracy of the forces. | ||
- name: ExternalFields | ||
docstring: | | ||
Define external electromagnetic fields. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,17 +36,17 @@ add_subdirectory(properties) | |
add_subdirectory(qmfunctions) | ||
add_subdirectory(qmoperators) | ||
add_subdirectory(scf_solver) | ||
add_subdirectory(surface_forces) | ||
add_subdirectory(tensor) | ||
add_subdirectory(utils) | ||
|
||
target_compile_definitions(mrchem PRIVATE | ||
HIRSHFELD_SOURCE_DIR="${HIRSHFELD_SOURCE_DIR}" | ||
HIRSHFELD_INSTALL_DIR="${HIRSHFELD_INSTALL_DIR}" | ||
) | ||
|
||
target_compile_definitions(mrchem PRIVATE | ||
AZORA_POTENTIALS_SOURCE_DIR="${AZORA_POTENTIALS_SOURCE_DIR}" | ||
AZORA_POTENTIALS_INSTALL_DIR="${AZORA_POTENTIALS_INSTALL_DIR}" | ||
LEBVEDEV_SOURCE_DIR="${LEBVEDEV_SOURCE_DIR}" | ||
LEBVEDEV_INSTALL_DIR="${LEBVEDEV_INSTALL_DIR}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can delete these lines |
||
) | ||
|
||
target_link_libraries(mrchem | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,7 @@ | |
#include "qmoperators/one_electron/NuclearOperator.h" | ||
#include "qmoperators/one_electron/ZoraOperator.h" | ||
#include "qmoperators/one_electron/AZoraPotential.h" | ||
#include "qmoperators/one_electron/NablaOperator.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not needed |
||
|
||
#include "qmoperators/one_electron/H_BB_dia.h" | ||
#include "qmoperators/one_electron/H_BM_dia.h" | ||
|
@@ -83,8 +84,10 @@ | |
#include "environment/LPBESolver.h" | ||
#include "environment/PBESolver.h" | ||
#include "environment/Permittivity.h" | ||
|
||
#include "surface_forces/SurfaceForce.h" | ||
#include "properties/hirshfeld/HirshfeldPartition.h" | ||
#include <fstream> | ||
#include <filesystem> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not needed |
||
|
||
#include "mrdft/Factory.h" | ||
|
||
|
@@ -117,7 +120,7 @@ namespace scf { | |
bool guess_orbitals(const json &input, Molecule &mol); | ||
bool guess_energy(const json &input, Molecule &mol, FockBuilder &F); | ||
void write_orbitals(const json &input, Molecule &mol); | ||
void calc_properties(const json &input, Molecule &mol); | ||
void calc_properties(const json &input, Molecule &mol, const json &json_fock); | ||
void plot_quantities(const json &input, Molecule &mol); | ||
} // namespace scf | ||
|
||
|
@@ -318,7 +321,7 @@ json driver::scf::run(const json &json_scf, Molecule &mol) { | |
|
||
if (json_out["success"]) { | ||
if (json_scf.contains("write_orbitals")) scf::write_orbitals(json_scf["write_orbitals"], mol); | ||
if (json_scf.contains("properties")) scf::calc_properties(json_scf["properties"], mol); | ||
if (json_scf.contains("properties")) scf::calc_properties(json_scf["properties"], mol, json_fock); | ||
if (json_scf.contains("plots")) scf::plot_quantities(json_scf["plots"], mol); | ||
} | ||
|
||
|
@@ -471,7 +474,7 @@ void driver::scf::write_orbitals(const json &json_orbs, Molecule &mol) { | |
* input section, and will compute all properties which are present in this input. | ||
* This includes the diamagnetic contributions to the magnetic response properties. | ||
*/ | ||
void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { | ||
void driver::scf::calc_properties(const json &json_prop, Molecule &mol, const json &json_fock) { | ||
Timer t_tot, t_lap; | ||
auto plevel = Printer::getPrintLevel(); | ||
if (plevel == 1) mrcpp::print::header(1, "Computing ground state properties"); | ||
|
@@ -519,12 +522,29 @@ void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { | |
if (json_prop.contains("geometric_derivative")) { | ||
t_lap.start(); | ||
mrcpp::print::header(2, "Computing geometric derivative"); | ||
for (const auto &item : json_prop["geometric_derivative"].items()) { | ||
const auto &id = item.key(); | ||
const double &prec = item.value()["precision"]; | ||
const double &smoothing = item.value()["smoothing"]; | ||
GeometricDerivative &G = mol.getGeometricDerivative(id); | ||
auto &nuc = G.getNuclear(); | ||
GeometricDerivative &G = mol.getGeometricDerivative("geom-1"); | ||
auto &nuc = G.getNuclear(); | ||
|
||
// calculate nuclear gradient | ||
for (auto k = 0; k < mol.getNNuclei(); ++k) { | ||
const auto nuc_k = nuclei[k]; | ||
auto Z_k = nuc_k.getCharge(); | ||
auto R_k = nuc_k.getCoord(); | ||
nuc.row(k) = Eigen::RowVector3d::Zero(); | ||
for (auto l = 0; l < mol.getNNuclei(); ++l) { | ||
if (l == k) continue; | ||
const auto nuc_l = nuclei[l]; | ||
auto Z_l = nuc_l.getCharge(); | ||
auto R_l = nuc_l.getCoord(); | ||
std::array<double, 3> R_kl = {R_k[0] - R_l[0], R_k[1] - R_l[1], R_k[2] - R_l[2]}; | ||
auto R_kl_3_2 = std::pow(math_utils::calc_distance(R_k, R_l), 3.0); | ||
nuc.row(k) -= Eigen::Map<Eigen::RowVector3d>(R_kl.data()) * (Z_k * Z_l / R_kl_3_2); | ||
} | ||
} | ||
// calculate electronic gradient using the Hellmann-Feynman theorem | ||
if (json_prop["geometric_derivative"]["geom-1"]["method"] == "hellmann_feynman") { | ||
const double &prec = json_prop["geometric_derivative"]["geom-1"]["precision"]; | ||
const double &smoothing = json_prop["geometric_derivative"]["geom-1"]["smoothing"]; | ||
auto &el = G.getElectronic(); | ||
|
||
for (auto k = 0; k < mol.getNNuclei(); ++k) { | ||
|
@@ -534,19 +554,24 @@ void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { | |
double c = detail::nuclear_gradient_smoothing(smoothing, Z_k, mol.getNNuclei()); | ||
NuclearGradientOperator h(Z_k, R_k, prec, c); | ||
h.setup(prec); | ||
nuc.row(k) = Eigen::RowVector3d::Zero(); | ||
for (auto l = 0; l < mol.getNNuclei(); ++l) { | ||
if (l == k) continue; | ||
const auto nuc_l = nuclei[l]; | ||
auto Z_l = nuc_l.getCharge(); | ||
auto R_l = nuc_l.getCoord(); | ||
std::array<double, 3> R_kl = {R_k[0] - R_l[0], R_k[1] - R_l[1], R_k[2] - R_l[2]}; | ||
auto R_kl_3_2 = std::pow(math_utils::calc_distance(R_k, R_l), 3.0); | ||
nuc.row(k) -= Eigen::Map<Eigen::RowVector3d>(R_kl.data()) * (Z_k * Z_l / R_kl_3_2); | ||
} | ||
el.row(k) = h.trace(Phi).real(); | ||
h.clear(); | ||
} | ||
// calculate electronic gradient using the surface integrals method | ||
} else if (json_prop["geometric_derivative"]["geom-1"]["method"] == "surface_integrals") { | ||
double prec = json_prop["geometric_derivative"]["geom-1"]["precision"]; | ||
std::string leb_prec = json_prop["geometric_derivative"]["geom-1"]["surface_integral_precision"]; | ||
double radius_factor = json_prop["geometric_derivative"]["geom-1"]["radius_factor"]; | ||
Eigen::MatrixXd surfaceForces = surface_force::surface_forces(mol, Phi, prec, json_fock, leb_prec, radius_factor); | ||
GeometricDerivative &G = mol.getGeometricDerivative("geom-1"); | ||
auto &nuc = G.getNuclear(); | ||
auto &el = G.getElectronic(); | ||
// set electronic gradient | ||
for (int k = 0; k < mol.getNNuclei(); k++) { | ||
el.row(k) = surfaceForces.row(k) - nuc.row(k); | ||
} | ||
} else { | ||
MSG_ABORT("Invalid method for geometric derivative"); | ||
} | ||
mrcpp::print::footer(2, t_lap, 2); | ||
if (plevel == 1) mrcpp::print::time(1, "Geometric derivative", t_lap); | ||
|
@@ -783,7 +808,7 @@ json driver::rsp::run(const json &json_rsp, Molecule &mol) { | |
F_0.setup(unpert_prec); | ||
if (plevel == 1) mrcpp::print::footer(1, t_unpert, 2); | ||
|
||
if (json_rsp.contains("properties")) scf::calc_properties(json_rsp["properties"], mol); | ||
if (json_rsp.contains("properties")) scf::calc_properties(json_rsp["properties"], mol, unpert_fock); | ||
|
||
/////////////////////////////////////////////////////////// | ||
////////////// Preparing Perturbed System ///////////// | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#pragma once | ||
|
||
#include "tensor/RankOneOperator.h" | ||
|
||
#include "qmoperators/QMDerivative.h" | ||
#include "qmoperators/one_electron/NablaOperator.h" | ||
|
||
namespace mrchem { | ||
|
||
/** @class HessianOperator | ||
* | ||
* @brief Hessian operator | ||
* | ||
* This Hessian operator stores the second derivatives of Orbitals in an OrbitalVector. The ordering of the indices is | ||
* [xx, yy, zz, yz, xz, xy]. | ||
*/ | ||
class HessianOperator final : public RankOneOperator<6> { | ||
public: | ||
HessianOperator(std::shared_ptr<mrcpp::DerivativeOperator<3>> D1, std::shared_ptr<mrcpp::DerivativeOperator<3>> D2, double prec) { | ||
bool imag = false; | ||
NablaOperator N1 = NablaOperator(D1, imag); | ||
NablaOperator N2 = NablaOperator(D2, imag); | ||
N1.setup(prec); | ||
N2.setup(prec); | ||
|
||
// Invoke operator= to assign *this operator | ||
RankOneOperator<6> &d = (*this); | ||
d[0] = N2[0]; | ||
d[1] = N2[1]; | ||
d[2] = N2[2]; | ||
d[3] = N1[1] * N1[2]; | ||
d[4] = N1[0] * N1[2]; | ||
d[5] = N1[0] * N1[1]; | ||
|
||
d[0].name() = "del[x]del[x]"; | ||
d[1].name() = "del[y]del[y]"; | ||
d[2].name() = "del[z]del[z]"; | ||
d[3].name() = "del[y]del[z]"; | ||
d[4].name() = "del[x]del[z]"; | ||
d[5].name() = "del[x]del[y]"; | ||
} | ||
}; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't you change that to 0.5?