48#include "nonbonded/GB.hpp"
54#include "types/GayBerneAdapter.hpp"
55#include "types/LennardJonesAdapter.hpp"
56#include "utils/simError.h"
97 initialized_(false), name_(
"GB"), forceField_(NULL), mu_(2.0), nu_(1.0) {}
99 void GB::initialize() {
105 GBtids.resize(forceField_->getNAtomType(), -1);
107 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
108 mu_ = fopts.getGayBerneMu();
109 nu_ = fopts.getGayBerneNu();
113 AtomTypeSet::iterator at;
114 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
115 if ((*at)->isGayBerne()) nGB_++;
116 if ((*at)->isLennardJones()) nGB_++;
119 MixingMap.resize(nGB_);
120 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
121 if ((*at)->isGayBerne() || (*at)->isLennardJones()) addType(*at);
127 void GB::addType(AtomType* atomType) {
129 int atid = atomType->getIdent();
130 int gbtid = GBtypes.size();
132 pair<set<int>::iterator,
bool> ret;
133 ret = GBtypes.insert(atid);
134 if (ret.second ==
false) {
135 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
136 "GB already had a previous entry with ident %d\n", atid);
137 painCave.severity = OPENMD_INFO;
138 painCave.isFatal = 0;
142 GBtids[atid] = gbtid;
143 MixingMap[gbtid].resize(nGB_);
145 RealType d1(0.0), l1(0.0), eX1(0.0), eS1(0.0), eE1(0.0), dw1(0.0);
147 LennardJonesAdapter lja1 = LennardJonesAdapter(atomType);
148 GayBerneAdapter gba1 = GayBerneAdapter(atomType);
149 if (gba1.isGayBerne()) {
152 eX1 = gba1.getEpsX();
153 eS1 = gba1.getEpsS();
154 eE1 = gba1.getEpsE();
156 }
else if (lja1.isLennardJones()) {
157 d1 = lja1.getSigma() / sqrt(2.0);
159 eX1 = lja1.getEpsilon();
164 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
165 "GB::addType was passed an atomType (%s) that does not\n"
166 "\tappear to be a Gay-Berne or Lennard-Jones atom.\n",
167 atomType->getName().c_str());
168 painCave.severity = OPENMD_ERROR;
169 painCave.isFatal = 1;
175 std::set<int>::iterator it;
176 for (it = GBtypes.begin(); it != GBtypes.end(); ++it) {
177 int gbtid2 = GBtids[(*it)];
178 AtomType* atype2 = forceField_->getAtomType((*it));
180 LennardJonesAdapter lja2 = LennardJonesAdapter(atype2);
181 GayBerneAdapter gba2 = GayBerneAdapter(atype2);
182 RealType d2(0.0), l2(0.0), eX2(0.0), eS2(0.0), eE2(0.0), dw2(0.0);
184 if (gba2.isGayBerne()) {
187 eX2 = gba2.getEpsX();
188 eS2 = gba2.getEpsS();
189 eE2 = gba2.getEpsE();
191 }
else if (lja2.isLennardJones()) {
192 d2 = lja2.getSigma() / sqrt(2.0);
194 eX2 = lja2.getEpsilon();
199 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
200 "GB::addType found an atomType (%s) that does not\n"
201 "\tappear to be a Gay-Berne or Lennard-Jones atom.\n",
202 atype2->getName().c_str());
203 painCave.severity = OPENMD_ERROR;
204 painCave.isFatal = 1;
208 GBInteractionData mixer1, mixer2;
212 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
213 string DistanceMix = fopts.getDistanceMixingRule();
214 toUpper(DistanceMix);
216 if (DistanceMix ==
"ARITHMETIC")
217 mixer1.sigma0 = 0.5 * (d1 + d2);
219 mixer1.sigma0 = sqrt(d1 * d1 + d2 * d2);
221 mixer1.xa2 = (l1 * l1 - d1 * d1) / (l1 * l1 + d2 * d2);
222 mixer1.xai2 = (l2 * l2 - d2 * d2) / (l2 * l2 + d1 * d1);
223 mixer1.x2 = (l1 * l1 - d1 * d1) * (l2 * l2 - d2 * d2) /
224 ((l2 * l2 + d1 * d1) * (l1 * l1 + d2 * d2));
226 mixer2.sigma0 = mixer1.sigma0;
229 mixer2.xa2 = mixer1.xai2;
230 mixer2.xai2 = mixer1.xa2;
231 mixer2.x2 = mixer1.x2;
235 mixer1.dw = 0.5 * (dw1 + dw2);
236 mixer1.eps0 = sqrt(eX1 * eX2);
238 mixer2.dw = mixer1.dw;
239 mixer2.eps0 = mixer1.eps0;
241 RealType mi = RealType(1.0) / mu_;
244 (pow(eS1, mi) - pow(eE1, mi)) / (pow(eS1, mi) + pow(eE2, mi));
246 (pow(eS2, mi) - pow(eE2, mi)) / (pow(eS2, mi) + pow(eE1, mi));
248 (pow(eS1, mi) - pow(eE1, mi)) * (pow(eS2, mi) - pow(eE2, mi)) /
249 (pow(eS2, mi) + pow(eE1, mi)) / (pow(eS1, mi) + pow(eE2, mi));
253 mixer2.xpap2 = mixer1.xpapi2;
254 mixer2.xpapi2 = mixer1.xpap2;
255 mixer2.xp2 = mixer1.xp2;
257 mixer1.i_is_LJ = atomType->isLennardJones();
258 mixer1.j_is_LJ = atype2->isLennardJones();
259 mixer2.i_is_LJ = mixer1.j_is_LJ;
260 mixer2.j_is_LJ = mixer1.i_is_LJ;
264 if (gba1.isGayBerne() || gba2.isGayBerne()) {
265 MixingMap[gbtid2].resize(nGB_);
266 MixingMap[gbtid][gbtid2] = mixer1;
267 if (gbtid2 != gbtid) { MixingMap[gbtid2][gbtid] = mixer2; }
272 void GB::calcForce(InteractionData& idat) {
273 if (!initialized_) initialize();
275 GBInteractionData& mixer =
276 MixingMap[GBtids[idat.atid1]][GBtids[idat.atid2]];
278 RealType sigma0 = mixer.sigma0;
279 RealType dw = mixer.dw;
280 RealType eps0 = mixer.eps0;
281 RealType x2 = mixer.x2;
282 RealType xa2 = mixer.xa2;
283 RealType xai2 = mixer.xai2;
284 RealType xp2 = mixer.xp2;
285 RealType xpap2 = mixer.xpap2;
286 RealType xpapi2 = mixer.xpapi2;
288 Vector3d ul1 = idat.A1.getRow(2);
289 Vector3d ul2 = idat.A2.getRow(2);
297 a =
dot(idat.d, ul1);
304 b =
dot(idat.d, ul2);
307 if (mixer.i_is_LJ || mixer.j_is_LJ)
312 RealType au = a / idat.rij;
313 RealType bu = b / idat.rij;
315 RealType au2 = au * au;
316 RealType bu2 = bu * bu;
320 (xa2 * au2 + xai2 * bu2 - 2.0 * x2 * au * bu * g) / (1.0 - x2 * g2);
321 RealType Hp = (xpap2 * au2 + xpapi2 * bu2 - 2.0 * xp2 * au * bu * g) /
324 RealType sigma = sigma0 / sqrt(1.0 - H);
325 RealType e1 = 1.0 / sqrt(1.0 - x2 * g2);
326 RealType e2 = 1.0 - Hp;
327 RealType eps = eps0 * pow(e1, nu_) * pow(e2, mu_);
328 RealType BigR = dw * sigma0 / (idat.rij - sigma + dw * sigma0);
330 RealType R3 = BigR * BigR * BigR;
331 RealType R6 = R3 * R3;
332 RealType R7 = R6 * BigR;
333 RealType R12 = R6 * R6;
334 RealType R13 = R6 * R7;
336 RealType U = idat.vdwMult * 4.0 * eps * (R12 - R6);
338 RealType s3 = sigma * sigma * sigma;
339 RealType s03 = sigma0 * sigma0 * sigma0;
342 -idat.vdwMult * 8.0 * eps * mu_ * (R12 - R6) / (e2 * idat.rij);
344 RealType pref2 = idat.vdwMult * 8.0 * eps * s3 * (6.0 * R13 - 3.0 * R7) /
345 (dw * idat.rij * s03);
348 -(pref1 * Hp + pref2 * (sigma0 * sigma0 * idat.rij / s3 + H));
350 RealType dUda = pref1 * (xpap2 * au - xp2 * bu * g) / (1.0 - xp2 * g2) +
351 pref2 * (xa2 * au - x2 * bu * g) / (1.0 - x2 * g2);
353 RealType dUdb = pref1 * (xpapi2 * bu - xp2 * au * g) / (1.0 - xp2 * g2) +
354 pref2 * (xai2 * bu - x2 * au * g) / (1.0 - x2 * g2);
356 RealType dUdg = 4.0 * eps * nu_ * (R12 - R6) * x2 * g / (1.0 - x2 * g2) +
357 8.0 * eps * mu_ * (R12 - R6) *
358 (xp2 * au * bu - Hp * xp2 * g) / (1.0 - xp2 * g2) / e2 +
359 8.0 * eps * s3 * (3.0 * R7 - 6.0 * R13) *
360 (x2 * au * bu - H * x2 * g) / (1.0 - x2 * g2) /
363 Vector3d rhat = idat.d / idat.rij;
364 Vector3d rxu1 =
cross(idat.d, ul1);
365 Vector3d rxu2 =
cross(idat.d, ul2);
366 Vector3d uxu =
cross(ul1, ul2);
371 idat.f1 += (dUdr * rhat + dUda * ul1 + dUdb * ul2) * idat.sw;
372 idat.t1 += (dUda * rxu1 - dUdg * uxu) * idat.sw;
373 idat.t2 += (dUdb * rxu2 + dUdg * uxu) * idat.sw;
378 RealType GB::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
379 if (!initialized_) initialize();
383 LennardJonesAdapter lja1 = LennardJonesAdapter(atypes.first);
384 GayBerneAdapter gba1 = GayBerneAdapter(atypes.first);
385 LennardJonesAdapter lja2 = LennardJonesAdapter(atypes.second);
386 GayBerneAdapter gba2 = GayBerneAdapter(atypes.second);
388 if (gba1.isGayBerne()) {
389 RealType d1 = gba1.getD();
390 RealType l1 = gba1.getL();
392 cut = max(cut, RealType(2.5) * sqrt(RealType(2.0)) * max(d1, l1));
393 }
else if (lja1.isLennardJones()) {
394 cut = max(cut, RealType(2.5) * lja1.getSigma());
397 if (gba2.isGayBerne()) {
398 RealType d2 = gba2.getD();
399 RealType l2 = gba2.getL();
400 cut = max(cut, RealType(2.5) * sqrt(RealType(2.0)) * max(d2, l2));
401 }
else if (lja2.isLennardJones()) {
402 cut = max(cut, RealType(2.5) * lja2.getSigma());
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
@ VANDERWAALS_FAMILY
Long-range dispersion and short-range pauli repulsion.