Skip to content

Commit a711ab7

Browse files
committed
Add documentation to the solvent classes
1 parent e630106 commit a711ab7

File tree

11 files changed

+244
-38
lines changed

11 files changed

+244
-38
lines changed

doc/index.rst

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Features in MRChem-1.1:
4242
- Electric field
4343
+ Solvent effects
4444
- Cavity-free PCM
45+
- Poisson-Boltzmann PCM
46+
- Linearized Poisson-Boltzmann PCM
4547
* Properties:
4648
+ Ground state energy
4749
+ Dipole moment

doc/programmers/code_reference/environment.rst

+29-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,38 @@ Permittivity
2121
:protected-members:
2222
:private-members:
2323

24-
SCRF
24+
DHScreening
2525
------------
2626

27-
.. doxygenclass:: mrchem::SCRF
27+
.. doxygenclass:: mrchem::DHScreening
2828
:project: MRChem
2929
:members:
3030
:protected-members:
3131
:private-members:
32+
33+
GPESolver
34+
------------
35+
36+
.. doxygenclass:: mrchem::GPESolver
37+
:project: MRChem
38+
:members:
39+
:protected-members:
40+
:private-members:
41+
42+
PBESolver
43+
------------
44+
45+
.. doxygenclass:: mrchem::PBESolver
46+
:project: MRChem
47+
:members:
48+
:protected-members:
49+
:private-members:
50+
51+
LPBESolver
52+
------------
53+
54+
.. doxygenclass:: mrchem::LPBESolver
55+
:project: MRChem
56+
:members:
57+
:protected-members:
58+
:private-members:

doc/programming.bib

+17-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ @article{Fosso-Tande2013
333333
abstract = {We describe and present results of the implementation of the surface and volume polarization for electrostatics (SVPE) solvation model. Unlike most other implementations of the solvation model where the solute and the solvent are described with multiple numerical representations, our implementation uses a multiresolution, adaptive multiwavelet basis to describe both the solute and the solvent. This requires reformulation to use integral equations throughout as well as a conscious management of numerical properties of the basis. {\textcopyright} 2013 Elsevier B.V. All rights reserved.},
334334
author = {Fosso-Tande, Jacob and Harrison, Robert J.},
335335
doi = {10.1016/j.cplett.2013.01.065},
336-
file = {:home/ggerez/.local/share/data/Mendeley Ltd./Mendeley Desktop/Downloaded/Fosso-Tande, Harrison - 2013 - Implicit solvation models in a multiresolution multiwavelet basis.pdf:pdf},
337336
issn = {00092614},
338337
journal = {Chem. Phys. Lett.},
339338
pages = {179--184},
@@ -343,3 +342,20 @@ @article{Fosso-Tande2013
343342
year = {2013}
344343
}
345344

345+
@article{gerez2023,
346+
author = {Gerez S, Gabriel A. and Di Remigio Eikås, Roberto and Jensen, Stig Rune and Bjørgve, Magnar and Frediani, Luca},
347+
title = {Cavity-Free Continuum Solvation: Implementation and Parametrization in a Multiwavelet Framework},
348+
journal = {Journal of Chemical Theory and Computation},
349+
volume = {19},
350+
number = {7},
351+
pages = {1986-1997},
352+
year = {2023},
353+
doi = {10.1021/acs.jctc.2c01098},
354+
note ={PMID: 36933225},
355+
URL = {
356+
https://doi.org/10.1021/acs.jctc.2c01098
357+
},
358+
eprint = {
359+
https://doi.org/10.1021/acs.jctc.2c01098
360+
}
361+
}

doc/users/user_inp.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ as the ``world_origin`` is the true origin).
194194
WaveFunction
195195
------------
196196

197-
Here we give the wavefunction method and whether we run spin restricted (alpha
197+
Here we give the wavefunction method, environment used (for solvent models) and whether we run spin restricted (alpha
198198
and beta spins are forced to occupy the same spatial orbitals) or not (method
199199
must be specified, otherwise defaults are shown):
200200

@@ -203,6 +203,7 @@ must be specified, otherwise defaults are shown):
203203
WaveFunction {
204204
method = <wavefunction_method> # Core, Hartree, HF or DFT
205205
restricted = true # Spin restricted/unrestricted
206+
environment = pcm # Environment (pcm, pcm-pb, pcm-lpb) defaults to none
206207
}
207208
208209
There are currently four methods available: Core Hamiltonian, Hartree,
@@ -212,6 +213,11 @@ B3LYP``), *or* you can set ``method = DFT`` and specify a "non-standard"
212213
functional in the separate DFT section (see below). See
213214
:ref:`User input reference` for a list of available default functionals.
214215

216+
The solvent model implemented is a cavity free PCM, described in :cite:`gerez2023`.
217+
In this model we have implemented the Generalized Poisson equation solver, keyword ``pcm``, a
218+
Poisson-Boltzmann solver, keyword ``pcm-pb`` and a Linearized Poisson-Boltzmann solver, keyword ``pcm-lpb``.
219+
Further details for the calculation have to be included in the ``PCM`` section, see :ref: `User input reference` for details.
220+
215221
.. note::
216222

217223
Restricted open-shell wavefunctions are not supported.

src/environment/Cavity.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ namespace mrchem {
3737
namespace detail {
3838
/** @relates mrchem::Cavity
3939
* @brief Constructs a single element of the gradient of the Cavity.
40-
*
41-
* This constructs the analytical partial derivative of the Cavity \f$C\f$ with respect to \f$x\f$, \f$y\f$ or \f$z\f$
40+
* @details This constructs the analytical partial derivative of the Cavity \f$C\f$ with respect to \f$x\f$, \f$y\f$ or \f$z\f$
4241
* coordinates and evaluates it at a point \f$\mathbf{r}\f$. This is given for \f$x\f$ by
4342
* \f[
4443
* \frac{\partial C\left(\mathbf{r}\right)}{\partial x} = \left(1 - C{\left(\mathbf{r} \right)}\right)

src/environment/Cavity.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
namespace mrchem {
3535
/** @class Cavity
3636
* @brief Interlocking spheres cavity centered on the nuclei of the molecule.
37-
* The Cavity class represents the following function \cite Fosso-Tande2013
37+
* @details The Cavity class represents the following function \cite Fosso-Tande2013
3838
*
3939
* \f[
4040
* C(\mathbf{r}) = 1 - \prod^N_{i=1} (1-C_i(\mathbf{r})) \\
@@ -59,7 +59,7 @@ namespace mrchem {
5959
* - \f$R_{0,i}\f$ is the atomic radius. By default, the van der Waals radius.
6060
* - \f$\alpha_{i}\f$ is a scaling factor. By default, 1.1
6161
* - \f$\beta_{i}\f$ is a width scaling factor. By default, 0.5
62-
* - \f$\sigma_{i}\f$ is the width. By default, 0.2
62+
* - \f$\sigma_{i}\f$ is the width. By default, 0.2 bohr
6363
*/
6464

6565
class Cavity final : public mrcpp::RepresentableFunction<3> {

src/environment/DHScreening.h

+25-18
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,19 @@ namespace mrchem {
3434
/** @class DHScreening
3535
*
3636
* @brief Square of the Debye-Huckel Screening parameter.
37-
* TODO write proper docs for this function
38-
*
39-
* Here the \f$\bar{\kappa}\f$ is dependent on a separate cavity function with its own radius.
40-
*
37+
* @details
38+
* This is used for the Poisson-Boltzmann solver. The DHScreening function is defined as
39+
* \f[
40+
* \kappa^2(\mathbf{r}) = \begin{cases}
41+
* \kappa^2_{out} & \text{if } \mathbf{r} \notin \Omega_{ion} \\
42+
* 0.0 & \text{if } \mathbf{r} \in \Omega_{ion}
43+
* \end{cases}
44+
* \f]
45+
* This can be parametrized a number of ways. The one used here is
46+
* \f[
47+
* \kappa^2(\mathbf{r}) = (1 - C_{ion}(\mathbf{r})) \kappa^2_{out}
48+
* \f]
49+
* Where \f$C_{ion}(\mathbf{r})\f$ is the ion accessible Cavity function.
4150
*/
4251

4352
class Cavity;
@@ -47,40 +56,38 @@ class DHScreening final : public mrcpp::RepresentableFunction<3> {
4756
/** @brief Standard constructor. Initializes the #cavity_ion and #kappa_out with the input parameters.
4857
* @param cavity_ion interlocking spheres of Cavity class.
4958
* @param kappa_out value of the screening function outside the #cavity_ion.
50-
* @param formulation Decides which formulation of the #DHScreening function to implement, only continuous screening function available
51-
* available as of now.
59+
* @param formulation Decides which formulation of the #DHScreening function to implement, only continuous screening function available.
60+
* @details #kappa_out is given by
61+
* \f[
62+
* \kappa = \sqrt{\frac{2000 I_{0} e^2 N_a I_0}{\epsilon_{out} \epsilon_{in} k_B T}}
63+
* \f]
64+
* where \f$N_a\f$ is the Avogadro constant, e is the elementary charge, \f$I_0\f$ is the concentration of the ions,
65+
* \f$k_B\f$ is the Boltzmann constant, \f$T\f$ is the temperature, \f$\epsilon_{out}\f$ is the permittivity of the solvent and \f$\epsilon_{in}\f$ is the permittivity of free space.
5266
*/
53-
DHScreening(const Cavity & cavity_ion, double kappa_out, const std::string & formulation);
67+
DHScreening(const Cavity &cavity_ion, double kappa_out, const std::string &formulation);
5468

55-
/** @brief Evaluates DHScreening at a point in 3D space with respect to the state of #inverse.
69+
/** @brief Evaluates DHScreening at a point in 3D space.
5670
* @param r coordinates of a 3D point in space.
57-
* @return \f$\frac{1}{\epsilon(\mathbf{r})}\f$ if #inverse is true, and \f$ \epsilon(\mathbf{r})\f$ if #inverse is
58-
* false.
71+
* @return Value at point r.
5972
*/
6073
double evalf(const mrcpp::Coord<3> &r) const override;
6174

62-
/** @brief Calls the Cavity::getCoordinates() method of the #cavity instance. */
6375
auto getCoordinates() const { return this->cavity_ion.getCoordinates(); }
6476

65-
/** @brief Calls the Cavity::getRadii() method of the #cavity instance. */
6677
auto getRadii() const { return this->cavity_ion.getRadii(); }
6778

68-
/** @brief Returns the value of #kappa_out. */
6979
auto getKOut() const { return this->kappa_out; }
7080

71-
/** @brief Returns the cavity */
7281
Cavity getCavity() const { return this->cavity_ion; }
7382

74-
/** @brief Returns the formulation */
7583
std::string getFormulation() const { return this->formulation; }
7684

77-
/** @brief Print parameters */
7885
void printParameters() const;
7986

8087
private:
81-
double kappa_out; //!< Dielectric constant describing the permittivity of the solvent.
88+
double kappa_out; //!< value of the Debye-Huckel screening constant outside the ion accessible cavity.
8289
std::string formulation; //!< Formulation of the DHScreening function. Only linear variable is used now.
83-
Cavity cavity_ion; //!< A Cavity class instance.
90+
Cavity cavity_ion; //!< A Cavity class instance which describes the ion accessible cavity.
8491
};
8592

8693
} // namespace mrchem

src/environment/GPESolver.h

+109-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,27 @@
3232

3333
namespace mrchem {
3434
/** @class GPESolver
35-
* @brief class that performs the computation of the ReactionPotential, named Self Consistent Reaction Field.
35+
* @brief Solves the Generalized Poisson equation iteratively
36+
* @details The Generalized Poisson equation is given by
37+
* \f[
38+
* \nabla \cdot \left( \epsilon(\mathbf{r}) \nabla V(\mathbf{r}) \right) = -4\pi \rho(\mathbf{r})
39+
* \f]
40+
* where \f$\epsilon(\mathbf{r})\f$ is the permittivity, \f$V(\mathbf{r})\f$ is the total electrostatic potential and \f$\rho(\mathbf{r})\f$ is the molecular charge density defined as:
41+
* \f[
42+
* \rho(\mathbf{r}) = \rho_{el}(\mathbf{r}) + \rho_{nuc}(\mathbf{r})
43+
* \f]
44+
* where \f$\rho_{el}\f$ is the electronic charge density and \f$\rho_{nuc}\f$ is the nuclear charge density.
45+
* The Generalized Poisson equation is solved iteratively through a set of micro-iteration on each SCF-iteration by appliation of the Poisson operator \f$\mathcal{P}\f$ :cite:`Fosso-Tande2013`
46+
* \f[
47+
* V_R(\mathbf{r}) = \mathcal{P} \star \left[ \rho_{eff}(\mathbf{r}) - \rho(\mathbf{r}) + \gamma_s(\mathbf{r}) \right]
48+
* \f]
49+
* where \f$\gamma_s(\mathbf{r})\f$ is the surface charge distribution describing the polarization at the surface, \f$\rho_{eff}(\mathbf{r})\f$ is the effective charge density given by
50+
* \f$\frac{\rho(\mathbf{r})}{\epsilon(\mathbf{r})}\f$ and \f$V_R(\mathbf{r})\f$ is the reaction potential.
51+
*
52+
* We utilize a so-called dynamic threshold to more easily converge the reaction potential. This is done by setting the convergence threshold of the micro-iterations to
53+
* the MO update of the previous SCF iteration, unless the MO update is small enough (once the quality of the MOs is good enough, we use the default convergence threshold).
54+
* Another optimization used is that we utilize the previous SCF converged Reaction potential as an initial guess for the next micro-iterations. These procedures are
55+
* investigated and explained in :cite:`gerez2023`
3656
*/
3757
class Nuclei;
3858
class KAIN;
@@ -49,6 +69,12 @@ class GPESolver {
4969

5070
~GPESolver();
5171

72+
/** @brief Sets the convergence threshold for the micro-iterations, used with dynamic thresholding.
73+
* @param prec value to set the convergence threshold to
74+
* @return the current convergence threshold.
75+
* @details will check if the MO update is small enough (ten times as big) wrt. to the scf convergence threshold, if so, it will use the default convergence threshold.
76+
* If not, it will use the MO update as the convergence threshold.
77+
*/
5278
double setConvergenceThreshold(double prec);
5379

5480
mrcpp::ComplexFunction &getCurrentReactionPotential() { return this->Vr_n; }
@@ -58,12 +84,23 @@ class GPESolver {
5884
void updateMOResidual(double const err_t) { this->mo_residual = err_t; }
5985

6086
friend class ReactionPotential;
87+
88+
/** @brief Computes the energy contributions from the reaction potential
89+
* @param rho_el the electronic charge density
90+
* @return a tuple containing the electronic and nuclear energy contributions
91+
* @details We compute the reaction energy through the following integral:
92+
* \f[
93+
* E_{R} = \frac{1}{2}\int \rho_{el}(\mathbf{r}) V_R(\mathbf{r}) d\mathbf{r} + \frac{1}{2} \int \rho_{nuc}(\mathbf{r}) V_R(\mathbf{r}) d\mathbf{r}
94+
* \f]
95+
* Each term represents the electronic and nuclear contributions to the reaction energy, respectively.
96+
* We compute each term separately, and return a tuple containing both.
97+
*/
6198
auto computeEnergies(const Density &rho_el) -> std::tuple<double, double>;
6299

63100
protected:
64101
void clear();
65102
bool dynamic_thrs;
66-
std::string density_type;
103+
std::string density_type; //!< Decides which density we will use for computing the reaction potential, options are ``total``, ``electronic`` and ``nuclear``.
67104
std::string solver_name = "Generalized Poisson";
68105

69106
int max_iter;
@@ -79,24 +116,93 @@ class GPESolver {
79116
// another one could be to define a representable function which only has the exact analytical form of the nuclear contribution.
80117
// Since we already have \nabla^2 V_nuc = -4*pi*rho_nuc (nuclear potential) we could use this as a way to bypass computing rho_nuc at all
81118
// Same with the coulomb potential, which is basically what is left from V_vac after subtracting V_nuc. in one way we could just precompute both and
82-
// just iterate through V_R only. Only issue here is (1 -1\varepsilon)/\varepsilon * \rho_nuc as I am not sure how to represent this as an analytitcal function,
119+
// just iterate through V_R only. Only issue here is (1 -1\epsilon)/\epsilon * \rho_nuc as I am not sure how to represent this as an analytitcal function,
83120
// maybe after applying the Poisson operator?
84121

85122
mrcpp::ComplexFunction Vr_n;
86123

87124
std::shared_ptr<mrcpp::DerivativeOperator<3>> derivative;
88125
std::shared_ptr<mrcpp::PoissonOperator> poisson;
89126

127+
/** @brief computes density wrt. the density_type variable
128+
* @param Phi the molecular orbitals
129+
* @param rho_out Density function in which the density will be computed.
130+
* @details The total charge density is given by the sum of the electronic and nuclear charge densities:
131+
* \f[
132+
* \rho(\mathbf{r}) = \rho_{el}(\mathbf{r}) + \rho_{nuc}(\mathbf{r})
133+
* \f]
134+
* where \f$\rho_{el}\f$ is the electronic charge density and \f$\rho_{nuc}\f$ is the nuclear charge density.
135+
* The nuclear charge density is stored in the class variable #rho_nuc, while we compute the electronic charge density
136+
* from the molecular orbitals.
137+
* The class variable #density_type decides the density which will be computed in rho_out, options are ``total``, ``electronic`` and ``nuclear``.
138+
*/
90139
void computeDensities(OrbitalVector &Phi, Density &rho_out);
140+
141+
/** @brief Computes the surface charge distibution due to polarization at the solute-solvent boundary
142+
* @param potential Potential used to compute \f$\nabla V(\mathbf{r})\f$
143+
* @param out_gamma ComplexFunction in which the surface charge distribution will be computed.
144+
* @details The surface charge distribution is given by
145+
* \f[
146+
* \gamma_s(\mathbf{r}) = \frac{\log \frac{\epsilon_{in}}{\epsilon_{out}}}{4 \pi } \left( \nabla C(\mathbf{r}) \cdot \nabla V(\mathbf{r})\right)
147+
* \f]
148+
* where \f$\epsilon_{in}\f$ is the permittivity inside the cavity and \f$\epsilon_{out}\f$ is the permittivity outside the cavity.
149+
*/
91150
virtual void computeGamma(mrcpp::ComplexFunction &potential, mrcpp::ComplexFunction &out_gamma);
92151

152+
/** @brief Iterates once through the Generalized Poisson equation to compute the reaction potential
153+
* @param ingamma the surface charge distribution
154+
* @param Phi the molecular orbitals
155+
* @return the reaction potential
156+
* @details Constructs the effective charge density \f$\rho_{eff}(\mathbf{r})\f$ and the Poisson operator \f$\mathcal{P}\f$ as:
157+
* \f[
158+
* V_R(\mathbf{r}) = \mathcal{P} \star \left[ \rho_{eff}(\mathbf{r}) - \rho(\mathbf{r}) + \gamma_s(\mathbf{r}) \right]
159+
* \f]
160+
* where \f$\gamma_s(\mathbf{r})\f$ is the surface charge distribution describing the polarization at the surface, \f$\rho_{eff}(\mathbf{r})\f$ is the effective charge density given by
161+
* \f$\frac{\rho(\mathbf{r})}{\epsilon(\mathbf{r})}\f$ and \f$V_R(\mathbf{r})\f$ is the reaction potential.
162+
*/
93163
mrcpp::ComplexFunction solvePoissonEquation(const mrcpp::ComplexFunction &ingamma, mrchem::OrbitalVector &Phi);
94164

165+
/** @brief Uses KAIN to accelerate convergece of the reaction potential
166+
* @param dfunc the current update of the reaction potential
167+
* @param func the current reaction potential
168+
* @param kain the KAIN object
169+
*/
95170
void accelerateConvergence(mrcpp::ComplexFunction &dfunc, mrcpp::ComplexFunction &func, KAIN &kain);
96171

172+
/** @brief Iterates through the application of the Poisson operator to Solve the Generalized Poisson equation
173+
* @param V_vac the vacuum potential
174+
* @param Phi_p the molecular orbitals
175+
* @details Iterating through the application of the Poisson operator is done through a set of micro-iterations,
176+
* where the convergence threshold is set to the MO update of the previous SCF iteration.
177+
* The micro-iterations are done through the following steps:
178+
* -# Compute the total potential as \f$V(\mathbf{r}) = V_{vac}(\mathbf{r}) + V_R(\mathbf{r})\f$
179+
* -# Compute the surface charge distribution \f$\gamma_s(\mathbf{r})\f$ with #computeGamma
180+
* -# Compute a new reaction potential \f$V_R(\mathbf{r})\f$ by application of the Poisson operator with #solvePoissonEquation
181+
* -# Calculate the update of the reaction potential as \f$\Delta V_R(\mathbf{r}) = V_R(\mathbf{r}) - V_R^{old}(\mathbf{r})\f$
182+
* -# Accelerate convergence of the reaction potential through KAIN
183+
* -# Update the reaction potential as \f$V_R(\mathbf{r}) = V_R^{old}(\mathbf{r}) + \Delta V_R(\mathbf{r})\f$
184+
* -# Check if the reaction potential has converged, if not, repeat from step 1.
185+
*/
97186
void runMicroIterations(const mrcpp::ComplexFunction &V_vac, std::shared_ptr<mrchem::OrbitalVector> Phi_p);
187+
188+
/** @brief Setups and computes the reaction potential through the microiterations
189+
* @param V_vac the vacuum potential
190+
* @param Phi_p the molecular orbitals
191+
* @return The converged reaction potential for the current SCF iteration
192+
* @details An initial guess of the reaction potential is computed with the following steps:
193+
* -# Set the total potential as \f$V(\mathbf{r}) = V_{vac}(\mathbf{r})\f$
194+
* -# Compute the surface charge distribution \f$\gamma_s(\mathbf{r})\f$ from this potential
195+
* -# Iterate once through the application of the Poisson operator to return the initial guess of the reaction potential \f$V_R(\mathbf{r})\f$
196+
*
197+
* the method then runs the micro-iterations through #runMicroIterations and returns the converged reaction potential.
198+
* If this is not the first SCF iteration, the previous converged reaction potential is used as an initial guess for the micro-iterations.
199+
*/
98200
mrcpp::ComplexFunction &solveEquation(double prec, const std::shared_ptr<mrchem::OrbitalVector> &Phi_p);
99201

202+
/** @brief Frees the memory used by the FunctionTrees of the input Complexfunction and reallocates them.
203+
* @param function the ComplexFunction to reset
204+
* @details This is done to avoid memory leaks when the ComplexFunction is used in the micro-iterations.
205+
*/
100206
void resetComplexFunction(mrcpp::ComplexFunction &function);
101207

102208
virtual void printParameters() const;

0 commit comments

Comments
 (0)