Routines for fourth-generation (4G) model predictions.
author: Alexander Knoll
Calculate all contributions to the 4G electrostatic energies, forces, and
lattice strain arising from environment-dependent electronegativities
and hardnesses.
This routine calculates
$$$
& \frac{\partial E_{\mathrm{elec}}}{\partial Q} \cdot \(
\frac{\partial\chi}{\partial R} + \frac{\partial J}{\partial R}
\)
$$$
for a fourth generation (3G) potential and adds it the forces and
lattice strain.
Please see the docstring of calculate_electrostatics_4g_single_structure_part_1 for
a more detailed explanations of the math.
Nodes of different colours represent the following:
Solid arrows point from a submodule to the (sub)module which it is
descended from. Dashed arrows point from a module or program unit to
modules which it uses.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.
Nodes of different colours represent the following:
Solid arrows point from a submodule to the (sub)module which it is
descended from. Dashed arrows point from a module or program unit to
modules which it uses.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.
Equilibrate global charges for a single structures based on the calculated
electronegativity and hardness values.
Arguments
num_atoms :
integer [in]– The total number of atoms in the structure. Note that this must always
be the global number of atoms, not only the number of atoms owned by
this MPI process or their ghost atoms.
total_charge :
real(DP) [in]– The total charge of the structure to which the sum of all atomic charges
is constrained.
atomic_electronegativities :
real(DP) (dim: (num_atoms)) [in]– The predicted electronegativity of each atom.
atomic_hardnesses :
real(DP) (dim: (num_atoms)) [in]– The predicted hardess of each atom.
qeq_solver :
class(AbstractChargeEquilibrator) [inout]– An charge equilibrator that was previously initialized for the current
structure.
atomic_charges :
real(DP) (dim: (num_atoms)) [inout]– The final equilibrated charges for all atoms. They are automatically
constrained to the `total_charge` hypersurface.
If l_initial_guess is false, the input charges
are used as initial guess.
l_initial_guess :
logical [in]– Whether or not initial guess should be calculated or are provided
in atomic_charges array
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed
arrows point from an interface to procedures which implement that interface.
This could include the module procedures in a generic interface or the
implementation in a submodule of an interface in a parent module.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.
This routine evaluates an electrostatic calculator
for a single structure based on equilibrated atomic charges and
applies the first part of the force trick to calculate the
total energy, as well as (incomplete) force and d_energy_d_strain contributions.
For a fourth generation (4G) potential, the total energy is
\(E_{\mathrm{total}(R, Q(R))} = E_{\mathrm{short}(R)} + E_{\mathrm{elec}(R, Q(R))}\).
This routine handles the second part of that sum.
As one can see, the 4G electrostatic forces \(\frac{\mathrm{d} E}{\mathrm{d} R}\)
are a function of both the Cartesian coordinates \(R\) and the global
charges \(Q(R)\). In mathematical terms:
$$$
\frac{\mathrm{d} E_{\mathrm{elec}}}{\mathrm{d} R} =
& \frac{\partial E_{\mathrm{elec}}}{\partial R}
& + \frac{\partial E_{\mathrm{elec}}}{\partial Q} \frac{\partial Q}{\partial R}
$$$
Applying the force trick, the electrostatic forces can be calculated as
$$$
\frac{\mathrm{d} E_{\mathrm{elec}}}{\mathrm{d} R} =
& \frac{\partial E_{\mathrm{elec}}}{\partial R}
& + \lambda \frac{\partial \mathbf{A}}{\partial R} * q
& + \frac{\partial E_{\mathrm{elec}}}{\partial Q} \cdot \(
\frac{\partial\chi}{\partial R} + \frac{\partial J}{\partial R}
\)
$$$
where \(A\) is the Coulomb matrix, \(\chi\) are the atomic electronegativities
and \(J\) is the atomic hardness.
This routine handles the first and second parts of that chain rule.
The force and strain contributions arising from the environment-dependent
electronegativities and hardnesses will be added in calculate_electrostatics_4g_single_structure_part_2.
Arguments
num_atoms :
integer [in]– The total number of atoms in the structure. Note that this must always
be the global number of atoms, not only the number of atoms owned by
this MPI process or their ghost atoms.
short_range_de_dq :
real(DP) (dim: (num_atoms)) [in]– The derivative of the short-range energy with respect to the
atomic charge neuron for all atoms in the structure. If electrostatic
screening is applied, it should be added to this quantity before
passing it to this routine. `short_range_de_dq` is added to the
electrostatic energy derivative wrt the atomic charges and used
to compute the `lagrange_charges` for the force trick.
lattice :
real(DP) (dim: (3,3)) [in]– The cell vectors of the structure.
calculate_forces :
logical [in]– Whether forces are calculated.
calculate_d_energy_d_strain :
logical [in]– Whether lattice strain contributions are calculated.
qeq_solver :
class(AbstractChargeEquilibrator) [inout]– An charge equilibrator that was previously initialized for the current
structure.
atomic_charges :
real(DP) (dim: (num_atoms)) [in]– The atomic charges as computed by the qeq_solver for the same committee
member that we are currently evaluating.
hardness :
real(DP) (dim: (num_atoms)) [in]
lagrange_charges :
real(DP) (dim: (num_atoms)) [out]– The constrained charges for each atom that are used for the force trick.
elec_energy :
real(DP) [out]– The calculated electrostatic energy.
elec_forces :
real(DP) (dim: (3,num_atoms)) [out]– The calculated electrostatic forces for all atoms in the structure.
ldo_force_trick :
logical [in]– Whether the force trick is applied to the electrostatic forces.
defaults to `.true.` if not present. The forces will simply be
incorrect if this is set to `.false.`, do only use this if you
know what you are doing.
ldo_elec_force_trick :
logical [in]– Whether we consider dE_elec/dq during the force trick. If this is
.false., only the short-range dE/dQ term will be used for computing
the Lagrangian charges. The electrostatic forces will be
incorrect if this is set to `.false.`, do only use this if you
know what you are doing. It is needed in some training scenarios.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed
arrows point from an interface to procedures which implement that interface.
This could include the module procedures in a generic interface or the
implementation in a submodule of an interface in a parent module.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.
num_atoms :
integer [in]– The total number of atoms in the structure that
reside on this process. This is the sum of the local atoms
belonging to this MPI process and the ghost atoms which
are copies of local atoms from other MPI processes that
build up the neighbor list of owned local atoms.
num_local_atoms :
integer [in]– The number of atoms owned by this MPI process.
atom_offset_on_process :
integer [in]– The offset of the id on process for all local atoms.
lagrange_charges :
real(DP) (dim: (num_atoms)) [in]– The previously calculated auxiliary charges for each atom in the structure.
charges :
real(DP) (dim: (num_atoms)) [in]– The previously calculated charges for each atom in the structure.
chi_feature_calculator :
type(FeatureCalculator) [in]– An evaluated feature calculator containing all derivatives
dG/dxyz for the features of the atomic electronegativities.
hardness_feature_calculator :
type(FeatureCalculator) [in]– An evaluated feature calculator containing all derivatives
dG/dxyz for the features of the atomic hardnesses.
neighbor_lists :
type(FeatureMapNeighborList) (dim: (:)) [in]– A list containing at the least the neighbor list used
by the given `feature_calculator`s.
d_chi_d_features :
real(DP) (dim: (:,:)) [in]– The derivatives of the atomic electronegativities with respect to the
input features of the model that was used to predict them.
d_hardness_d_features :
real(DP) (dim: (:,:)) [in]– The derivatives of the atomic hardnesses with respect to the
input features of the model that was used to predict them.
calculate_forces :
logical [in]– Whether forces are calculated.
calculate_d_energy_d_strain :
logical [in]– Whether lattice strain contributions are calculated.
forces :
real(DP) (dim: (3,num_atoms)) [inout]– The calculated force contributions of the environment-dependent
atomic electronegativities and hardnesses will be added to this array
for all local and ghost atoms on this process.
This array will usually already contain the
force contributions arising from the direct derivative of the
electrostatic energy with respect to the Cartesian coordinates.
d_energy_d_strain :
real(DP) (dim: (3,3)) [inout]– The calculated lattice strain contributions of the environment-dependent
atomic electronegativities and hardnesses will be added to this array
for all local and ghost atoms on this process.
This array will usually already contain the
strain contributions arising from the direct derivative of the
electrostatic energy with respect to the Cartesian coordinates.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed
arrows point from an interface to procedures which implement that interface.
This could include the module procedures in a generic interface or the
implementation in a submodule of an interface in a parent module.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed
arrows point from an interface to procedures which implement that interface.
This could include the module procedures in a generic interface or the
implementation in a submodule of an interface in a parent module.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.