n2p2 - A neural network potential package
SymFncCompAngwWeighted.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
31SymFncCompAngwWeighted::
32SymFncCompAngwWeighted(ElementMap const& elementMap) :
33 SymFncBaseCompAngWeighted(25, elementMap)
34{
35}
36
38{
39 if (ec != rhs.getEc() ) return false;
40 if (type != rhs.getType()) return false;
41 SymFncCompAngwWeighted const& c =
42 dynamic_cast<SymFncCompAngwWeighted 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 SymFncCompAngwWeighted const& c =
58 dynamic_cast<SymFncCompAngwWeighted 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 SymFncCompAngwWeighted::calculate(Atom& atom, bool const derivatives) const
73{
74 double result = 0.0;
75
76 size_t numNeighbors = atom.numNeighbors;
77 // Prevent problematic condition in loop test below (j < numNeighbors - 1).
78 if (numNeighbors == 0) numNeighbors = 1;
79
80 for (size_t j = 0; j < numNeighbors - 1; j++)
81 {
82 Atom::Neighbor& nj = atom.neighbors[j];
83 size_t const nej = nj.element;
84 double const rij = nj.d;
85 if (rij < rc && rij > rl)
86 {
87 double radij;
88 double dradij;
89#ifndef N2P2_NO_SF_CACHE
90 if (cacheIndices[nej].size() == 0) cr.fdf(rij, radij, dradij);
91 else
92 {
93 double& crad = nj.cache[cacheIndices[nej][0]];
94 double& cdrad = nj.cache[cacheIndices[nej][1]];
95 if (crad < 0) cr.fdf(rij, crad, cdrad);
96 radij = crad;
97 dradij = cdrad;
98 }
99#else
100 cr.fdf(rij, radij, dradij);
101#endif
102 for (size_t k = j + 1; k < numNeighbors; k++)
103 {
104 Atom::Neighbor& nk = atom.neighbors[k];
105 size_t const nek = nk.element;
106 double const rik = nk.d;
107 if (rik < rc && rik > rl)
108 {
109 // Energy calculation.
110 double radik;
111 double dradik;
112#ifndef N2P2_NO_SF_CACHE
113 if (cacheIndices[nek].size() == 0)
114 {
115 cr.fdf(rik, radik, dradik);
116 }
117 else
118 {
119 double& crad = nk.cache[cacheIndices[nek][0]];
120 double& cdrad = nk.cache[cacheIndices[nek][1]];
121 if (crad < 0) cr.fdf(rik, crad, cdrad);
122 radik = crad;
123 dradik = cdrad;
124 }
125#else
126 cr.fdf(rik, radik, dradik);
127#endif
128
129 Vec3D drij = nj.dr;
130 Vec3D drik = nk.dr;
131 Vec3D drjk = nk.dr - nj.dr;
132 double costijk = drij * drik;
133 double rinvijik = 1.0 / rij / rik;
134 costijk *= rinvijik;
135
136 // By definition, our polynomial is zero at 0 and 180 deg.
137 // Therefore, skip the whole rest which might yield some NaN
138 if (costijk <= -1.0 || costijk >= 1.0) continue;
139
140 // Regroup later: Get acos(cos)
141 double const acostijk = acos(costijk);
142 // Only go on if we are within our compact support
143 if (acostijk < angleLeftRadians ||
144 acostijk > angleRightRadians) continue;
145 double ang = 0.0;
146 double dang = 0.0;
147 ca.fdf(acostijk, ang, dang);
148
149 double const rad = radij * radik; // product of cutoff fcts
150 ang *= elementMap.atomicNumber(nej)
152 result += rad * ang;
153
154 // Force calculation.
155 if (!derivatives) continue;
156
157 double const dacostijk = -1.0
158 / sqrt(1.0 - costijk * costijk);
159 dang *= dacostijk
162 double const rinvij = rinvijik * rik;
163 double const rinvik = rinvijik * rij;
164 double phiijik = rinvij * (rinvik - rinvij * costijk);
165 double phiikij = rinvik * (rinvij - rinvik * costijk);
166 double psiijik = rinvijik; // careful: sign flip w.r.t. notes due to nj.dGd...
167 phiijik *= dang;
168 phiikij *= dang;
169 psiijik *= dang;
170
171 // Cutoff function might be a divide by zero, but we screen that case before
172 double const chiij = rinvij * radik * dradij;
173 double const chiik = rinvik * radij * dradik;
174
175 // rijs/rij due to the shifted radial part of the Gaussian
176 double const p1 = rad * phiijik + ang * chiij;
177 double const p2 = rad * phiikij + ang * chiik;
178 double const p3 = rad * psiijik;
179 drij *= p1 * scalingFactor;
180 drik *= p2 * scalingFactor;
181 drjk *= p3 * scalingFactor;
182
183 // Save force contributions in Atom storage.
184 atom.dGdr[index] += drij + drik;
185#ifndef N2P2_FULL_SFD_MEMORY
186 nj.dGdr[indexPerElement[nej]] -= drij + drjk;
187 nk.dGdr[indexPerElement[nek]] -= drik - drjk;
188#else
189 nj.dGdr[index] -= drij + drjk;
190 nk.dGdr[index] -= drik - drjk;
191#endif
192 } // rik <= rc
193 } // k
194 } // rij <= rc
195 } // j
196
197 atom.G[index] = scale(result);
198
199 return;
200}
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 wide angular symmetry function with compact support (type 25)
virtual bool operator<(SymFnc const &rhs) const
Overload < operator.
virtual void calculate(Atom &atom, bool const derivatives) const
Calculate symmetry function for one atom.
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:28
Struct to store information on neighbor atoms.
Definition: Atom.h:35
std::vector< double > cache
Symmetry function cache (e.g. for cutoffs, compact functions).
Definition: Atom.h:48
std::size_t element
Element index of neighbor atom.
Definition: Atom.h:41
double d
Distance to neighbor atom.
Definition: Atom.h:43
Vec3D dr
Distance vector to neighbor atom.
Definition: Atom.h:45
std::vector< Vec3D > dGdr
Derivatives of symmetry functions with respect to neighbor coordinates.
Definition: Atom.h:59
Storage for a single atom.
Definition: Atom.h:32
std::vector< Neighbor > neighbors
Neighbor array (maximum number defined in macros.h.
Definition: Atom.h:148
std::vector< Vec3D > dGdr
Derivative of symmetry functions with respect to this atom's coordinates.
Definition: Atom.h:146
std::vector< double > G
Symmetry function values.
Definition: Atom.h:134
std::size_t numNeighbors
Total number of neighbors.
Definition: Atom.h:106
Vector in 3 dimensional real space.
Definition: Vec3D.h:29