n2p2 - A neural network potential package
SymGrpExpAngnWeighted.cpp
Go to the documentation of this file.
1// n2p2 - A neural network potential package
2// Copyright (C) 2018 Andreas Singraber (University of Vienna)
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
18#include "Atom.h"
19#include "SymFnc.h"
21#include "Vec3D.h"
22#include "utility.h"
23#include <algorithm> // std::sort
24#include <cmath> // exp
25#include <stdexcept> // std::runtime_error
26
27using namespace std;
28using namespace nnp;
29
30SymGrpExpAngnWeighted::SymGrpExpAngnWeighted(ElementMap const& elementMap) :
31 SymGrpBaseCutoff(13, elementMap)
32{
33 parametersMember.insert("eta");
34 parametersMember.insert("rs/rl");
35 parametersMember.insert("lambda");
36 parametersMember.insert("zeta");
37 parametersMember.insert("mindex");
38 parametersMember.insert("sfindex");
39 parametersMember.insert("calcexp");
40}
41
43{
44 if (ec != rhs.getEc() ) return false;
45 if (type != rhs.getType()) return false;
46 SymGrpExpAngnWeighted const& c =
47 dynamic_cast<SymGrpExpAngnWeighted const&>(rhs);
48 if (cutoffType != c.cutoffType ) return false;
49 if (cutoffAlpha != c.cutoffAlpha) return false;
50 if (rc != c.rc ) return false;
51 return true;
52}
53
55{
56 if (ec < rhs.getEc() ) return true;
57 else if (ec > rhs.getEc() ) return false;
58 if (type < rhs.getType()) return true;
59 else if (type > rhs.getType()) return false;
60 SymGrpExpAngnWeighted const& c =
61 dynamic_cast<SymGrpExpAngnWeighted const&>(rhs);
62 if (cutoffType < c.cutoffType ) return true;
63 else if (cutoffType > c.cutoffType ) return false;
64 if (cutoffAlpha < c.cutoffAlpha) return true;
65 else if (cutoffAlpha > c.cutoffAlpha) return false;
66 if (rc < c.rc ) return true;
67 else if (rc > c.rc ) return false;
68 return false;
69}
70
71bool SymGrpExpAngnWeighted::addMember(SymFnc const* const symmetryFunction)
72{
73 if (symmetryFunction->getType() != type) return false;
74
75 SymFncExpAngnWeighted const* sf =
76 dynamic_cast<SymFncExpAngnWeighted const*>(symmetryFunction);
77
78 if (members.empty())
79 {
81 subtype = sf->getSubtype();
83 ec = sf->getEc();
84 rc = sf->getRc();
86
90 }
91
92 if (sf->getCutoffType() != cutoffType ) return false;
93 if (sf->getCutoffAlpha() != cutoffAlpha) return false;
94 if (sf->getEc() != ec ) return false;
95 if (sf->getRc() != rc ) return false;
96 if (sf->getConvLength() != convLength )
97 {
98 throw runtime_error("ERROR: Unable to add symmetry function members "
99 "with different conversion factors.\n");
100 }
101
102 members.push_back(sf);
103
104 return true;
105}
106
108{
109 sort(members.begin(),
110 members.end(),
111 comparePointerTargets<SymFncExpAngnWeighted const>);
112
113 // Members are now sorted with eta changing the slowest.
114 for (size_t i = 0; i < members.size(); i++)
115 {
116 factorNorm.push_back(pow(2.0, 1.0 - members[i]->getZeta()));
117 factorDeriv.push_back(2.0 * members[i]->getEta() /
118 members[i]->getZeta() / members[i]->getLambda());
119 if (i == 0)
120 {
121 calculateExp.push_back(true);
122 }
123 else
124 {
125 if ( members[i - 1]->getEta() != members[i]->getEta() ||
126 members[i - 1]->getRs() != members[i]->getRs() )
127 {
128 calculateExp.push_back(true);
129 }
130 else
131 {
132 calculateExp.push_back(false);
133 }
134 }
135 useIntegerPow.push_back(members[i]->getUseIntegerPow());
136 memberIndex.push_back(members[i]->getIndex());
137 zetaInt.push_back(members[i]->getZetaInt());
138 eta.push_back(members[i]->getEta());
139 rs.push_back(members[i]->getRs());
140 lambda.push_back(members[i]->getLambda());
141 zeta.push_back(members[i]->getZeta());
142 zetaLambda.push_back(members[i]->getZeta() * members[i]->getLambda());
143 memberIndexPerElement.push_back(members[i]->getIndexPerElement());
144 }
145
146 return;
147}
148
150{
151 scalingFactors.resize(members.size(), 0.0);
152 for (size_t i = 0; i < members.size(); i++)
153 {
154 scalingFactors.at(i) = members[i]->getScalingFactor();
155 factorNorm.at(i) *= scalingFactors.at(i);
156 }
157
158 return;
159}
160
161// Depending on chosen symmetry functions this function may be very
162// time-critical when predicting new structures (e.g. in MD simulations). Thus,
163// lots of optimizations were used sacrificing some readablity. Vec3D
164// operations have been rewritten in simple C array style and the use of
165// temporary objects has been minimized. Some of the originally coded
166// expressions are kept in comments marked with "SIMPLE EXPRESSIONS:".
167void SymGrpExpAngnWeighted::calculate(Atom& atom, bool const derivatives) const
168{
169#ifndef N2P2_NO_SF_CACHE
170 // Can use cache indices of any member because this group is defined via
171 // identical symmetry function type and cutoff functions.
172 auto cacheIndices = members.at(0)->getCacheIndices();
173#endif
174 double* result = new double[members.size()];
175 for (size_t l = 0; l < members.size(); ++l)
176 {
177 result[l] = 0.0;
178 }
179
180 double const rc2 = rc * rc;
181 size_t numNeighbors = atom.numNeighbors;
182 // Prevent problematic condition in loop test below (j < numNeighbors - 1).
183 if (numNeighbors == 0) numNeighbors = 1;
184
185 for (size_t j = 0; j < numNeighbors - 1; j++)
186 {
187 Atom::Neighbor& nj = atom.neighbors[j];
188 size_t const nej = nj.element;
189 double const rij = nj.d;
190 if (rij < rc)
191 {
192 double const r2ij = rij * rij;
193
194 // Calculate cutoff function and derivative.
195 double pfcij;
196 double pdfcij;
197#ifndef N2P2_NO_SF_CACHE
198 if (cacheIndices[nej].size() == 0) fc.fdf(rij, pfcij, pdfcij);
199 else
200 {
201 double& cfc = nj.cache[cacheIndices[nej][0]];
202 double& cdfc = nj.cache[cacheIndices[nej][1]];
203 if (cfc < 0) fc.fdf(rij, cfc, cdfc);
204 pfcij = cfc;
205 pdfcij = cdfc;
206 }
207#else
208 fc.fdf(rij, pfcij, pdfcij);
209#endif
210 // SIMPLE EXPRESSIONS:
211 //Vec3D const drij(atom.neighbors[j].dr);
212 //double const* const dr1 = drij.r;
213 double const* const dr1 = nj.dr.r;
214
215 for (size_t k = j + 1; k < numNeighbors; k++)
216 {
217 Atom::Neighbor& nk = atom.neighbors[k];
218 size_t const nek = nk.element;
219 double const rik = nk.d;
220 if (rik < rc)
221 {
222 // SIMPLE EXPRESSIONS:
223 //Vec3D const drjk(atom.neighbors[k].dr
224 // - atom.neighbors[j].dr);
225 //double rjk = drjk.norm2();
226 double const* const dr2 = nk.dr.r;
227 double dr3[3];
228 dr3[0] = dr2[0] - dr1[0];
229 dr3[1] = dr2[1] - dr1[1];
230 dr3[2] = dr2[2] - dr1[2];
231 double rjk = dr3[0] * dr3[0]
232 + dr3[1] * dr3[1]
233 + dr3[2] * dr3[2];
234 if (rjk < rc2)
235 {
236 // Energy calculation.
237 double pfcik;
238 double pdfcik;
239#ifndef N2P2_NO_SF_CACHE
240 if (cacheIndices[nej].size() == 0)
241 {
242 fc.fdf(rik, pfcik, pdfcik);
243 }
244 else
245 {
246 double& cfc = nk.cache[cacheIndices[nek][0]];
247 double& cdfc = nk.cache[cacheIndices[nek][1]];
248 if (cfc < 0) fc.fdf(rik, cfc, cdfc);
249 pfcik = cfc;
250 pdfcik = cdfc;
251 }
252#else
253 fc.fdf(rik, pfcik, pdfcik);
254#endif
255 rjk = sqrt(rjk);
256
257 double pfcjk;
258 double pdfcjk;
259 fc.fdf(rjk, pfcjk, pdfcjk);
260
261 // SIMPLE EXPRESSIONS:
262 //Vec3D const drik(atom.neighbors[k].dr);
263 //double const* const dr2 = drik.r;
264 //double const* const dr3 = drjk.r;
265 double const rinvijik = 1.0 / rij / rik;
266 // SIMPLE EXPRESSIONS:
267 //double const costijk = (drij * drik) * rinvijik;
268 double const costijk = (dr1[0] * dr2[0] +
269 dr1[1] * dr2[1] +
270 dr1[2] * dr2[2]) * rinvijik;
271 double const z = elementMap.atomicNumber(nej)
273 double const pfc = z * pfcij * pfcik * pfcjk;
274 double const r2ik = rik * rik;
275 double const pr1 = z * pfcik * pfcjk * pdfcij / rij;
276 double const pr2 = z * pfcij * pfcjk * pdfcik / rik;
277 double const pr3 = z * pfcij * pfcik * pdfcjk / rjk;
278 double vexp = 0.0;
279 double rijs = 0.0;
280 double riks = 0.0;
281 double rjks = 0.0;
282
283 for (size_t l = 0; l < members.size(); ++l)
284 {
285 if (calculateExp[l])
286 {
287 rijs = rij - rs[l];
288 riks = rik - rs[l];
289 rjks = rjk - rs[l];
290 double const r2sum = rijs * rijs
291 + riks * riks
292 + rjks * rjks;
293 vexp = exp(-eta[l] * r2sum);
294 }
295 double const plambda = 1.0
296 + lambda[l] * costijk;
297 double fg = vexp;
298 if (plambda <= 0.0) fg = 0.0;
299 else
300 {
301 if (useIntegerPow[l])
302 {
303 fg *= pow_int(plambda, zetaInt[l] - 1);
304 }
305 else
306 {
307 fg *= pow(plambda, zeta[l] - 1.0);
308 }
309 }
310 result[l] += fg * plambda * pfc;
311
312 // Force calculation.
313 if (!derivatives) continue;
314 fg *= factorNorm[l];
315 double const pfczl = pfc * zetaLambda[l];
316 double const p2etapl = plambda * factorDeriv[l];
317 double const p1 = fg * (pfczl * (rinvijik - costijk
318 / r2ij - p2etapl * rijs / rij)
319 + pr1 * plambda);
320 double const p2 = fg * (pfczl * (rinvijik - costijk
321 / r2ik - p2etapl * riks / rik)
322 + pr2 * plambda);
323 double const p3 = fg * (pfczl * (rinvijik + p2etapl
324 * rjks / rjk) - pr3 * plambda);
325
326 // Save force contributions in Atom storage.
327 //
328 // SIMPLE EXPRESSIONS:
329 //size_t const li = members[l]->getIndex();
330 //atom.dGdr[li] += p1 * drij + p2 * drik;
331 //atom.neighbors[j].dGdr[li] -= p1 * drij
332 // + p3 * drjk;
333 //atom.neighbors[k].dGdr[li] -= p2 * drik
334 // - p3 * drjk;
335
336 double const p1drijx = p1 * dr1[0];
337 double const p1drijy = p1 * dr1[1];
338 double const p1drijz = p1 * dr1[2];
339
340 double const p2drikx = p2 * dr2[0];
341 double const p2driky = p2 * dr2[1];
342 double const p2drikz = p2 * dr2[2];
343
344 double const p3drjkx = p3 * dr3[0];
345 double const p3drjky = p3 * dr3[1];
346 double const p3drjkz = p3 * dr3[2];
347
348#ifndef N2P2_FULL_SFD_MEMORY
349 size_t li = memberIndex[l];
350#else
351 size_t const li = memberIndex[l];
352#endif
353 double* dGdr = atom.dGdr[li].r;
354 dGdr[0] += p1drijx + p2drikx;
355 dGdr[1] += p1drijy + p2driky;
356 dGdr[2] += p1drijz + p2drikz;
357
358#ifndef N2P2_FULL_SFD_MEMORY
359 li = memberIndexPerElement[l][nej];
360#endif
361 dGdr = nj.dGdr[li].r;
362 dGdr[0] -= p1drijx + p3drjkx;
363 dGdr[1] -= p1drijy + p3drjky;
364 dGdr[2] -= p1drijz + p3drjkz;
365
366#ifndef N2P2_FULL_SFD_MEMORY
367 li = memberIndexPerElement[l][nek];
368#endif
369 dGdr = nk.dGdr[li].r;
370 dGdr[0] -= p2drikx - p3drjkx;
371 dGdr[1] -= p2driky - p3drjky;
372 dGdr[2] -= p2drikz - p3drjkz;
373 } // l
374 } // rjk <= rc
375 } // rik <= rc
376 } // k
377 } // rij <= rc
378 } // j
379
380 for (size_t l = 0; l < members.size(); ++l)
381 {
382 result[l] *= factorNorm[l] / scalingFactors[l];
383 atom.G[memberIndex[l]] = members[l]->scale(result[l]);
384 }
385
386 delete[] result;
387
388 return;
389}
390
392{
393 vector<string> v;
394
395 v.push_back(strpr(getPrintFormatCommon().c_str(),
396 index + 1,
397 elementMap[ec].c_str(),
398 type,
399 subtype.c_str(),
400 rc / convLength,
401 cutoffAlpha));
402
403 for (size_t i = 0; i < members.size(); ++i)
404 {
405 v.push_back(strpr(getPrintFormatMember().c_str(),
406 members[i]->getEta() * convLength * convLength,
407 members[i]->getRs() / convLength,
408 members[i]->getLambda(),
409 members[i]->getZeta(),
410 members[i]->getLineNumber() + 1,
411 i + 1,
412 members[i]->getIndex() + 1,
413 (int)calculateExp[i]));
414 }
415
416 return v;
417}
void fdf(double r, double &fc, double &dfc) const
Calculate cutoff function and derivative .
void setCutoffParameter(double const alpha)
Set parameter for polynomial cutoff function (CT_POLY).
void setCutoffType(CutoffType const cutoffType)
Set cutoff type.
void setCutoffRadius(double const cutoffRadius)
Set cutoff radius.
Contains element map.
Definition: ElementMap.h:30
std::size_t atomicNumber(std::size_t index) const
Get atomic number from element index.
Definition: ElementMap.h:145
std::string getSubtype() const
Get private subtype member variable.
double getCutoffAlpha() const
Get private cutoffAlpha member variable.
CutoffFunction::CutoffType getCutoffType() const
Get private cutoffType member variable.
Weighted angular symmetry function (type 13)
Symmetry function base class.
Definition: SymFnc.h:40
double getConvLength() const
Get private convLength member variable.
Definition: SymFnc.h:364
double getRc() const
Get private rc member variable.
Definition: SymFnc.h:360
std::size_t getType() const
Get private type member variable.
Definition: SymFnc.h:355
std::size_t getEc() const
Get private ec member variable.
Definition: SymFnc.h:356
double cutoffAlpha
Cutoff function parameter (common feature).
std::string subtype
Subtype string (specifies cutoff type) (common feature).
CutoffFunction fc
Cutoff function used by this symmetry function group.
double rc
Cutoff radius (common feature).
CutoffFunction::CutoffType cutoffType
Cutoff type used by this symmetry function group (common feature).
Weighted angular symmetry function group (type 13)
std::vector< double > zetaLambda
Vector containing values of all member symmetry functions.
virtual bool addMember(SymFnc const *const symmetryFunction)
Potentially add a member to group.
std::vector< double > eta
Vector containing values of all member symmetry functions.
std::vector< bool > useIntegerPow
Vector containing values of all member symmetry functions.
std::vector< double > zeta
Vector containing values of all member symmetry functions.
std::vector< double > lambda
Vector containing values of all member symmetry functions.
std::vector< double > rs
Vector containing values of all member symmetry functions.
virtual void setScalingFactors()
Fill scalingFactors with values from member symmetry functions.
virtual bool operator==(SymGrp const &rhs) const
Overload == operator.
std::vector< int > zetaInt
Vector containing values of all member symmetry functions.
virtual void calculate(Atom &atom, bool const derivatives) const
Calculate all symmetry functions of this group for one atom.
std::vector< bool > calculateExp
Vector indicating whether exponential term needs to be calculated.
std::vector< double > factorDeriv
Vector containing precalculated normalizing factor for derivatives.
virtual bool operator<(SymGrp const &rhs) const
Overload < operator.
virtual void sortMembers()
Sort member symmetry functions.
std::vector< SymFncExpAngnWeighted const * > members
Vector of all group member pointers.
std::vector< double > factorNorm
Vector containing precalculated normalizing factor for each zeta.
virtual std::vector< std::string > parameterLines() const
Give symmetry function group parameters on multiple lines.
std::size_t type
Symmetry function type.
Definition: SymGrp.h:106
std::size_t getType() const
Get private type member variable.
Definition: SymGrp.h:185
std::size_t index
Symmetry function group index.
Definition: SymGrp.h:110
std::vector< size_t > memberIndex
Vector containing indices of all member symmetry functions.
Definition: SymGrp.h:116
std::string getPrintFormatCommon() const
Get common parameter line format string.
Definition: SymGrp.cpp:97
std::size_t ec
Element index of center atom (common feature).
Definition: SymGrp.h:112
std::vector< std::vector< std::size_t > > memberIndexPerElement
Vector containing per-element indices of all member symmetry functions.
Definition: SymGrp.h:124
std::size_t getEc() const
Get private ec member variable.
Definition: SymGrp.h:186
double convLength
Data set normalization length conversion factor.
Definition: SymGrp.h:114
ElementMap elementMap
Copy of element map.
Definition: SymGrp.h:108
std::size_t getIndex() const
Get private index member variable.
Definition: SymGrp.h:184
std::string getPrintFormatMember() const
Get member parameter line format string.
Definition: SymGrp.cpp:130
std::vector< double > scalingFactors
Scaling factors of all member symmetry functions.
Definition: SymGrp.h:118
std::set< std::string > parametersMember
Set of common parameters IDs.
Definition: SymGrp.h:122
Definition: Atom.h:29
string strpr(const char *format,...)
String version of printf function.
Definition: utility.cpp:90
double pow_int(double x, int n)
Integer version of power function, "fast exponentiation algorithm".
Definition: utility.cpp:292
Struct to store information on neighbor atoms.
Definition: Atom.h:36
std::vector< double > cache
Symmetry function cache (e.g. for cutoffs, compact functions).
Definition: Atom.h:49
std::size_t element
Element index of neighbor atom.
Definition: Atom.h:42
double d
Distance to neighbor atom.
Definition: Atom.h:44
Vec3D dr
Distance vector to neighbor atom.
Definition: Atom.h:46
std::vector< Vec3D > dGdr
Derivatives of symmetry functions with respect to neighbor coordinates.
Definition: Atom.h:60
Storage for a single atom.
Definition: Atom.h:33
std::vector< Neighbor > neighbors
Neighbor array (maximum number defined in macros.h.
Definition: Atom.h:170
std::vector< Vec3D > dGdr
Derivative of symmetry functions with respect to this atom's coordinates.
Definition: Atom.h:161
std::vector< double > G
Symmetry function values.
Definition: Atom.h:146
std::size_t numNeighbors
Total number of neighbors.
Definition: Atom.h:109
double r[3]
cartesian coordinates.
Definition: Vec3D.h:32