Skip to content
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

Merged
merged 106 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 103 commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
437b563
density wrong
moritzgubler Apr 16, 2024
ff8f386
better plots
moritzgubler Apr 16, 2024
1e9fb06
add new directory
moritzgubler Apr 17, 2024
a5af9de
add docs
moritzgubler Apr 17, 2024
d60ff3c
add header
moritzgubler Apr 17, 2024
3364258
move stuff around
moritzgubler Apr 17, 2024
2207f58
it compiles
moritzgubler Apr 17, 2024
b5de572
maxwell test running
moritzgubler Apr 17, 2024
f70e6f2
maxwell stress correct
moritzgubler Apr 17, 2024
8ab1f27
xc extraction working
moritzgubler Apr 19, 2024
d99c387
add hessian operator
moritzgubler Apr 22, 2024
b268225
add test for kinetic stress
moritzgubler Apr 22, 2024
261a974
add other template
moritzgubler Apr 22, 2024
70f426e
change types
moritzgubler Apr 22, 2024
992d06d
working for tiny radius
moritzgubler Apr 22, 2024
c1d2e3a
surface force working for one orbital
moritzgubler Apr 23, 2024
58aabc7
cleanup surface force function
moritzgubler Apr 23, 2024
de741c2
multiple orbitals fix
moritzgubler Apr 23, 2024
9e8539a
delete unused stuff
moritzgubler Apr 23, 2024
31c90be
prepare for tests
moritzgubler Apr 23, 2024
81bd73d
more points
moritzgubler Apr 23, 2024
a28b7b6
switch to surface forces and debug info
moritzgubler Apr 23, 2024
4cd817e
fix initialization of nabla
moritzgubler Apr 24, 2024
e8a73c8
add check
moritzgubler Apr 24, 2024
cf5f561
reduce number of grid points
moritzgubler Apr 24, 2024
38be4f1
average over different radii
moritzgubler Apr 24, 2024
02f9890
more averaging
moritzgubler Apr 24, 2024
f48edba
pass operators
moritzgubler Apr 25, 2024
767f7f4
add timer
moritzgubler Apr 25, 2024
7d30a9c
better radii
moritzgubler Apr 25, 2024
568103a
add auto radius
moritzgubler May 1, 2024
dbff4dd
break symmetry
moritzgubler May 1, 2024
b7aab7f
make sqnm energy free
moritzgubler May 1, 2024
7189059
choose better radii
moritzgubler May 1, 2024
f9c8967
make radii more random
moritzgubler May 2, 2024
6eddf4d
less radii
moritzgubler May 2, 2024
f4ac2a6
add lebvedev shift integration
moritzgubler May 5, 2024
1d4bc20
larger tiny radius
moritzgubler May 5, 2024
5b6fca2
more moderate smoothing
moritzgubler May 6, 2024
83b7e15
more points
moritzgubler May 6, 2024
3e728ee
make forces faster
moritzgubler May 10, 2024
2f94d98
start work on finite nucleus
moritzgubler May 12, 2024
ea137c8
fix typo
moritzgubler May 31, 2024
b4bacab
update template and helper
moritzgubler May 31, 2024
8f81ecd
automatic changes
moritzgubler May 31, 2024
c2cb775
adjust driver
moritzgubler May 31, 2024
7167246
pass new parameters to code
moritzgubler May 31, 2024
95eceb6
add linebreaks
moritzgubler May 31, 2024
8d52878
input mech not yet working
moritzgubler Jun 4, 2024
5435552
fix all bugs
moritzgubler Jun 5, 2024
bb1a651
new lebvedev files
moritzgubler Jun 5, 2024
5955cab
add noise estimation
moritzgubler Jun 5, 2024
5517f5b
remove old comment
moritzgubler Jun 5, 2024
86497a0
use parameters from input file
moritzgubler Jun 5, 2024
3ac0018
move lebvedev files to share
moritzgubler Jun 5, 2024
d244b9c
install lebvedev data files and pass their location to source code in…
moritzgubler Jun 5, 2024
fed683f
adjust paths
moritzgubler Jun 5, 2024
24d80df
use fewer lebvedev points
moritzgubler Jun 5, 2024
542e071
add new parameter
moritzgubler Jun 6, 2024
8527418
convert matrix to vector
moritzgubler Jun 6, 2024
1f03edc
add finite nucleus but do not use it.
moritzgubler Jun 6, 2024
cf4b6e7
remove unused includes
moritzgubler Jun 12, 2024
1edb31e
add more documentation
moritzgubler Jun 12, 2024
9f32c9f
remove typo
moritzgubler Jul 17, 2024
03a6280
fix typo in doc
moritzgubler Jul 17, 2024
a6894c0
add lebvedev data
moritzgubler Jul 17, 2024
66bc391
add meta utils
moritzgubler Jul 17, 2024
f4e78a9
get rid of reading files
moritzgubler Jul 18, 2024
d270102
get rid of lebedev data files
moritzgubler Jul 18, 2024
c239c0e
suggestion from peter
moritzgubler Jul 19, 2024
02e719a
it compiles
moritzgubler Jul 19, 2024
2165872
fix it again
moritzgubler Jul 22, 2024
92e693d
start work on xcfun
moritzgubler Jul 23, 2024
11e7842
working but mess
moritzgubler Jul 30, 2024
b7f7a5a
better interface
moritzgubler Jul 31, 2024
6684133
gga working
moritzgubler Jul 31, 2024
ac6fde6
open shell gga working
moritzgubler Jul 31, 2024
92f955c
revert changes in xc operator
moritzgubler Jul 31, 2024
a16ce05
rename files
moritzgubler Jul 31, 2024
91217e0
rename functions
moritzgubler Jul 31, 2024
4222d22
move xc stress to seperate file
moritzgubler Jul 31, 2024
a7384c1
adjust tests
moritzgubler Jul 31, 2024
5175b38
add more documentation and namespaces
moritzgubler Jul 31, 2024
cf6b73f
remove averaging feature
moritzgubler Aug 1, 2024
e08ea9d
remove averaging parameters
moritzgubler Aug 1, 2024
945d9b0
update input parser
moritzgubler Aug 1, 2024
dbd5a72
output more digits in xyz file
moritzgubler Aug 6, 2024
2cd611e
make xc potentials visible
moritzgubler Aug 7, 2024
5464d55
make xc operator to get wavelet represantation of xc potential
moritzgubler Aug 7, 2024
1594679
use wavelet represenatation for xc potential in gga case
moritzgubler Aug 7, 2024
22ec0eb
add new radius_factor keyword.
moritzgubler Aug 7, 2024
db37881
remove prints
moritzgubler Aug 7, 2024
980fe03
remove orbitalvectors
moritzgubler Aug 8, 2024
99d0357
more prints
moritzgubler Aug 8, 2024
f7a2523
turn on xc stress again
moritzgubler Aug 8, 2024
d4a7820
debugging
moritzgubler Aug 12, 2024
ecb8023
remove prints
moritzgubler Aug 12, 2024
74fc083
mpi working
moritzgubler Aug 12, 2024
d4640b7
add test
moritzgubler Aug 12, 2024
92c7ce3
reorganize calculation of nuclear gradients
moritzgubler Aug 12, 2024
dc430cf
Fixes small leftovers after rebase
ilfreddy Nov 9, 2024
c3b7122
Default radius 0.5 and bug-fix for single atom
ilfreddy Nov 20, 2024
412a80c
Reverts to non-default radius factor 0.6
ilfreddy Nov 20, 2024
da85b58
Remove some unused lines
stigrj Nov 26, 2024
b822448
Update user_ref.rst
ilfreddy Nov 27, 2024
2e0fb62
Update template.yml
ilfreddy Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions doc/users/user_ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,33 @@ User input reference

**Default** ``user['GeometryOptimizer']['run']``

:Forces: Define parameters for the computation of forces.

:red:`Keywords`
:method: 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.

**Type** ``str``

**Default** ``surface_integrals``

**Predicates**
- ``value.lower() in ['surface_integrals', 'hellmann_feynman']``

:surface_integral_precision: Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the surface integration.

**Type** ``str``

**Default** ``medium``

**Predicates**
- ``value.lower() in ['low', 'medium', 'high']``

:radius_factor: Sets the radius of the surface used in the computation of forces. 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.

**Type** ``float``

**Default** ``0.6``
Copy link
Contributor

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?


:ExternalFields: Define external electromagnetic fields.

:red:`Keywords`
Expand Down
5 changes: 4 additions & 1 deletion python/mrchem/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def write_scf_solver(user_dict, wf_dict):
def write_scf_properties(user_dict, origin):
prop_dict = {}
if user_dict["Properties"]["dipole_moment"]:
prop_dict["dipole_moment"] = {}
prop_dict["dipole_moment"] = {}
prop_dict["dipole_moment"]["dip-1"] = {
"operator": "h_e_dip",
"precision": user_dict["world_prec"],
Expand All @@ -306,6 +306,9 @@ def write_scf_properties(user_dict, origin):
"operator": "h_nuc_grad",
"precision": user_dict["world_prec"],
"smoothing": user_dict["Precisions"]["nuclear_prec"],
"method": user_dict["Forces"]["method"],
"surface_integral_precision": user_dict["Forces"]["surface_integral_precision"],
"radius_factor": user_dict["Forces"]["radius_factor"],
}
if user_dict["Properties"]["hirshfeld_charges"]:
prop_dict["hirshfeld_charges"] = {}
Expand Down
18 changes: 18 additions & 0 deletions python/mrchem/input_parser/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,24 @@ def stencil() -> JSONDict:
'name': 'geometric_derivative',
'type': 'bool'}],
'name': 'Properties'},
{ 'keywords': [ { 'default': 'surface_integrals',
'name': 'method',
'predicates': [ 'value.lower() '
'in '
"['surface_integrals', "
"'hellmann_feynman']"],
'type': 'str'},
{ 'default': 'medium',
'name': 'surface_integral_precision',
'predicates': [ 'value.lower() '
"in ['low', "
"'medium', "
"'high']"],
'type': 'str'},
{ 'default': 0.5,
'name': 'radius_factor',
'type': 'float'}],
'name': 'Forces'},
{ 'keywords': [ { 'default': [],
'name': 'electric_field',
'predicates': [ 'len(value) == 0 '
Expand Down
27 changes: 27 additions & 0 deletions python/mrchem/input_parser/docs/user_ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,33 @@ User input reference

**Default** ``user['GeometryOptimizer']['run']``

:Forces: Define parameters for the computation of forces.

:red:`Keywords`
:method: 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.

**Type** ``str``

**Default** ``surface_integrals``

**Predicates**
- ``value.lower() in ['surface_integrals', 'hellmann_feynman']``

:surface_integral_precision: Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the surface integration.

**Type** ``str``

**Default** ``medium``

**Predicates**
- ``value.lower() in ['low', 'medium', 'high']``

:radius_factor: Sets the radius of the surface used in the computation of forces. 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.

**Type** ``float``

**Default** ``0.6``

:ExternalFields: Define external electromagnetic fields.

:red:`Keywords`
Expand Down
28 changes: 28 additions & 0 deletions python/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
Expand Down
6 changes: 3 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can delete these lines

)

target_link_libraries(mrchem
Expand Down
67 changes: 46 additions & 21 deletions src/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Contributor

Choose a reason for hiding this comment

The 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"
Expand All @@ -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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not needed


#include "mrdft/Factory.h"

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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 /////////////
Expand Down
4 changes: 2 additions & 2 deletions src/mrdft/Functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class Functional {
}
double XCenergy = 0.0;

Eigen::MatrixXd evaluate(Eigen::MatrixXd &inp) const;
Eigen::MatrixXd evaluate_transposed(Eigen::MatrixXd &inp) const;
friend class MRDFT;

protected:
Expand All @@ -78,8 +80,6 @@ class Functional {
virtual int getCtrInputLength() const = 0;
virtual int getCtrOutputLength() const = 0;

Eigen::MatrixXd evaluate(Eigen::MatrixXd &inp) const;
Eigen::MatrixXd evaluate_transposed(Eigen::MatrixXd &inp) const;
Eigen::MatrixXd contract(Eigen::MatrixXd &xc_data, Eigen::MatrixXd &d_data) const;
Eigen::MatrixXd contract_transposed(Eigen::MatrixXd &xc_data, Eigen::MatrixXd &d_data) const;

Expand Down
14 changes: 14 additions & 0 deletions src/properties/GeometricDerivative.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class GeometricDerivative final {
mrcpp::print::separator(0, '-');
print_utils::matrix(0, "Electronic", getElectronic());
print_utils::scalar(0, "Norm", getElectronic().norm(), "(au)");
mrcpp::print::separator(0, '-');
print_utils::scalar(0, "Est. var. of force error", variance(), "(au)", 4, true);
mrcpp::print::separator(0, '=', 2);
}

Expand All @@ -68,6 +70,18 @@ class GeometricDerivative final {
{"electronic_norm", getElectronic().norm()}};
}

/**
* @brief Compute the variance of the total force using the formula
* sigma = sqrt(1/(3N) * sum_i sum_j (F_{ij})^2) presented in
* Gubler et al.: Journal of Computational Physics: X Volume 17, November 2023, 100131
*/
double variance() const {
DoubleMatrix forces = getTensor();
Eigen::Vector3d total_force = forces.colwise().sum();
double force_variance = total_force.norm() * std::sqrt( 1.0 / (3.0 * forces.rows()) );
return force_variance;
}

protected:
DoubleMatrix nuclear;
DoubleMatrix electronic;
Expand Down
44 changes: 44 additions & 0 deletions src/qmoperators/one_electron/HessianOperator.h
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]";
}
};

}
4 changes: 3 additions & 1 deletion src/qmoperators/two_electron/XCOperator.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ class XCOperator final : public RankZeroOperator {
}
void clearSpin() { this->potential->setReal(nullptr); }

std::shared_ptr<XCPotential> getPotential() { return potential; }

private:
std::shared_ptr<XCPotential> potential{nullptr};
};

} // namespace mrchem
} // namespace mrchem
Loading
Loading