n2p2 - A neural network potential package
SymGrpCompAngwWeighted.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 "SymFnc.h"
22#include "Vec3D.h"
23#include "utility.h"
24#include <algorithm> // std::sort
25#include <cmath> // exp
26#include <stdexcept> // std::runtime_error
27using namespace std;
28using namespace nnp;
29
30SymGrpCompAngwWeighted::
31SymGrpCompAngwWeighted(ElementMap const& elementMap) :
32 SymGrpBaseCompAngWeighted(25, elementMap)
33{
34}
35
37{
38 if (ec != rhs.getEc() ) return false;
39 if (type != rhs.getType()) return false;
40 return true;
41}
42
44{
45 if (ec < rhs.getEc() ) return true;
46 else if (ec > rhs.getEc() ) return false;
47 if (type < rhs.getType()) return true;
48 else if (type > rhs.getType()) return false;
49 return false;
50}
51
52bool SymGrpCompAngwWeighted::addMember(SymFnc const* const symmetryFunction)
53{
54 if (symmetryFunction->getType() != type) return false;
55
56 SymFncCompAngwWeighted const* sf =
57 dynamic_cast<SymFncCompAngwWeighted const*>(symmetryFunction);
58
59 if (members.empty())
60 {
61 ec = sf->getEc();
63 }
64
65 if (sf->getEc() != ec ) return false;
66 if (sf->getConvLength() != convLength )
67 {
68 throw runtime_error("ERROR: Unable to add symmetry function members "
69 "with different conversion factors.\n");
70 }
71
72 if (sf->getRl() <= 0.0) rmin = 0.0;
73 else rmin = min( rmin, sf->getRl() );
74 rmax = max( rmax, sf->getRc() );
75
76 members.push_back(sf);
77
78 return true;
79}
80
82{
83 sort(members.begin(),
84 members.end(),
85 comparePointerTargets<SymFncCompAngwWeighted const>);
86
87 mrl.resize(members.size(), 0.0);
88 mrc.resize(members.size(), 0.0);
89 mal.resize(members.size(), 0.0);
90 mar.resize(members.size(), 0.0);
91 for (size_t i = 0; i < members.size(); i++)
92 {
93 mrl.at(i) = members[i]->getRl();
94 mrc.at(i) = members[i]->getRc();
95 mal.at(i) = members[i]->getAngleLeft() * M_PI / 180.0;
96 mar.at(i) = members[i]->getAngleRight() * M_PI / 180.0;
97 memberIndex.push_back(members[i]->getIndex());
98 memberIndexPerElement.push_back(members[i]->getIndexPerElement());
99 calculateComp.push_back(true);
100 }
101
102#ifndef N2P2_NO_SF_CACHE
103 mci.resize(members.size());
104 for (size_t k = 0; k < members.size(); ++k)
105 {
106 mci.at(k) = members.at(k)->getCacheIndices();
107 }
108#endif
109
110 return;
111}
112
113// Depending on chosen symmetry functions this function may be very
114// time-critical when predicting new structures (e.g. in MD simulations). Thus,
115// lots of optimizations were used sacrificing some readablity. Vec3D
116// operations have been rewritten in simple C array style and the use of
117// temporary objects has been minimized. Some of the originally coded
118// expressions are kept in comments marked with "SIMPLE EXPRESSIONS:".
120calculate(Atom& atom, bool const derivatives) const
121{
122 double* result = new double[members.size()];
123 double* radij = new double[members.size()];
124 double* dradij = new double[members.size()];
125 for (size_t l = 0; l < members.size(); ++l)
126 {
127 result[l] = 0.0;
128 radij[l] = 0.0;
129 dradij[l] = 0.0;
130 }
131
132 size_t numNeighbors = atom.numNeighbors;
133 // Prevent problematic condition in loop test below (j < numNeighbors - 1).
134 if (numNeighbors == 0) numNeighbors = 1;
135
136 for (size_t j = 0; j < numNeighbors - 1; j++)
137 {
138 Atom::Neighbor& nj = atom.neighbors[j];
139 size_t const nej = nj.element;
140 double const rij = nj.d;
141
142 if (rij < rmax && rij > rmin)
143 {
144 // Precalculate the radial part for ij
145 // Supposedly saves quite a number of operations
146 for (size_t l = 0; l < members.size(); ++l)
147 {
148 if (rij > mrl[l] && rij < mrc[l])
149 {
150 SymFncCompAngwWeighted const& sf = *(members[l]);
151#ifndef N2P2_NO_SF_CACHE
152 if (mci[l][nej].size() == 0)
153 {
154 sf.getCompactRadial(rij, radij[l], dradij[l]);
155 }
156 else
157 {
158 double& crad = nj.cache[mci[l][nej][0]];
159 double& cdrad = nj.cache[mci[l][nej][1]];
160 if (crad < 0) sf.getCompactRadial(rij, crad, cdrad);
161 radij[l] = crad;
162 dradij[l] = cdrad;
163 }
164#else
165 sf.getCompactRadial(rij, radij[l], dradij[l]);
166#endif
167 }
168 else radij[l] = 0.0;
169 }
170
171 // SIMPLE EXPRESSIONS:
172 //Vec3D drij(atom.neighbors[j].dr);
173 double const* const dr1 = nj.dr.r;
174
175 for (size_t k = j + 1; k < numNeighbors; k++)
176 {
177 Atom::Neighbor& nk = atom.neighbors[k];
178 size_t const nek = nk.element;
179 double const rik = nk.d;
180 if (rik < rmax && rik > rmin)
181 {
182 // SIMPLE EXPRESSIONS:
183 //Vec3D drik(atom.neighbors[k].dr);
184 //Vec3D drjk = drik - drij;
185 double const* const dr2 = nk.dr.r;
186 double const dr30 = dr2[0] - dr1[0];
187 double const dr31 = dr2[1] - dr1[1];
188 double const dr32 = dr2[2] - dr1[2];
189
190 // Energy calculation.
191 double const rinvijik = 1.0 / (rij * rik);
192 double const costijk = (dr1[0] * dr2[0] +
193 dr1[1] * dr2[1] +
194 dr1[2] * dr2[2]) * rinvijik;
195
196 // By definition, our polynomial is zero at 0 and 180 deg.
197 // Therefore, skip the whole rest which might yield some NaN
198 if (costijk <= -1.0 || costijk >= 1.0) continue;
199
200 double const acostijk = acos(costijk);
201
202 double const rinvij = rinvijik * rik;
203 double const rinvik = rinvijik * rij;
204 double const phiijik0 = rinvij
205 * (rinvik - rinvij * costijk);
206 double const phiikij0 = rinvik
207 * (rinvij - rinvik * costijk);
208 double dacostijk = 0.0;
209 if (derivatives)
210 {
211 dacostijk = -1.0 / sqrt(1.0 - costijk * costijk);
212 }
213
214 double ang;
215 double dang;
216 double radik;
217 double dradik;
218
219 for (size_t l = 0; l < members.size(); ++l)
220 {
221 // Break conditions.
222 if (radij[l] == 0.0 ||
223 rik <= mrl[l] || rik >= mrc[l] ||
224 acostijk <= mal[l] || acostijk >= mar[l])
225 {
226 continue;
227 }
228
229 SymFncCompAngwWeighted const& sf = *(members[l]);
230#ifndef N2P2_NO_SF_CACHE
231 if (mci[l][nek].size() == 0)
232 {
233 sf.getCompactRadial(rik, radik, dradik);
234 }
235 else
236 {
237 double& crad = nk.cache[mci[l][nek][0]];
238 double& cdrad = nk.cache[mci[l][nek][1]];
239 if (crad < 0) sf.getCompactRadial(rik, crad, cdrad);
240 radik = crad;
241 dradik = cdrad;
242 }
243#else
244 sf.getCompactRadial(rik, radik, dradik);
245#endif
246 sf.getCompactAngle(acostijk, ang, dang);
247
248 double const z = elementMap.atomicNumber(nej)
250 ang *= z;
251 double rad = radij[l] * radik;
252 result[l] += rad * ang;
253
254 // Force calculation.
255 if (!derivatives) continue;
256
257 dang *= dacostijk;
258 double const phiijik = phiijik0 * dang;
259 double const phiikij = phiikij0 * dang;
260 double const psiijik = rinvijik * dang;
261
262 double const chiij = rinvij * dradij[l] * radik;
263 double const chiik = rinvik * radij[l] * dradik;
264
265 double p1;
266 double p2;
267 double p3;
268
269 if (dang != 0.0 && rad != 0.0)
270 {
271 rad *= scalingFactors[l] * z;
272 ang *= scalingFactors[l];
273 p1 = rad * phiijik + ang * chiij;
274 p2 = rad * phiikij + ang * chiik;
275 p3 = rad * psiijik;
276 }
277 else if (ang != 0.0)
278 {
279 ang *= scalingFactors[l];
280
281 p1 = ang * chiij;
282 p2 = ang * chiik;
283 p3 = 0.0;
284 }
285 else continue;
286
287 // SIMPLE EXPRESSIONS:
288 // Save force contributions in Atom storage.
289 //atom.dGdr[memberIndex[l]] += p1 * drij
290 // + p2 * drik;
291 //atom.neighbors[j].
292 // dGdr[memberIndex[l]] -= p1 * drij
293 // + p3 * drjk;
294 //atom.neighbors[k].
295 // dGdr[memberIndex[l]] -= p2 * drik
296 // - p3 * drjk;
297
298 double const p1drijx = p1 * dr1[0];
299 double const p1drijy = p1 * dr1[1];
300 double const p1drijz = p1 * dr1[2];
301
302 double const p2drikx = p2 * dr2[0];
303 double const p2driky = p2 * dr2[1];
304 double const p2drikz = p2 * dr2[2];
305
306 double const p3drjkx = p3 * dr30;
307 double const p3drjky = p3 * dr31;
308 double const p3drjkz = p3 * dr32;
309
310#ifndef N2P2_FULL_SFD_MEMORY
311 size_t li = memberIndex[l];
312#else
313 size_t const li = memberIndex[l];
314#endif
315 double* dGdr = atom.dGdr[li].r;
316 dGdr[0] += p1drijx + p2drikx;
317 dGdr[1] += p1drijy + p2driky;
318 dGdr[2] += p1drijz + p2drikz;
319
320#ifndef N2P2_FULL_SFD_MEMORY
321 li = memberIndexPerElement[l][nej];
322#endif
323 dGdr = nj.dGdr[li].r;
324 dGdr[0] -= p1drijx + p3drjkx;
325 dGdr[1] -= p1drijy + p3drjky;
326 dGdr[2] -= p1drijz + p3drjkz;
327
328#ifndef N2P2_FULL_SFD_MEMORY
329 li = memberIndexPerElement[l][nek];
330#endif
331 dGdr = nk.dGdr[li].r;
332 dGdr[0] -= p2drikx - p3drjkx;
333 dGdr[1] -= p2driky - p3drjky;
334 dGdr[2] -= p2drikz - p3drjkz;
335 } // l
336 } // rik <= rc
337 } // k
338 } // rij <= rc
339 } // j
340
341 for (size_t l = 0; l < members.size(); ++l)
342 {
343 atom.G[memberIndex[l]] = members[l]->scale(result[l]);
344 }
345
346 delete[] result;
347 delete[] radij;
348 delete[] dradij;
349
350 return;
351}
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
void getCompactRadial(double const x, double &fx, double &dfx) const
void getCompactAngle(double const x, double &fx, double &dfx) const
double getRl() const
Get private rl member variable.
Weighted wide angular symmetry function with compact support (type 25)
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
std::vector< double > mal
Member angleLeft.
std::vector< double > mrc
Member rc.
std::vector< bool > calculateComp
Vector indicating whether compact function needs to be recalculated.
std::vector< double > mrl
Member rl.
std::vector< std::vector< std::vector< std::size_t > > > mci
Member cache indices for actual neighbor element.
std::vector< double > mar
Member angleRight.
double rmin
Minimum radius within group.
double rmax
Maximum radius within group.
virtual bool addMember(SymFnc const *const symmetryFunction)
Potentially add a member to group.
virtual void calculate(Atom &atom, bool const derivatives) const
Calculate all symmetry functions of this group for one atom.
std::vector< SymFncCompAngwWeighted const * > members
Vector of all group member pointers.
virtual bool operator<(SymGrp const &rhs) const
Overload < operator.
virtual void sortMembers()
Sort member symmetry functions.
virtual bool operator==(SymGrp const &rhs) const
Overload == operator.
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::vector< size_t > memberIndex
Vector containing indices of all member symmetry functions.
Definition: SymGrp.h:116
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::vector< double > scalingFactors
Scaling factors of all member symmetry functions.
Definition: SymGrp.h:118
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
double r[3]
cartesian coordinates.
Definition: Vec3D.h:32