n2p2 - A neural network potential package
SymFncCompAngn.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
18#include "SymFncCompAngn.h"
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
31SymFncCompAngn::
32SymFncCompAngn(ElementMap const& elementMap) :
33 SymFncBaseCompAng(21, elementMap)
34{
35}
36
37bool SymFncCompAngn::operator==(SymFnc const& rhs) const
38{
39 if (ec != rhs.getEc() ) return false;
40 if (type != rhs.getType()) return false;
41 SymFncCompAngn const& c = dynamic_cast<SymFncCompAngn const&>(rhs);
42 if (subtype != c.getSubtype()) return false;
43 if (e1 != c.e1 ) return false;
44 if (e2 != c.e2 ) return false;
45 if (rc != c.rc ) return false;
46 if (rl != c.rl ) return false;
47 if (angleLeft != c.angleLeft ) return false;
48 if (angleRight != c.angleRight ) return false;
49 return true;
50}
51
52bool SymFncCompAngn::operator<(SymFnc const& rhs) const
53{
54 if (ec < rhs.getEc() ) return true;
55 else if (ec > rhs.getEc() ) return false;
56 if (type < rhs.getType()) return true;
57 else if (type > rhs.getType()) return false;
58 SymFncCompAngn const& c = dynamic_cast<SymFncCompAngn const&>(rhs);
59 if (subtype < c.getSubtype()) return true;
60 else if (subtype > c.getSubtype()) return false;
61 if (e1 < c.e1 ) return true;
62 else if (e1 > c.e1 ) return false;
63 if (e2 < c.e2 ) return true;
64 else if (e2 > c.e2 ) return false;
65 if (rc < c.rc ) return true;
66 else if (rc > c.rc ) return false;
67 if (rl < c.rl ) return true;
68 else if (rl > c.rl ) return false;
69 if (angleLeft < c.angleLeft ) return true;
70 else if (angleLeft > c.angleLeft ) return false;
71 if (angleRight < c.angleRight ) return true;
72 else if (angleRight > c.angleRight ) return false;
73 return false;
74}
75
76void SymFncCompAngn::calculate(Atom& atom, bool const derivatives) const
77{
78 double r2l = 0.0;
79 if (rl > 0.0) r2l = rl * rl;
80 double r2c = rc * rc;
81 double result = 0.0;
82
83 size_t numNeighbors = atom.numNeighbors;
84 // Prevent problematic condition in loop test below (j < numNeighbors - 1).
85 if (numNeighbors == 0) numNeighbors = 1;
86
87 for (size_t j = 0; j < numNeighbors - 1; j++)
88 {
89 Atom::Neighbor& nj = atom.neighbors[j];
90 size_t const nej = nj.element;
91 double const rij = nj.d;
92 if ((e1 == nej || e2 == nej) && rij < rc && rij > rl)
93 {
94 double radij;
95 double dradij;
96#ifndef N2P2_NO_SF_CACHE
97 if (cacheIndices[nej].size() == 0) cr.fdf(rij, radij, dradij);
98 else
99 {
100 double& crad = nj.cache[cacheIndices[nej][0]];
101 double& cdrad = nj.cache[cacheIndices[nej][1]];
102 if (crad < 0) cr.fdf(rij, crad, cdrad);
103 radij = crad;
104 dradij = cdrad;
105 }
106#else
107 cr.fdf(rij, radij, dradij);
108#endif
109 for (size_t k = j + 1; k < numNeighbors; k++)
110 {
111 Atom::Neighbor& nk = atom.neighbors[k];
112 size_t const nek = nk.element;
113 if ((e1 == nej && e2 == nek) ||
114 (e2 == nej && e1 == nek))
115 {
116 double const rik = nk.d;
117 if (rik < rc && rik > rl)
118 {
119 // Energy calculation.
120 Vec3D drij = nj.dr;
121 Vec3D drik = nk.dr;
122 Vec3D drjk = nk.dr - nj.dr;
123 double rjk = drjk.norm2();
124 if (rjk >= r2c || rjk <= r2l) continue;
125 rjk = sqrt(rjk);
126
127 double radik;
128 double dradik;
129#ifndef N2P2_NO_SF_CACHE
130 if (cacheIndices[nek].size() == 0)
131 {
132 cr.fdf(rik, radik, dradik);
133 }
134 else
135 {
136 double& crad = nk.cache[cacheIndices[nek][0]];
137 double& cdrad = nk.cache[cacheIndices[nek][1]];
138 if (crad < 0) cr.fdf(rik, crad, cdrad);
139 radik = crad;
140 dradik = cdrad;
141 }
142#else
143 cr.fdf(rik, radik, dradik);
144#endif
145 double radjk;
146 double dradjk;
147 cr.fdf(rjk, radjk, dradjk);
148
149 double costijk = drij * drik;
150 double rinvijik = 1.0 / rij / rik;
151 costijk *= rinvijik;
152
153 // By definition, our polynomial is zero at 0 and 180 deg.
154 // Therefore, skip the whole rest which might yield some NaN
155 if (costijk <= -1.0 || costijk >= 1.0) continue;
156
157 // Regroup later: Get acos(cos)
158 double const acostijk = acos(costijk);
159 // Only go on if we are within our compact support
160 if (acostijk < angleLeftRadians ||
161 acostijk > angleRightRadians) continue;
162 double ang = 0.0;
163 double dang = 0.0;
164 ca.fdf(acostijk, ang, dang);
165
166 double const rad = radij * radik * radjk; // product of cutoff fcts
167 result += rad * ang;
168
169 // Force calculation.
170 if (!derivatives) continue;
171
172 double const dacostijk = -1.0
173 / sqrt(1.0 - costijk * costijk);
174 dang *= dacostijk;
175 double const rinvij = rinvijik * rik;
176 double const rinvik = rinvijik * rij;
177 double const rinvjk = 1.0 / rjk;
178 double phiijik = rinvij * (rinvik - rinvij*costijk);
179 double phiikij = rinvik * (rinvij - rinvik*costijk);
180 double psiijik = rinvijik; // careful: sign flip w.r.t. notes due to nj.dGd...
181 phiijik *= dang;
182 phiikij *= dang;
183 psiijik *= dang;
184
185 // Cutoff function might be a divide by zero, but we screen that case before
186 double const chiij = rinvij * dradij * radik * radjk;
187 double const chiik = rinvik * radij * dradik * radjk;
188 double const chijk = -rinvjk * radij * radik * dradjk;
189
190 // rijs/rij due to the shifted radial part of the Gaussian
191 double const p1 = rad * phiijik + ang * chiij;
192 double const p2 = rad * phiikij + ang * chiik;
193 double const p3 = rad * psiijik + ang * chijk;
194 drij *= p1 * scalingFactor;
195 drik *= p2 * scalingFactor;
196 drjk *= p3 * scalingFactor;
197
198 // Save force contributions in Atom storage.
199 atom.dGdr[index] += drij + drik;
200#ifndef N2P2_FULL_SFD_MEMORY
201 nj.dGdr[indexPerElement[nej]] -= drij + drjk;
202 nk.dGdr[indexPerElement[nek]] -= drik - drjk;
203#else
204 nj.dGdr[index] -= drij + drjk;
205 nk.dGdr[index] -= drik - drjk;
206#endif
207 } // rik <= rc
208 } // elem
209 } // k
210 } // rij <= rc
211 } // j
212
213 atom.G[index] = scale(result);
214
215 return;
216}
void fdf(double a, double &fa, double &dfa) const
Calculate compact function and derivative at once.
Contains element map.
Definition: ElementMap.h:30
Intermediate symmetry function class for angular SFs with compact support.
double angleLeft
Left angle boundary.
double angleRight
Right angle boundary.
double angleRightRadians
Right angle boundary in radians.
std::size_t e2
Element index of neighbor atom 2.
CompactFunction ca
Compact function member for angular part.
double angleLeftRadians
Left angle boundary in radians.
std::size_t e1
Element index of neighbor atom 1.
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).
Narrow angular symmetry function with compact support (type 21)
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
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