45#include "nonbonded/SC.hpp"
52#include "utils/simError.h"
56 SC::SC() : name_(
"SC"), initialized_(false), forceField_(NULL), np_(3000) {}
67 RealType SC::getM(AtomType* atomType1, AtomType* atomType2) {
68 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
69 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
70 RealType m1 = sca1.getM();
71 RealType m2 = sca2.getM();
72 return 0.5 * (m1 + m2);
75 RealType SC::getN(AtomType* atomType1, AtomType* atomType2) {
76 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
77 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
78 RealType n1 = sca1.getN();
79 RealType n2 = sca2.getN();
80 return 0.5 * (n1 + n2);
83 RealType SC::getAlpha(AtomType* atomType1, AtomType* atomType2) {
84 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
85 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
86 RealType alpha1 = sca1.getAlpha();
87 RealType alpha2 = sca2.getAlpha();
89 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
90 std::string DistanceMix = fopts.getDistanceMixingRule();
93 if (DistanceMix ==
"GEOMETRIC")
94 return sqrt(alpha1 * alpha2);
96 return 0.5 * (alpha1 + alpha2);
99 RealType SC::getEpsilon(AtomType* atomType1, AtomType* atomType2) {
100 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
101 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
102 RealType epsilon1 = sca1.getEpsilon();
103 RealType epsilon2 = sca2.getEpsilon();
104 return sqrt(epsilon1 * epsilon2);
107 void SC::initialize() {
115 SCtids.resize(forceField_->getNAtomType(), -1);
117 AtomTypeSet::iterator at;
118 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
119 if ((*at)->isSC()) nSC_++;
122 MixingMap.resize(nSC_);
123 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
124 if ((*at)->isSC()) addType((*at));
129 void SC::addType(AtomType* atomType) {
130 SuttonChenAdapter sca = SuttonChenAdapter(atomType);
131 SCAtomData scAtomData;
133 scAtomData.c = sca.getC();
134 scAtomData.m = sca.getM();
135 scAtomData.n = sca.getN();
136 scAtomData.alpha = sca.getAlpha();
137 scAtomData.epsilon = sca.getEpsilon();
138 scAtomData.rCut = 2.0 * scAtomData.alpha;
141 int atid = atomType->getIdent();
142 int sctid = SCtypes.size();
144 pair<set<int>::iterator,
bool> ret;
145 ret = SCtypes.insert(atid);
146 if (ret.second ==
false) {
147 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
148 "SC already had a previous entry with ident %d\n", atid);
149 painCave.severity = OPENMD_INFO;
150 painCave.isFatal = 0;
154 SCtids[atid] = sctid;
155 SCdata[sctid] = scAtomData;
156 MixingMap[sctid].resize(nSC_);
160 std::set<int>::iterator it;
161 for (it = SCtypes.begin(); it != SCtypes.end(); ++it) {
162 int sctid2 = SCtids[(*it)];
163 AtomType* atype2 = forceField_->getAtomType((*it));
165 SCInteractionData mixer;
167 mixer.alpha = getAlpha(atomType, atype2);
168 mixer.rCut = 2.0 * mixer.alpha;
169 mixer.epsilon = getEpsilon(atomType, atype2);
170 mixer.m = getM(atomType, atype2);
171 mixer.n = getN(atomType, atype2);
173 RealType dr = mixer.rCut / (np_ - 1);
174 vector<RealType> rvals;
175 vector<RealType> vvals;
176 vector<RealType> phivals;
178 rvals.push_back(0.0);
179 vvals.push_back(0.0);
180 phivals.push_back(0.0);
182 for (
int k = 1; k < np_; k++) {
185 vvals.push_back(mixer.epsilon * pow(mixer.alpha / r, mixer.n));
186 phivals.push_back(pow(mixer.alpha / r, mixer.m));
189 mixer.vCut = mixer.epsilon * pow(mixer.alpha / mixer.rCut, mixer.n);
191 CubicSpline* V =
new CubicSpline();
192 V->addPoints(rvals, vvals);
194 CubicSpline* phi =
new CubicSpline();
195 phi->addPoints(rvals, phivals);
200 mixer.explicitlySet =
false;
202 MixingMap[sctid2].resize(nSC_);
204 MixingMap[sctid][sctid2] = mixer;
205 if (sctid2 != sctid) { MixingMap[sctid2][sctid] = mixer; }
210 void SC::addExplicitInteraction(AtomType* atype1, AtomType* atype2,
211 RealType epsilon, RealType m, RealType n,
217 SCInteractionData mixer;
219 mixer.epsilon = epsilon;
223 mixer.rCut = 2.0 * mixer.alpha;
225 RealType dr = mixer.rCut / (np_ - 1);
226 vector<RealType> rvals;
227 vector<RealType> vvals;
228 vector<RealType> phivals;
230 rvals.push_back(0.0);
231 vvals.push_back(0.0);
232 phivals.push_back(0.0);
234 for (
int k = 1; k < np_; k++) {
237 vvals.push_back(mixer.epsilon * pow(mixer.alpha / r, mixer.n));
238 phivals.push_back(pow(mixer.alpha / r, mixer.m));
241 mixer.vCut = mixer.epsilon * pow(mixer.alpha / mixer.rCut, mixer.n);
243 CubicSpline* V =
new CubicSpline();
244 V->addPoints(rvals, vvals);
246 CubicSpline* phi =
new CubicSpline();
247 phi->addPoints(rvals, phivals);
252 mixer.explicitlySet =
true;
254 int sctid1 = SCtids[atype1->getIdent()];
255 int sctid2 = SCtids[atype2->getIdent()];
257 MixingMap[sctid1][sctid2] = mixer;
258 if (sctid2 != sctid1) { MixingMap[sctid2][sctid1] = mixer; }
262 void SC::calcDensity(InteractionData& idat) {
263 if (!initialized_) initialize();
264 int sctid1 = SCtids[idat.atid1];
265 int sctid2 = SCtids[idat.atid2];
267 SCInteractionData& mixer = MixingMap[sctid1][sctid2];
269 RealType rcij = mixer.rCut;
271 if (idat.rij < rcij) {
272 RealType rho = mixer.phi->getValueAt(idat.rij);
280 void SC::calcFunctional(SelfData& sdat) {
281 if (!initialized_) initialize();
283 SCAtomData& data1 = SCdata[SCtids[sdat.atid]];
285 RealType u = -data1.c * data1.epsilon * sqrt(sdat.rho);
287 sdat.dfrhodrho = 0.5 * sdat.frho / sdat.rho;
293 if (sdat.doParticlePot) { sdat.particlePot += u; }
298 void SC::calcForce(InteractionData& idat) {
299 if (!initialized_) initialize();
301 int& sctid1 = SCtids[idat.atid1];
302 int& sctid2 = SCtids[idat.atid2];
304 SCAtomData& data1 = SCdata[sctid1];
305 SCAtomData& data2 = SCdata[sctid2];
307 SCInteractionData& mixer = MixingMap[sctid1][sctid2];
309 RealType rcij = mixer.rCut;
311 if (idat.rij < rcij) {
312 RealType vcij = mixer.vCut;
313 RealType rhtmp, drhodr, vptmp, dvpdr;
315 mixer.phi->getValueAndDerivativeAt(idat.rij, rhtmp, drhodr);
316 mixer.V->getValueAndDerivativeAt(idat.rij, vptmp, dvpdr);
318 RealType pot_temp = vptmp - vcij;
319 idat.vpair += pot_temp;
321 RealType dudr = drhodr * (idat.dfrho1 + idat.dfrho2) + dvpdr;
323 idat.f1 += idat.d * dudr / idat.rij;
325 if (idat.doParticlePot) {
336 data2.c * data2.epsilon * sqrt(idat.rho2 - rhtmp) + idat.frho2;
339 data1.c * data1.epsilon * sqrt(idat.rho1 - rhtmp) + idat.frho1;
350 RealType SC::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
351 if (!initialized_) initialize();
353 int atid1 = atypes.first->getIdent();
354 int atid2 = atypes.second->getIdent();
355 int& sctid1 = SCtids[atid1];
356 int& sctid2 = SCtids[atid2];
358 if (sctid1 == -1 || sctid2 == -1) {
361 return MixingMap[sctid1][sctid2].rCut;
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
@ METALLIC_EMBEDDING_FAMILY
Transition metal interactions involving electron density.
@ METALLIC_PAIR_FAMILY
Transition metal interactions involving pair potentials.