SimpleFastOpenAtomicVisualiser
Loading...
Searching...
No Matches
neighbours.h
Go to the documentation of this file.
1#ifndef NEIGHBOURS_H
2#define NEIGHBOURS_H
3
4#include <vector>
5#include <cstdint>
6#include <cmath>
7#include <algorithm>
8
9#include <constants.h>
10#include <atom.h>
11
18{
19
20public:
21
28 (
29 const std::vector<Atom> & atoms,
30 float domainSideLength = -1.0
31 )
32 {
33 if (domainSideLength == -1.0)
34 {
35 float r = largest(atoms);
36 domainSize = 2.0f*glm::vec3(r, r, r);
37 }
38 else
39 {
40 domainSize = glm::vec3(domainSideLength, domainSideLength, domainSideLength);
41 }
42
43 minPoint = min(atoms);
44 length = max(atoms)-minPoint;
45
46
47 length += domainSize;
48
49 nx = length.x / domainSize.x;
50 ny = length.y / domainSize.y;
51 nz = length.z / domainSize.z;
52
53 clear();
54
55 build(atoms);
56 }
57
63 void build(const std::vector<Atom> & atoms)
64 {
65 domainAssignments = std::vector<uint64_t>(atoms.size(), NULL_INDEX);
66 for (uint64_t i = 0; i < atoms.size(); i++)
67 {
68 domainAssignments[i] = std::min(hash(atoms[i].position), uint64_t(domains.size()-1));
69 domains[domainAssignments[i]].push_back(i);
70 }
71 }
72
77 void clear()
78 {
79 // Set to twice close packing domain list size.
80 // Overlaps may lead to > close packed size.
81 domains = std::vector<std::vector<uint64_t>>(nx*ny*nz);
82 for (auto & domain : domains)
83 {
84 domain.reserve(2*std::ceil(domainSize.x*domainSize.y*domainSize.z*0.74048));
85 }
86 domainAssignments = std::vector<uint64_t>(domainAssignments.size(), NULL_INDEX);
87 }
88
108 std::vector<std::pair<uint64_t, float>> neighbours
109 (
110 const std::vector<Atom> & atoms,
111 glm::vec3 position,
112 float cutoff,
113 bool noDirect = false,
114 bool nearestImage = true
115 ) const
116 {
117 std::map<uint64_t, float> n;
118
119 auto wrap = [](int i, int m){ return ((i % m) + m) % m; };
120
121 auto coords = domainCoords(position);
122 float rc2 = cutoff*cutoff;
123 float halfWidth = 0.5f*std::min(std::min(length.x, length.y), length.z);
124 if (!noDirect && cutoff >= halfWidth)
125 {
126 return neighboursDirect(atoms, position, cutoff, nearestImage);
127 }
128
129 cutoff = std::min(cutoff, std::max(std::max(length.x, length.y), length.z));
130
131 // Shells to search in either direction.
132 int sx = int(std::ceil(cutoff/domainSize.x))+1;
133 int sy = int(std::ceil(cutoff/domainSize.y))+1;
134 int sz = int(std::ceil(cutoff/domainSize.z))+1;
135
136 for (int i = -sx; i <= sx; i++)
137 {
138 uint64_t u = (wrap(i+int(coords.x), nx))*ny*nz;
139 for (int j = -sy; j <= sy; j++)
140 {
141 uint64_t v = (wrap(j+int(coords.y), ny))*nz;
142 for (int k = -sz; k <= sz; k++)
143 {
144 uint64_t w = u+v+wrap(k+int(coords.z), nz);
145 if (w > domains.size()) { continue; }
146 for (const auto & index : domains[w])
147 {
148 if (index > atoms.size()) { break; }
149 glm::vec3 r = position-atoms[index].position;
150 if (nearestImage)
151 {
152 for (uint8_t c = 0; c < 3; c++)
153 {
154 if (r[c] > length[c]*0.5f) { r[c] = r[c]-length[c]; }
155 if (r[c] <= -length[c]*0.5f) { r[c] = r[c]+length[c]; }
156 }
157 }
158 float d2 = glm::dot(r, r);
159 if (d2 <= rc2)
160 {
161 n.insert({index, std::sqrt(d2)});
162 }
163 }
164 }
165 }
166 }
167 std::vector<std::pair<uint64_t, float>> nd(n.begin(), n.end());
168 std::sort
169 (
170 nd.begin(),
171 nd.end(),
172 []
173 (
174 const std::pair<uint64_t, float> & a,
175 const std::pair<uint64_t, float> & b
176 ) { return a.second == b.second ? a.first < b.first : a.second < b.second; }
177 );
178 return nd;
179 }
180
194 std::vector<std::pair<uint64_t, float>> neighboursDirect
195 (
196 const std::vector<Atom> & atoms,
197 glm::vec3 position,
198 float cutoff,
199 bool nearestImage = true
200 ) const
201 {
202 std::vector<std::pair<uint64_t, float>> directNeighbours;
203 float rc2 = cutoff*cutoff;
204 for (uint64_t i = 0; i < atoms.size(); i++)
205 {
206 glm::vec3 r = position-atoms[i].position;
207 if (nearestImage)
208 {
209 for (uint8_t c = 0; c < 3; c++)
210 {
211 if (r[c] > length[c]*0.5f) { r[c] = r[c]-length[c]; }
212 if (r[c] <= -length[c]*0.5f) { r[c] = r[c]+length[c]; }
213 }
214 }
215 float d2 = glm::dot(r, r);
216 if (d2 <= rc2)
217 {
218 directNeighbours.push_back({i, std::sqrt(d2)});
219 }
220 }
221 std::sort
222 (
223 directNeighbours.begin(),
224 directNeighbours.end(),
225 []
226 (
227 const std::pair<uint64_t, float> & a,
228 const std::pair<uint64_t, float> & b
229 ) { return a.second == b.second ? a.first < b.first : a.second < b.second; }
230 );
231 return directNeighbours;
232 }
233
234
235private:
236
237 glm::vec3 minPoint;
238 glm::vec3 length;
239 uint64_t nx, ny, nz;
240 glm::vec3 domainSize;
241
242 std::vector<std::vector<uint64_t>> domains;
243 std::vector<uint64_t> domainAssignments;
244
245 inline glm::vec<3, uint64_t, glm::packed_highp> domainCoords(const glm::vec3 & position) const
246 {
247 return glm::floor((position-minPoint)/domainSize);
248 }
249
250 inline uint64_t hash(const glm::vec3 & position) const
251 {
252 auto c = domainCoords(position);
253 return c.x*ny*nz+c.y*nz+c.z;
254 }
255};
256
257#endif /* NEIGHBOURS_H */
glm::vec3 max(const std::vector< Atom > &atoms)
Calculate the maximum positions of some Atoms.
Definition atom.h:176
glm::vec3 min(const std::vector< Atom > &atoms)
Calculate the minimum positions of some Atoms.
Definition atom.h:157
float largest(const std::vector< Atom > &atoms)
Calculate the largest Atom.
Definition atom.h:232
Calculate neighbour lists.
Definition neighbours.h:18
std::vector< std::pair< uint64_t, float > > neighboursDirect(const std::vector< Atom > &atoms, glm::vec3 position, float cutoff, bool nearestImage=true) const
Get the neighbours to a position within a cutoff by a direct evaluation.
Definition neighbours.h:195
Neighbours(const std::vector< Atom > &atoms, float domainSideLength=-1.0)
Construct a Neighbour list from some Atoms.
Definition neighbours.h:28
std::vector< std::pair< uint64_t, float > > neighbours(const std::vector< Atom > &atoms, glm::vec3 position, float cutoff, bool noDirect=false, bool nearestImage=true) const
Get the neighbours to a position within a cutoff using the spatial domains.
Definition neighbours.h:109
void build(const std::vector< Atom > &atoms)
Build the neighbour list from some Atoms.
Definition neighbours.h:63
void clear()
Reset the spatial domains.
Definition neighbours.h:77
glm::vec< L, float, glm::qualifier::highp > vec
Definition commandLine.h:214
constexpr uint64_t NULL_INDEX
An index reserved for a NULL value.
Definition constants.h:11