Loading...
Searching...
No Matches
spce_ccl.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
19#include <cassert>
20#include <cmath>
21#include <iostream>
22// #include "unit_system.hpp"
23
24using namespace forcefields;
25
26#if defined(FORCEFIELDS_UNIT_SYSTEM_HPP) && \
27 (FORCEFIELDS_UNIT_SYSTEM_HPP != \
28 FORCEFIELDS_UNIT_SYSTEM_ELECTRONVOLT_ANGSTROM_FEMTOSECOND_ECHARGE)
29using namespace unit_system;
30const double SpceCcl::roh_ = 1.0 * ANGSTROM;
31const double SpceCcl::theta_ =
32 std::acos(-1.0 / 3.0); // tetrahedron about 109.47*DEGREE
33const double SpceCcl::rhh_ = isoscelesBase(roh_, theta_);
34const double SpceCcl::charge_ = 0.4238 * ECHARGE;
35const double SpceCcl::charge2_ = charge_ * charge_;
36// Definition of A and B are inverted compared to original publication by
37// Berendsen
38const double SpceCcl::A_ = std::pow(0.3428 * NM, 12.0) * KJ_PER_MOL;
39const double SpceCcl::B_ = std::pow(0.37122 * NM, 6.0) * KJ_PER_MOL;
40const double SpceCcl::sigma_ = sigma(A_, B_);
41const double SpceCcl::epsilon_ = epsilon(A_, B_);
42const double SpceCcl::polarisationEnergy_ = 5.22 * KJ_PER_MOL;
43#else
44const double SpceCcl::roh_ = 1.0; // Angstrom
45const double SpceCcl::theta_ = 1.91063; // radians
46const double SpceCcl::rhh_ = 1.63299; // Angstrom
47const double SpceCcl::charge_ = 0.4238; // e
48const double SpceCcl::charge2_ = 0.179606; // e
49const double SpceCcl::A_ = 27291.6; // Angstrom^-1
50const double SpceCcl::B_ = 27.1223; // Angstrom^-1
51const double SpceCcl::sigma_ = 3.16556; // Angstrom
52const double SpceCcl::epsilon_ = 0.00673853; // eV
53const double SpceCcl::polarisationEnergy_ = 0.0541015; // eV
54#endif
55
58
59SpceCcl::SpceCcl(double cutoff, double switchingWidth)
60 : Ccl(cutoff, switchingWidth) {}
61
62void SpceCcl::computeHH_O_(const int nAtoms, const double R[], double F[],
63 double &U, const double b[]) {
64 computeHH_O_(nAtoms, R, F, U, b, 0);
65}
66
67void SpceCcl::computeHH_O_(const int nAtoms, const double R[], double F[],
68 double &U, const double b[], const bool fixed[]) {
69 int const nMolecules = nAtoms / 3;
70 const double (*const rh1)[6] = reinterpret_cast<const double (*)[6]>(R);
71 const double (*const rh2)[6] = reinterpret_cast<const double (*)[6]>(&R[3]);
72 const double (*const ro)[3] =
73 reinterpret_cast<const double (*)[3]>(&R[nMolecules * 6]);
74 double (*const fh1)[6] = reinterpret_cast<double (*)[6]>(F);
75 double (*const fh2)[6] = reinterpret_cast<double (*)[6]>(&F[3]);
76 double (*const fo)[3] = reinterpret_cast<double (*)[3]>(&F[nMolecules * 6]);
77 bool const(*const xh1)[2] = reinterpret_cast<bool const(*)[2]>(fixed);
78 bool const(*const xh2)[2] = reinterpret_cast<bool const(*)[2]>(&fixed[1]);
79 bool const(*const xo)[1] =
80 reinterpret_cast<bool const(*)[1]>(&fixed[nMolecules * 2]);
81 computeTemplate(nMolecules, rh1, rh2, ro, fh1, fh2, fo, U, b, xh1, xh2, xo);
82}
83
84char const *SpceCcl::getName() const { return "SpceCcl"; }
85
86void SpceCcl::lennardJonesWithCutoff(Water &w1, Water &w2, double &U) {
87 double z[3], z1;
88 distance(w1.ro_, w2.ro_, z, z1);
89 if (z1 <= cutoff_ - switchingWidth_) {
90 lennardJones(w1.ro_, w2.ro_, w1.fo_, w2.fo_, U, epsilon_, sigma_);
91 } else if (z1 < cutoff_) {
92 double f1[3] = {0}, f2[3] = {0};
93 double energy = 0.0;
94 lennardJones(w1.ro_, w2.ro_, f1, f2, energy, epsilon_, sigma_);
95 switching(w1.ro_, w2.ro_, f1, f2, energy);
96 U += energy;
97 for (int i = 0; i < 3; i++) {
98 w1.fo_[i] += f1[i];
99 w2.fo_[i] += f2[i];
100 };
101 };
102}
103
104void SpceCcl::coulombWithCutoff(Water &w1, Water &w2, double &U) {
105 double z[3], z1, z2;
106 distance(w1.rc_, w2.rc_, z, z1, z2);
107 if (z1 <= cutoff_ - switchingWidth_) {
108 coulombFull(w1, w2, U);
109 } else if (z1 < cutoff_) {
110 // store forces and energy of the full interaction in temporaries
111 double f1[3][3] = {{0}}, f2[3][3] = {{0}};
112 Water v1(w1.rh1_, w1.rh2_, w1.ro_, w1.rc_, f1[0], f1[1], f1[2]);
113 Water v2(w2.rh1_, w2.rh2_, w2.ro_, w2.rc_, f2[0], f2[1], f2[2]);
114 double energy = 0.0;
115 coulombFull(v1, v2, energy);
116 ChargeGroup<3> g1 = {v1.rc_, 0, f1};
117 ChargeGroup<3> g2 = {v2.rc_, 0, f2};
118 // Calculate the weakened forces and energy.
119 switching(g1, g2, energy, cutoff_, switchingWidth_);
120 // add weakened force and energy to those of other interactions.
121 U += energy;
122 for (int i = 0; i < 3; ++i) {
123 w1.fh1_[i] += v1.fh1_[i];
124 w1.fh2_[i] += v1.fh2_[i];
125 w1.fo_[i] += v1.fo_[i];
126 w2.fh1_[i] += v2.fh1_[i];
127 w2.fh2_[i] += v2.fh2_[i];
128 w2.fo_[i] += v2.fo_[i];
129 };
130 };
131}
132
133void SpceCcl::coulombFull(Water &w1, Water &w2, double &U) {
134 // Coulomb interactions between hydrogens
135 coulomb(w1.rh1_, w2.rh1_, w1.fh1_, w2.fh1_, U, charge2_);
136 coulomb(w1.rh1_, w2.rh2_, w1.fh1_, w2.fh2_, U, charge2_);
137 coulomb(w1.rh2_, w2.rh1_, w1.fh2_, w2.fh1_, U, charge2_);
138 coulomb(w1.rh2_, w2.rh2_, w1.fh2_, w2.fh2_, U, charge2_);
139 // interactions between H and O.
140 coulomb(w1.ro_, w2.rh1_, w1.fo_, w2.fh1_, U, -2.0 * charge2_);
141 coulomb(w1.ro_, w2.rh2_, w1.fo_, w2.fh2_, U, -2.0 * charge2_);
142 coulomb(w1.rh1_, w2.ro_, w1.fh1_, w2.fo_, U, -2.0 * charge2_);
143 coulomb(w1.rh2_, w2.ro_, w1.fh2_, w2.fo_, U, -2.0 * charge2_);
144 // interactions between O1, O2
145 coulomb(w1.ro_, w2.ro_, w1.fo_, w2.fo_, U, 4.0 * charge2_);
146}
147
148void SpceCcl::initialiseRho(Vector3 const &v, Rho &ro) {
149 // re_ = r_CCL and roh_ = r_SPC
150 ro._1 = (v._1 - roh_) / (v._1 - roh_ + re_);
151 ro._2 = ro._1 * ro._1;
152 ro._3 = ro._2 * ro._1;
153 double const a = v._1 - roh_ + re_;
154 double const d = re_ / a / a / v._1;
155 for (int i = 0; i < 3; ++i)
156 ro.n[i] = v.v[i] * d;
157}
158
159void SpceCcl::intramolecular(Water &w, double &energy) {
160 Vector3 v1, v2;
161 distance(w.rh1_, w.ro_, v1);
162 distance(w.rh2_, w.ro_, v2);
163 // ------ prepare --------------------
164 Rho ro1, ro2;
165 initialiseRho(v1, ro1);
166 initialiseRho(v2, ro2);
167
168 // ------- prepare Delta theta
169 Dtheta dth;
170 initialiseDtheta(v1, v2, dth, theta_); // theta_ SPC equilibrium angle.
171 Ccl::intramolecular(ro1, ro2, dth, energy, w.fh1_, w.fh2_, w.fo_);
172}
173
174template <int H, int O>
176 const int nMolecules, const double (*const rh1)[H * 3],
177 const double (*const rh2)[H * 3], const double (*const ro)[O * 3],
178 double (*const fh1)[H * 3], double (*const fh2)[H * 3],
179 double (*const fo)[O * 3], double &energy, double const b[],
180 bool const (*const xh1)[H], bool const (*const xh2)[H],
181 bool const (*const xo)[O]) {
182 for (int i = 0; i < nMolecules; ++i) {
183 for (int a = 0; a < 3; a++) {
184 fh1[i][a] = 0.0;
185 fh2[i][a] = 0.0;
186 fo[i][a] = 0.0;
187 };
188 };
189 energy = 0.0;
191
192 for (int i = nMolecules - 1; i >= 0; --i) {
193 double rc1[3] = {0};
194 calculateCentre(rh1[i], rh2[i], ro[i], rc1);
195 Water w1(rh1[i], rh2[i], ro[i], rc1, fh1[i], fh2[i], fo[i]);
196 intramolecular(w1, energy);
197 energy += polarisationEnergy_;
198 for (int j = i - 1; j >= 0; --j) {
199 bool areFixed = false;
200 if (xh1 and xh2 and xo) {
201 areFixed = xh1[i][0] and xh2[i][0] and xo[i][0];
202 // check if all the atoms of molecule j are fixed.
203 areFixed &= xh1[j][0] and xh2[j][0] and xo[j][0];
204 };
205 // if both molecules are fixed skip force calculation
206 if (not areFixed) {
207 double rc2[3] = {0};
208 calculateCentre(rh1[j], rh2[j], ro[j], rc2);
209 Water w2(rh1[j], rh2[j], ro[j], rc2, fh1[j], fh2[j], fo[j]);
210 lennardJonesWithCutoff(w1, w2, energy);
211 coulombWithCutoff(w1, w2, energy);
212 };
213 };
214 };
215 assert(not std::isnan(energy) and not std::isinf(energy));
216}
static double const re_
Distance OH at equilibrium.
Definition ccl.hpp:56
void initialiseDtheta(Vector3 const &v1, Vector3 const &v2, Dtheta &dth, double const thetaEquilibrium)
Initialise Dtheta.
Definition ccl.cpp:209
void intramolecular(double const rh1[], double const rh2[], double const ro[], double fh1[], double fh2[], double fo[], double &energy)
Interactions inside one molecules.
Definition ccl.cpp:238
void switching(ChargeGroup< N, R, F > &g1, ChargeGroup< N, R, F > &g2, double &energy, double cutoff, double switchingWidth)
void coulomb(const double r1[], const double r2[], double f1[], double f2[], double &u, double const qq)
Compute Coulomb interaction between two charges.
void lennardJones(double const distance, double &force, double &energy, double const epsilon, double const sigma)
Lennard-Jones 12-6 between two atoms.
void calculateCentre(double const r1[], double const r2[], double rc[])
Calculate centre of two points.
void setPeriodicity(const double periods[])
Set periodicity.
void distance(const double x[], const double y[], double z[], double &z1, double &z2)
Distance vector, norm and norm square.
static const double A_
Lennard-Jones.
Definition spce_ccl.hpp:160
void initialiseRho(Vector3 const &v, Rho &r)
Initialise Rho.
Definition spce_ccl.cpp:148
static const double roh_
Distance OH.
Definition spce_ccl.hpp:149
void coulombWithCutoff(Water &w1, Water &w2, double &U)
Interactions between two molecules.
Definition spce_ccl.cpp:104
void intramolecular(Water &water, double &U)
Interactions within a molecules.
Definition spce_ccl.cpp:159
static const double charge_
Charge on one hydrogen.
Definition spce_ccl.hpp:155
void lennardJonesWithCutoff(Water &w1, Water &w2, double &U)
Interactions between two molecules.
Definition spce_ccl.cpp:86
char const * getName() const
Name of the potential.
Definition spce_ccl.cpp:84
static const double theta_
Angle HOH.
Definition spce_ccl.hpp:151
static const double rhh_
Distance HH.
Definition spce_ccl.hpp:153
static const double charge2_
Square of # charge_.
Definition spce_ccl.hpp:157
static const double sigma_
Lennard-Jones. See PotentialBase::lennardJones() for definition.
Definition spce_ccl.hpp:165
void coulombFull(Water &w1, Water &w2, double &U)
Interactions between two molecules.
Definition spce_ccl.cpp:133
void computeTemplate(const int nMolecules, const double(*const rh1)[H *3], const double(*const rh2)[H *3], const double(*const ro)[O *3], double(*const fh1)[H *3], double(*const fh2)[H *3], double(*const fo)[O *3], double &energy, double const b[], bool const (*const xh1)[H]=0, bool const (*const xh2)[H]=0, bool const (*const xo)[O]=0)
Compute forces and energy.
Definition spce_ccl.cpp:175
static double const polarisationEnergy_
Polarisation correction.
Definition spce_ccl.hpp:170
static const double epsilon_
Lennard-Jones. See PotentialBase::lennardJones() for definition.
Definition spce_ccl.hpp:167
void computeHH_O_(const int nAtoms, const double R[], double F[], double &U, const double b[])
Compute the forces and the energy.
Definition spce_ccl.cpp:62
static const double B_
Lennard-Jones.
Definition spce_ccl.hpp:163
Physical constants and unit conversion.
SPC/E potential for water.
parameter in paper.
Definition ccl.hpp:43
parameter in paper.
Definition ccl.hpp:36
double _2
rho^2
Definition ccl.hpp:38
double _3
rho^3
Definition ccl.hpp:39
double n[3]
Convert derivative to force.
Definition ccl.hpp:40
double _1
rho^1
Definition ccl.hpp:37
Pointers to molecule of water.
Definition spce_ccl.hpp:78
const double *const rh1_
Definition spce_ccl.hpp:103
const double *const ro_
Definition spce_ccl.hpp:105
const double *const rc_
Definition spce_ccl.hpp:106
const double *const rh2_
Definition spce_ccl.hpp:104