Loading...
Searching...
No Matches
tip4p_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// If unit_system.hpp is removed the system of unit will be (Energy: eV,
23// distance: Angstrom, time: fs, charge: e).
25
26namespace forcefields {
27/* defined(FORCEFIELDS_UNIT_SYSTEM_HPP) && \
28( FORCEFIELDS_UNIT_SYSTEM_HPP !=
29FORCEFIELDS_UNIT_SYSTEM_ELECTRONVOLT_ANGSTROM_FEMTOSECOND_ECHARGE) //*/
30namespace {
31double const re_ = 0.9572 * unit_system::ANGSTROM;
32double const thetae_ = 104.52 * unit_system::DEGREE;
33double const charge_ = 0.520 * unit_system::ECHARGE;
34double const charge2_ = charge_ * charge_;
35double const sigma_ =
36 3.154 *
38double const epsilon_ =
39 78.0 * unit_system::KELVIN;
40double const ron_ = 0.150 * unit_system::ANGSTROM;
42double const rok_ =
43 re_ * std::cos(thetae_ / 2.0);
45double const wh_ = ron_ / rok_ * 0.5;
46double const wo_ = (1.0 - wh_ * 2.0);
47} // namespace
48
65
67 : Ccl() {}
68
69Tip4p::Tip4p(double cutoff, double switchingWidth)
70 : Ccl(cutoff, switchingWidth) {}
71
84void Tip4p::computeHH_O_(const int nAtoms, const double R[], double F[],
85 double &U, const double b[]) {
86 computeHH_O_(nAtoms, R, F, U, b, 0);
87}
88
102void Tip4p::computeHH_O_(const int nAtoms, const double R[], double F[],
103 double &U, const double b[], const bool fixed[]) {
104 int const nMolecules = nAtoms / 3;
105 const double (*const rh1)[6] = reinterpret_cast<const double (*)[6]>(R);
106 const double (*const rh2)[6] = reinterpret_cast<const double (*)[6]>(&R[3]);
107 const double (*const ro)[3] =
108 reinterpret_cast<const double (*)[3]>(&R[nMolecules * 6]);
109 double (*const fh1)[6] = reinterpret_cast<double (*)[6]>(F);
110 double (*const fh2)[6] = reinterpret_cast<double (*)[6]>(&F[3]);
111 double (*const fo)[3] = reinterpret_cast<double (*)[3]>(&F[nMolecules * 6]);
112 bool const(*const xh1)[2] = reinterpret_cast<bool const(*)[2]>(fixed);
113 bool const(*const xh2)[2] = reinterpret_cast<bool const(*)[2]>(&fixed[1]);
114 bool const(*const xo)[1] =
115 reinterpret_cast<bool const(*)[1]>(&fixed[nMolecules * 2]);
116 computeTemplate(nMolecules, rh1, rh2, ro, fh1, fh2, fo, U, b, xh1, xh2, xo);
117}
118
120char const *Tip4p::getName() { return "Tip4p"; }
121
122// -----------------------------------------------------private----------------------------------------
123
126 const double *const rh1_;
127 const double *const rh2_;
128 const double *const ro_;
129 const double *const rn_;
130 const double *const rc_;
131 double *const fh1_;
132 double *const fh2_;
133 double *const fo_;
134 double *const fn_;
135};
136
155template <int H, int O>
157 const int nMolecules, const double (*const rh1)[H * 3],
158 const double (*const rh2)[H * 3], const double (*const ro)[O * 3],
159 double (*const fh1)[H * 3], double (*const fh2)[H * 3],
160 double (*const fo)[O * 3], double &energy, double const b[],
161 bool const (*const xh1)[H], bool const (*const xh2)[H],
162 bool const (*const xo)[O]) {
163 for (int i = 0; i < nMolecules; ++i) {
164 for (int a = 0; a < 3; a++) {
165 fh1[i][a] = 0.0;
166 fh2[i][a] = 0.0;
167 fo[i][a] = 0.0;
168 };
169 };
170 energy = 0.0;
172 for (int i = nMolecules - 1; i >= 0; --i) {
173 double rc1[3], rn1[3], fn1[3] = {0}; // rn position charge N, rc centre of
174 // charge for groupbased cutoff.
175 calculateWeightedCentre(wo_, wh_, wh_, ro[i], rh1[i], rh2[i], rn1);
176 calculateCentre(rn1, rh1[i], rh2[i], rc1);
177 Water w1 = {rh1[i], rh2[i], ro[i], rn1, rc1, fh1[i], fh2[i], fo[i], fn1};
178 intramolecular(rh1[i], rh2[i], ro[i], fh1[i], fh2[i], fo[i], energy);
179 for (int j = i - 1; j >= 0; --j) {
180 bool areFixed = false;
181 if (xh1 and xh2 and xo) {
182 areFixed = xh1[i][0] and xh2[i][0] and xo[i][0];
183 // check if all the atoms of molecule j are fixed.
184 areFixed &= xh1[j][0] and xh2[j][0] and xo[j][0];
185 };
186 // if both molecules are fixed skip force calculation
187 if (not areFixed) {
188 double rc2[3], rn2[3], fn2[3] = {0};
189 calculateWeightedCentre(wo_, wh_, wh_, ro[j], rh1[j], rh2[j], rn2);
190 calculateCentre(rn2, rh1[j], rh2[j], rc2);
191 Water w2 = {rh1[j], rh2[j], ro[j], rn2, rc2,
192 fh1[j], fh2[j], fo[j], fn2};
193 coulombWithCutoff(w1, w2, energy);
194 spreadWeightedForce(wo_, wh_, wh_, w2.fo_, w2.fh1_, w2.fh2_, w2.fn_);
195 lennardJonesWithCutoff(w1, w2, energy);
196 };
197 };
198 spreadWeightedForce(wo_, wh_, wh_, w1.fo_, w1.fh1_, w1.fh2_, w1.fn_);
199 };
200 assert(not std::isnan(energy) and not std::isinf(energy));
201}
202
209void Tip4p::coulombWithCutoff(Water &w1, Water &w2, double &U) {
210 double z[3], z1, z2;
211 distance(w1.rc_, w2.rc_, z, z1, z2);
212 if (z1 <= cutoff_ - switchingWidth_) {
213 coulombFull(w1, w2, U);
214 } else if (z1 < cutoff_) {
215 double f1[3][3] = {{0}}, f2[3][3] = {{0}};
216 // f1[0], f1[1], 0, f1[2] are respectively, H1, H2, O, N. There is no charge
217 // on O.
218 Water v1 = {w1.rh1_, w1.rh2_, w1.ro_, w1.rn_, w1.rc_,
219 f1[0], f1[1], 0, f1[2]};
220 Water v2 = {w2.rh1_, w2.rh2_, w2.ro_, w2.rn_, w2.rc_,
221 f2[0], f2[1], 0, f2[2]};
222 double energy = 0.0;
223 coulombFull(v1, v2, energy);
224 ChargeGroup<3> g1 = {v1.rc_, 0, f1};
225 ChargeGroup<3> g2 = {v2.rc_, 0, f2};
226 // Calculate the weakened forces and energy.
227 switching(g1, g2, energy, cutoff_, switchingWidth_);
228 // add weakened force and energy to those of other interactions.
229 U += energy;
230 for (int i = 0; i < 3; ++i) {
231 w1.fh1_[i] += v1.fh1_[i];
232 w1.fh2_[i] += v1.fh2_[i];
233 w1.fn_[i] += v1.fn_[i];
234 w2.fh1_[i] += v2.fh1_[i];
235 w2.fh2_[i] += v2.fh2_[i];
236 w2.fn_[i] += v2.fn_[i];
237 };
238 }
239}
240
251void Tip4p::coulombFull(Water &w1, Water &w2, double &U) {
252 // Coulomb interactions between hydrogens
253 coulomb(w1.rh1_, w2.rh1_, w1.fh1_, w2.fh1_, U, charge2_);
254 coulomb(w1.rh1_, w2.rh2_, w1.fh1_, w2.fh2_, U, charge2_);
255 coulomb(w1.rh2_, w2.rh1_, w1.fh2_, w2.fh1_, U, charge2_);
256 coulomb(w1.rh2_, w2.rh2_, w1.fh2_, w2.fh2_, U, charge2_);
257 // interactions between H and N.
258 coulomb(w1.rn_, w2.rh1_, w1.fn_, w2.fh1_, U, -2.0 * charge2_);
259 coulomb(w1.rn_, w2.rh2_, w1.fn_, w2.fh2_, U, -2.0 * charge2_);
260 coulomb(w1.rh1_, w2.rn_, w1.fh1_, w2.fn_, U, -2.0 * charge2_);
261 coulomb(w1.rh2_, w2.rn_, w1.fh2_, w2.fn_, U, -2.0 * charge2_);
262 // interactions between N1, N2
263 coulomb(w1.rn_, w2.rn_, w1.fn_, w2.fn_, U, 4.0 * charge2_);
264}
265
273void Tip4p::lennardJonesWithCutoff(Water &w1, Water &w2, double &U) {
274 double z[3], z1;
275 distance(w1.ro_, w2.ro_, z, z1);
276 if (z1 <= cutoff_ - switchingWidth_) {
277 lennardJones(w1.ro_, w2.ro_, w1.fo_, w2.fo_, U, epsilon_, sigma_);
278 } else if (z1 < cutoff_) {
279 double f1[3] = {0}, f2[3] = {0};
280 double energy = 0.0;
281 lennardJones(w1.ro_, w2.ro_, f1, f2, energy, epsilon_, sigma_);
282 switching(w1.ro_, w2.ro_, f1, f2, energy);
283 U += energy;
284 for (int i = 0; i < 3; i++) {
285 w1.fo_[i] += f1[i];
286 w2.fo_[i] += f2[i];
287 };
288 };
289}
290} // namespace forcefields
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:233
void switching(ChargeGroup< N, R, F > &g1, ChargeGroup< N, R, F > &g2, double &energy, double cutoff, double switchingWidth)
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.
void coulomb(const double r1[], const double r2[], double f1[], double f2[], double &u, double const qq)
Compute Coulomb interaction between two charges.
void calculateWeightedCentre(double const w1, double const w2, double const w3, double const r1[], double const r2[], double const r3[], double rc[])
Calculate barycentre.
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 spreadWeightedForce(double const w1, double const w2, double const w3, double f1[], double f2[], double f3[], double const fc[])
Spread force on barycentre to atoms.
static char const * getName()
Name of the potential.
void coulombWithCutoff(Water &w1, Water &w2, double &U)
Interactions between two molecules.
void computeHH_O_(const int nAtoms, const double R[], double F[], double &U, const double b[])
Compute the forces and the energy.
Definition tip4p_ccl.cpp:84
void lennardJonesWithCutoff(Water &w1, Water &w2, double &U)
Interactions between two molecules.
void coulombFull(Water &w1, Water &w2, double &U)
Interactions between two molecules.
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.
Pointers for one molecule of water.
const double *const rc_
const double *const ro_
const double *const rh2_
const double *const rn_
const double *const rh1_
TIP4P potential for water.
Physical constants, unit conversion.