n2p2 - A neural network potential package
SymFncCompAngnWeighted.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// Copyright (C) 2020 Martin P. Bircher
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
19#include "Atom.h"
20#include "ElementMap.h"
21#include "utility.h"
22#include "Vec3D.h"
23#include <cstdlib> // atof, atoi
24#include <cmath> // exp, pow, cos
25#include <limits> // std::numeric_limits
26#include <stdexcept> // std::runtime_error
27
28using namespace std;
29using namespace nnp;
30
31SymFncCompAngnWeighted::
32SymFncCompAngnWeighted(ElementMap const& elementMap) :
33 SymFncBaseCompAngWeighted(24, elementMap)
34{
35}
36
38{
39 if (ec != rhs.getEc() ) return false;
40 if (type != rhs.getType()) return false;
41 SymFncCompAngnWeighted const& c =
42 dynamic_cast<SymFncCompAngnWeighted const&>(rhs);
43 if (subtype != c.getSubtype()) return false;
44 if (rc != c.rc ) return false;
45 if (rl != c.rl ) return false;
46 if (angleLeft != c.angleLeft ) return false;
47 if (angleRight != c.angleRight ) return false;
48 return true;
49}
50
52{
53 if (ec < rhs.getEc() ) return true;
54 else if (ec > rhs.getEc() ) return false;
55 if (type < rhs.getType()) return true;
56 else if (type > rhs.getType()) return false;
57 SymFncCompAngnWeighted const& c =
58 dynamic_cast<SymFncCompAngnWeighted const&>(rhs);
59 if (subtype < c.getSubtype()) return true;
60 else if (subtype > c.getSubtype()) return false;
61 if (rc < c.rc ) return true;
62 else if (rc > c.rc ) return false;
63 if (rl < c.rl ) return true;
64 else if (rl > c.rl ) return false;
65 if (angleLeft < c.angleLeft ) return true;
66 else if (angleLeft > c.angleLeft ) return false;
67 if (angleRight < c.angleRight ) return true;
68 else if (angleRight > c.angleRight ) return false;
69 return false;
70}
71
72void SymFncCompAngnWeighted::calculate(Atom& atom, bool const derivatives) const
73{
74 double r2l = 0.0;
75 if (rl > 0.0) r2l = rl * rl;
76 double r2c = rc * rc;
77 double result = 0.0;
78
79 size_t numNeighbors = atom.numNeighbors;
80 // Prevent problematic condition in loop test below (j < numNeighbors - 1).
81 if (numNeighbors == 0) numNeighbors = 1;
82
83 for (size_t j = 0; j < numNeighbors - 1; j++)
84 {
85 Atom::Neighbor& nj = atom.neighbors[j];
86 size_t const nej = nj.element;
87 double const rij = nj.d;
88 if (rij < rc && rij > rl)
89 {
90 double radij;
91 double dradij;
92#ifndef N2P2_NO_SF_CACHE
93 if (cacheIndices[nej].size() == 0) cr.fdf(rij, radij, dradij);
94 else
95 {
96 double& crad = nj.cache[cacheIndices[nej][0]];
97 double& cdrad = nj.cache[cacheIndices[nej][1]];
98 if (crad < 0) cr.fdf(rij, crad, cdrad);
99 radij = crad;
100 dradij = cdrad;
101 }
102#else
103 cr.fdf(rij, radij, dradij);
104#endif
105 for (size_t k = j + 1; k < numNeighbors; k++)
106 {
107 Atom::Neighbor& nk = atom.neighbors[k];
108 size_t const nek = nk.element;
109 double const rik = nk.d;
110 if (rik < rc && rik > rl)
111 {
112 // Energy calculation.
113 Vec3D drij = nj.dr;
114 Vec3D drik = nk.dr;
115 Vec3D drjk = nk.dr - nj.dr;
116 double rjk = drjk.norm2();
117 if (rjk >= r2c || rjk <= r2l) continue;
118 rjk = sqrt(rjk);
119
120 double radik;
121 double dradik;
122#ifndef N2P2_NO_SF_CACHE
123 if (cacheIndices[nek].size() == 0)
124 {
125 cr.fdf(rik, radik, dradik);
126 }
127 else
128 {
129 double& crad = nk.cache[cacheIndices[nek][0]];
130 double& cdrad = nk.cache[cacheIndices[nek][1]];
131 if (crad < 0) cr.fdf(rik, crad, cdrad);
132 radik = crad;
133 dradik = cdrad;
134 }
135#else
136 cr.fdf(rik, radik, dradik);
137#endif
138 double radjk;
139 double dradjk;
140 cr.fdf(rjk, radjk, dradjk);
141
142 double costijk = drij * drik;
143 double rinvijik = 1.0 / rij / rik;
144 costijk *= rinvijik;
145
146 // By definition, our polynomial is zero at 0 and 180 deg.
147 // Therefore, skip the whole rest which might yield some NaN
148 if (costijk <= -1.0 || costijk >= 1.0) continue;
149
150 // Regroup later: Get acos(cos)
151 double const acostijk = acos(costijk);
152 // Only go on if we are within our compact support
153 if (acostijk < angleLeftRadians ||
154 acostijk > angleRightRadians) continue;
155 double ang = 0.0;
156 double dang = 0.0;
157 ca.fdf(acostijk, ang, dang);
158
159 double const rad = radij * radik * radjk; // product of cutoff fcts
160 ang *= elementMap.atomicNumber(nej)
162 result += rad * ang;
163
164 // Force calculation.
165 if (!derivatives) continue;
166
167 double const dacostijk = -1.0
168 / sqrt(1.0 - costijk * costijk);
169 dang *= dacostijk
172 double const rinvij = rinvijik * rik;
173 double const rinvik = rinvijik * rij;
174 double const rinvjk = 1.0 / rjk;
175 double phiijik = rinvij * (rinvik - rinvij * costijk);
176 double phiikij = rinvik * (rinvij - rinvik * costijk);
177 double psiijik = rinvijik; // careful: sign flip w.r.t. notes due to nj.dGd...
178 phiijik *= dang;
179 phiikij *= dang;
180 psiijik *= dang;
181
182 // Cutoff function might be a divide by zero, but we screen that case before
183 double const chiij = rinvij * dradij * radik * radjk;
184 double const chiik = rinvik * radij * dradik * radjk;
185 double const chijk = -rinvjk * radij * radik * dradjk;
186
187 // rijs/rij due to the shifted radial part of the Gaussian
188 double const p1 = rad * phiijik + ang * chiij;
189 double const p2 = rad * phiikij + ang * chiik;
190 double const p3 = rad * psiijik + ang * chijk;
191 drij *= p1 * scalingFactor;
192 drik *= p2 * scalingFactor;
193 drjk *= p3 * scalingFactor;
194
195 // Save force contributions in Atom storage.
196 atom.dGdr[index] += drij + drik;
197#ifndef N2P2_FULL_SFD_MEMORY
198 nj.dGdr[indexPerElement[nej]] -= drij + drjk;
199 nk.dGdr[indexPerElement[nek]] -= drik - drjk;
200#else
201 nj.dGdr[index] -= drij + drjk;
202 nk.dGdr[index] -= drik - drjk;
203#endif
204 } // rik <= rc
205 } // k
206 } // rij <= rc
207 } // j
208
209 atom.G[index] = scale(result);
210
211 return;
212}
void fdf(double a, double &fa, double &dfa) const
Calculate compact function and derivative at once.
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
Intermediate symmetry function class for weighted angular compact SFs.
CompactFunction ca
Compact function member for angular part.
double angleLeft
Left angle boundary.
double angleLeftRadians
Left angle boundary in radians.
double angleRight
Right angle boundary.
double angleRightRadians
Right angle boundary in radians.
std::string getSubtype() const
Get private subtype member variable.
double rl
Lower bound of compact function, .
CompactFunction cr
Compact function for radial part.
std::string subtype
Subtype string (specifies e.g. polynom type).
Weighted narrow angular symmetry function with compact support (type 24)
virtual void calculate(Atom &atom, bool const derivatives) const
Calculate symmetry function for one atom.
virtual bool operator==(SymFnc const &rhs) const
Overload == operator.
virtual bool operator<(SymFnc const &rhs) const
Overload < operator.
Symmetry function base class.
Definition: SymFnc.h:40
std::size_t type
Symmetry function type.
Definition: SymFnc.h:268
std::size_t index
Symmetry function index (per element).
Definition: SymFnc.h:272
double scalingFactor
Scaling factor.
Definition: SymFnc.h:294
std::size_t getType() const
Get private type member variable.
Definition: SymFnc.h:355
double rc
Cutoff radius .
Definition: SymFnc.h:292
std::vector< std::vector< std::size_t > > cacheIndices
Cache indices for each element.
Definition: SymFnc.h:306
ElementMap elementMap
Copy of element map.
Definition: SymFnc.h:270
double scale(double value) const
Apply symmetry function scaling and/or centering.
Definition: SymFnc.cpp:169
std::size_t getEc() const
Get private ec member variable.
Definition: SymFnc.h:356
std::vector< std::size_t > indexPerElement
Per-element index for derivative memory in Atom::Neighbor::dGdr arrays.
Definition: SymFnc.h:302
std::size_t ec
Element index of center atom.
Definition: SymFnc.h:276
Definition: Atom.h:29
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
Vector in 3 dimensional real space.
Definition: Vec3D.h:30
double norm2() const
Calculate square of norm of vector.
Definition: Vec3D.h:299