MDStressLab++
Loading...
Searching...
No Matches
neighbor_list.cpp
Go to the documentation of this file.
1/*
2 * neighbor_list.cpp
3 *
4 * Created on: Nov 9, 2019
5 * Author: Nikhil; Adapted from Mingjian Wen's kimpy code
6 */
7
8
9
10#include "neighbor_list.h"
11#include "helper.hpp"
12#include <cmath>
13#include <cstring>
14#include <sstream>
15#include <vector>
16
17#define DIM 3
18#define TOL 1.0e-10
19
20
22{
23 if (nl != NULL)
24 {
25 for (int i = 0; i < nl->numberOfNeighborLists; i++)
26 {
27 NeighListOne * cnl = &(nl->lists[i]);
28 delete[] cnl->Nneighbors;
29 delete[] cnl->neighborList;
30 delete[] cnl->beginIndex;
31 cnl->numberOfParticles = 0;
32 cnl->cutoff = 0.0;
33 cnl->Nneighbors = NULL;
34 cnl->neighborList = NULL;
35 cnl->beginIndex = NULL;
36 }
37 delete[] nl->lists;
38 nl->lists = NULL;
40 }
41}
42
43
45 int const numberOfCutoffs,
46 int const numberOfParticles)
47{
48 nl->lists = new NeighListOne[numberOfCutoffs];
49 nl->numberOfNeighborLists = numberOfCutoffs;
50 for (int i = 0; i < numberOfCutoffs; i++)
51 {
52 NeighListOne * cnl = &(nl->lists[i]);
53 cnl->numberOfParticles = 0;
54 cnl->cutoff = 0.0;
55 cnl->Nneighbors = new int[numberOfParticles];
56 cnl->neighborList = NULL;
57 cnl->beginIndex = new int[numberOfParticles];
58 }
59}
60
61
62void nbl_initialize(NeighList ** const nl)
63{
64 *nl = new NeighList;
65 (*nl)->numberOfNeighborLists = 0;
66 (*nl)->lists = NULL;
67}
68
69
70void nbl_clean(NeighList ** const nl)
71{
73
74 delete (*nl);
75
76 // nullify pointer
77 (*nl) = NULL;
78}
79
80
81int nbl_build(NeighList * const nl,
82 int const numberOfParticles,
83 double const * coordinates,
84 double const influenceDistance,
85 int const numberOfCutoffs,
86 double const * cutoffs,
87 int const * needNeighbors)
88{
89 // find max and min extend of coordinates
90 double min[DIM];
91 double max[DIM];
92
93 // init max and min of coordinates to that of the first atom
94 for (int k = 0; k < DIM; k++)
95 {
96 min[k] = coordinates[k];
97 max[k] = coordinates[k] + 1.0; // +1 to prevent max==min for 1D and 2D case
98// max[k] = coordinates[k] + TOL; // +1 to prevent max==min for 1D and 2D case
99 }
100 for (int i = 0; i < numberOfParticles; i++)
101 {
102 for (int j = 0; j < DIM; j++)
103 {
104 if (max[j] < coordinates[DIM * i + j])
105 { max[j] = coordinates[DIM * i + j]; }
106 if (min[j] > coordinates[DIM * i + j])
107 { min[j] = coordinates[DIM * i + j]; }
108 }
109 }
110
111 // make the cell box
112 int size_total = 1;
113 int size[DIM];
114 for (int i = 0; i < DIM; i++)
115 {
116 size[i] = static_cast<int>((max[i] - min[i]) / influenceDistance);
117 size[i] = size[i] <= 0 ? 1 : size[i];
118 size_total *= size[i];
119 }
120 if (size_total > 1000000000)
121 {
122 MY_WARNING("Cell size too large. Check if you have partilces fly away.");
123 return 1;
124 }
125
126 // assign atoms into cells
127 std::vector<std::vector<int> > cells(size_total);
128 for (int i = 0; i < numberOfParticles; i++)
129 {
130 int index[DIM];
131 coords_to_index(&coordinates[DIM * i], size, max, min, index);
132 int idx = index[0] + index[1] * size[0] + index[2] * size[0] * size[1];
133 cells[idx].push_back(i);
134 }
135
136 // create neighbors
137
138 // free previous neigh content and then create new
140 nbl_allocate_memory(nl, numberOfCutoffs, numberOfParticles);
141
142 double * cutsqs = new double[numberOfCutoffs];
143 for (int i = 0; i < numberOfCutoffs; i++)
144 { cutsqs[i] = cutoffs[i] * cutoffs[i]; }
145
146 // temporary neigh container
147 std::vector<int> * tmp_neigh = new std::vector<int>[numberOfCutoffs];
148 int * total = new int[numberOfCutoffs];
149 int * num_neigh = new int[numberOfCutoffs];
150 for (int k = 0; k < numberOfCutoffs; k++) { total[k] = 0; }
151
152 for (int i = 0; i < numberOfParticles; i++)
153 {
154 for (int k = 0; k < numberOfCutoffs; k++) { num_neigh[k] = 0; }
155
156 if (needNeighbors[i])
157 {
158 int index[DIM];
159 coords_to_index(&coordinates[DIM * i], size, max, min, index);
160
161 // loop over neighborling cells and the cell atom i resides
162 for (int ii = std::max(0, index[0] - 1);
163 ii <= std::min(index[0] + 1, size[0] - 1);
164 ii++)
165 {
166 for (int jj = std::max(0, index[1] - 1);
167 jj <= std::min(index[1] + 1, size[1] - 1);
168 jj++)
169 {
170 for (int kk = std::max(0, index[2] - 1);
171 kk <= std::min(index[2] + 1, size[2] - 1);
172 kk++)
173 {
174 int idx = ii + jj * size[0] + kk * size[0] * size[1];
175
176 for (size_t m = 0; m < cells[idx].size(); m++)
177 {
178 int n = cells[idx][m];
179 if (n != i)
180 {
181 double rsq = 0.0;
182
183 for (int k = 0; k < DIM; k++)
184 {
185 double del
186 = coordinates[DIM * n + k] - coordinates[DIM * i + k];
187 rsq += del * del;
188 }
189 if (rsq < TOL)
190 {
191 std::ostringstream stringStream;
192 stringStream << "Collision of atoms " << i + 1 << " and "
193 << n + 1 << ". ";
194 stringStream << "Their distance is " << std::sqrt(rsq) << "."
195 << std::endl;
196 std::string my_str = stringStream.str();
197 MY_WARNING(my_str);
198 return 1;
199 }
200 for (int k = 0; k < numberOfCutoffs; k++)
201 {
202 if (rsq < cutsqs[k])
203 {
204 tmp_neigh[k].push_back(n);
205 num_neigh[k]++;
206 }
207 }
208 }
209 }
210 }
211 }
212 }
213 }
214
215 for (int k = 0; k < numberOfCutoffs; k++)
216 {
217 nl->lists[k].Nneighbors[i] = num_neigh[k];
218 nl->lists[k].beginIndex[i] = total[k];
219 total[k] += num_neigh[k];
220 }
221 }
222
223 for (int k = 0; k < numberOfCutoffs; k++)
224 {
225 nl->lists[k].numberOfParticles = numberOfParticles;
226 nl->lists[k].cutoff = cutoffs[k];
227 nl->lists[k].neighborList = new int[total[k]];
228 std::memcpy(
229 nl->lists[k].neighborList, tmp_neigh[k].data(), sizeof(int) * total[k]);
230 }
231
232 delete[] cutsqs;
233 delete[] tmp_neigh;
234 delete[] num_neigh;
235 delete[] total;
236
237 return 0;
238}
239
240
241int nbl_get_neigh(void const * const dataObject,
242 int const numberOfCutoffs,
243 double const * const cutoffs,
244 int const neighborListIndex,
245 int const particleNumber,
246 int * const numberOfNeighbors,
247 int const ** const neighborsOfParticle)
248{
249 int error = 1;
250 NeighList * nl = (NeighList *) dataObject;
251
252 if (neighborListIndex >= nl->numberOfNeighborLists) { return error; }
253 NeighListOne * cnl = &(nl->lists[neighborListIndex]);
254
255 if (cutoffs[neighborListIndex] > cnl->cutoff + TOL) { return error; }
256
257 // invalid id
258 int numberOfParticles = cnl->numberOfParticles;
259 if ((particleNumber >= numberOfParticles) || (particleNumber < 0))
260 {
261 MY_WARNING("Invalid part ID in nbl_get_neigh");
262 return error;
263 }
264
265 // number of neighbors
266 *numberOfNeighbors = cnl->Nneighbors[particleNumber];
267
268 // neighbor list starting point
269 int idx = cnl->beginIndex[particleNumber];
270 *neighborsOfParticle = cnl->neighborList + idx;
271
272 return 0;
273}
274
275
276int nbl_create_paddings(int const numberOfParticles,
277 double const cutoff,
278 double const * reference_cell,
279 double const * cell,
280 int const * PBC,
281 double const * reference_coordinates,
282 double const * coordinates,
283 const std::vector<std::string>& speciesCode,
284 int & numberOfPaddings,
285 std::vector<double> & reference_coordinatesOfPaddings,
286 std::vector<double> & coordinatesOfPaddings,
287 std::vector<std::string> & speciesCodeOfPaddings,
288 std::vector<int> & masterOfPaddings,
289 int referenceAndFinal)
290{
291 // transform coordinates into fractional coordinates
292 double tcell[9];
293 double fcell[9];
294 transpose(cell, tcell);
295 {
296 int error = inverse(tcell, fcell);
297 if (error) { return error; }
298 }
299
300
301 double reference_tcell[9];
302 double reference_fcell[9];
303 if (referenceAndFinal)
304 {
305 transpose(reference_cell, reference_tcell);
306 {
307 int error = inverse(reference_tcell, reference_fcell);
308 if (error) { return error; }
309 }
310 }
311
312 double* frac_coords= new double[DIM * numberOfParticles];
313 double* reference_frac_coords= nullptr;
314 if (referenceAndFinal) reference_frac_coords= new double[DIM * numberOfParticles];
315 double min[DIM] = {1e10, 1e10, 1e10};
316 double max[DIM] = {-1e10, -1e10, -1e10};
317 for (int i = 0; i < numberOfParticles; i++)
318 {
319 const double * atom_coords = coordinates + (DIM * i);
320 const double * reference_atom_coords = reference_coordinates + (DIM * i);
321 double x = dot(fcell, atom_coords);
322 double y = dot(fcell + 3, atom_coords);
323 double z = dot(fcell + 6, atom_coords);
324 frac_coords[DIM * i + 0] = x;
325 frac_coords[DIM * i + 1] = y;
326 frac_coords[DIM * i + 2] = z;
327 if (x < min[0]) { min[0] = x; }
328 if (y < min[1]) { min[1] = y; }
329 if (z < min[2]) { min[2] = z; }
330 if (x > max[0]) { max[0] = x; }
331 if (y > max[1]) { max[1] = y; }
332 if (z > max[2]) { max[2] = z; }
333 if(referenceAndFinal)
334 {
335 double reference_x = dot(reference_fcell, reference_atom_coords);
336 double reference_y = dot(reference_fcell + 3, reference_atom_coords);
337 double reference_z = dot(reference_fcell + 6, reference_atom_coords);
338 reference_frac_coords[DIM * i + 0]= reference_x;
339 reference_frac_coords[DIM * i + 1]= reference_y;
340 reference_frac_coords[DIM * i + 2]= reference_z;
341 }
342 }
343 // add some extra value to deal with edge case
344 for (int i = 0; i < DIM; i++)
345 {
346 min[i] -= 1e-10;
347 max[i] += 1e-10;
348 }
349
350 // volume of cell
351 double xprod[DIM];
352 cross(cell + 3, cell + 6, xprod);
353 double volume = std::abs(dot(cell, xprod));
354
355 // distance between parallelpiped cell faces
356 double dist[DIM];
357 cross(cell + 3, cell + 6, xprod);
358 dist[0] = volume / norm(xprod);
359 cross(cell + 6, cell + 0, xprod);
360 dist[1] = volume / norm(xprod);
361 cross(cell, cell + 3, xprod);
362 dist[2] = volume / norm(xprod);
363
364 // number of cells in each direction
365 double ratio[DIM];
366 double size[DIM];
367 for (int i = 0; i < DIM; i++)
368 {
369 ratio[i] = cutoff / dist[i];
370 size[i] = static_cast<int>(std::ceil(ratio[i]));
371 }
372
373 // creating padding atoms
374 for (int i = -size[0]; i <= size[0]; i++)
375 {
376 for (int j = -size[1]; j <= size[1]; j++)
377 {
378 for (int k = -size[2]; k <= size[2]; k++)
379 {
380 // skip contributing atoms
381 if (i == 0 && j == 0 && k == 0) { continue; }
382
383 // apply BC
384 if (PBC[0] == 0 && i != 0) { continue; }
385 if (PBC[1] == 0 && j != 0) { continue; }
386 if (PBC[2] == 0 && k != 0) { continue; }
387
388 for (int at = 0; at < numberOfParticles; at++)
389 {
390 double x = frac_coords[DIM * at + 0];
391 double y = frac_coords[DIM * at + 1];
392 double z = frac_coords[DIM * at + 2];
393 double reference_x, reference_y, reference_z;
394 if(referenceAndFinal)
395 {
396 reference_x= reference_frac_coords[DIM * at + 0];
397 reference_y= reference_frac_coords[DIM * at + 1];
398 reference_z= reference_frac_coords[DIM * at + 2];
399 }
400 // select the necessary atoms to repeate for the most outside bins
401 // the follwing few lines can be easily understood when assuming
402 // size=1
403 if (i == -size[0]
404 && x - min[0] < static_cast<double>(size[0]) - ratio[0])
405 { continue; }
406 if (i == size[0]
407 && max[0] - x < static_cast<double>(size[0]) - ratio[0])
408 { continue; }
409 if (j == -size[1]
410 && y - min[1] < static_cast<double>(size[1]) - ratio[1])
411 { continue; }
412 if (j == size[1]
413 && max[1] - y < static_cast<double>(size[1]) - ratio[1])
414 { continue; }
415 if (k == -size[2]
416 && z - min[2] < static_cast<double>(size[2]) - ratio[2])
417 { continue; }
418 if (k == size[2]
419 && max[2] - z < static_cast<double>(size[2]) - ratio[2])
420 { continue; }
421
422 // fractional coordinates of padding atom at
423 double atom_coords[3] = {i + x, j + y, k + z};
424 double reference_atom_coords[3];
425 if (referenceAndFinal)
426 {
427 reference_atom_coords[0]= i + reference_x;
428 reference_atom_coords[1]= j + reference_y;
429 reference_atom_coords[2]= k + reference_z;
430 }
431
432 // absolute coordinates of padding atoms
433 coordinatesOfPaddings.push_back(dot(tcell, atom_coords));
434 coordinatesOfPaddings.push_back(dot(tcell + 3, atom_coords));
435 coordinatesOfPaddings.push_back(dot(tcell + 6, atom_coords));
436 if (referenceAndFinal)
437 {
438 reference_coordinatesOfPaddings.push_back(dot(reference_tcell, reference_atom_coords));
439 reference_coordinatesOfPaddings.push_back(dot(reference_tcell + 3, reference_atom_coords));
440 reference_coordinatesOfPaddings.push_back(dot(reference_tcell + 6, reference_atom_coords));
441 }
442
443 // padding speciesCode code and image
444 speciesCodeOfPaddings.push_back(speciesCode[at]);
445 masterOfPaddings.push_back(at);
446 }
447 }
448 }
449 }
450 delete[] frac_coords;
451 if(reference_frac_coords!= nullptr) delete[] reference_frac_coords;
452
453 numberOfPaddings = masterOfPaddings.size();
454
455 return 0;
456}
457
void transpose(double const *mat, double *const trans)
Definition helper.hpp:59
void coords_to_index(double const *x, int const *size, double const *max, double const *min, int *const index)
Definition helper.hpp:92
void cross(double const *a, double const *b, double *const axb)
Definition helper.hpp:34
double dot(double const *a, double const *b)
Definition helper.hpp:27
double norm(double const *a)
Definition helper.hpp:20
int inverse(double const *mat, double *const inv)
Definition helper.hpp:69
void nbl_initialize(NeighList **const nl)
#define TOL
int nbl_build(NeighList *const nl, int const numberOfParticles, double const *coordinates, double const influenceDistance, int const numberOfCutoffs, double const *cutoffs, int const *needNeighbors)
void nbl_clean(NeighList **const nl)
void nbl_allocate_memory(NeighList *const nl, int const numberOfCutoffs, int const numberOfParticles)
#define DIM
int nbl_get_neigh(void const *const dataObject, int const numberOfCutoffs, double const *const cutoffs, int const neighborListIndex, int const particleNumber, int *const numberOfNeighbors, int const **const neighborsOfParticle)
int nbl_create_paddings(int const numberOfParticles, double const cutoff, double const *reference_cell, double const *cell, int const *PBC, double const *reference_coordinates, double const *coordinates, const std::vector< std::string > &speciesCode, int &numberOfPaddings, std::vector< double > &reference_coordinatesOfPaddings, std::vector< double > &coordinatesOfPaddings, std::vector< std::string > &speciesCodeOfPaddings, std::vector< int > &masterOfPaddings, int referenceAndFinal)
void nbl_clean_content(NeighList *const nl)
NeighListOne * lists
int numberOfNeighborLists
#define MY_WARNING(message)
Definition typedef.h:24