source: src/linkedcell.cpp@ 5f612ee

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 5f612ee was a67d19, checked in by Frederik Heber <heber@…>, 15 years ago

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

Signed-off-by: Frederik Heber <heber@…>

  • Property mode set to 100644
File size: 14.0 KB
Line 
1/** \file linkedcell.cpp
2 *
3 * Function implementations for the class LinkedCell.
4 *
5 */
6
7
8#include "atom.hpp"
9#include "helpers.hpp"
10#include "linkedcell.hpp"
11#include "log.hpp"
12#include "molecule.hpp"
13#include "tesselation.hpp"
14#include "vector.hpp"
15
16// ========================================================= class LinkedCell ===========================================
17
18
19/** Constructor for class LinkedCell.
20 */
21LinkedCell::LinkedCell()
22{
23 LC = NULL;
24 for(int i=0;i<NDIM;i++)
25 N[i] = 0;
26 index = -1;
27 RADIUS = 0.;
28 max.Zero();
29 min.Zero();
30};
31
32/** Puts all atoms in \a *mol into a linked cell list with cell's lengths of \a RADIUS
33 * \param *set LCNodeSet class with all LCNode's
34 * \param RADIUS edge length of cells
35 */
36LinkedCell::LinkedCell(const PointCloud * const set, const double radius)
37{
38 TesselPoint *Walker = NULL;
39
40 RADIUS = radius;
41 LC = NULL;
42 for(int i=0;i<NDIM;i++)
43 N[i] = 0;
44 index = -1;
45 max.Zero();
46 min.Zero();
47 DoLog(1) && (Log() << Verbose(1) << "Begin of LinkedCell" << endl);
48 if ((set == NULL) || (set->IsEmpty())) {
49 DoeLog(1) && (eLog()<< Verbose(1) << "set is NULL or contains no linked cell nodes!" << endl);
50 return;
51 }
52 // 1. find max and min per axis of atoms
53 set->GoToFirst();
54 Walker = set->GetPoint();
55 for (int i=0;i<NDIM;i++) {
56 max.x[i] = Walker->node->x[i];
57 min.x[i] = Walker->node->x[i];
58 }
59 set->GoToFirst();
60 while (!set->IsEnd()) {
61 Walker = set->GetPoint();
62 for (int i=0;i<NDIM;i++) {
63 if (max.x[i] < Walker->node->x[i])
64 max.x[i] = Walker->node->x[i];
65 if (min.x[i] > Walker->node->x[i])
66 min.x[i] = Walker->node->x[i];
67 }
68 set->GoToNext();
69 }
70 DoLog(2) && (Log() << Verbose(2) << "Bounding box is " << min << " and " << max << "." << endl);
71
72 // 2. find then number of cells per axis
73 for (int i=0;i<NDIM;i++) {
74 N[i] = (int)floor((max.x[i] - min.x[i])/RADIUS)+1;
75 }
76 DoLog(2) && (Log() << Verbose(2) << "Number of cells per axis are " << N[0] << ", " << N[1] << " and " << N[2] << "." << endl);
77
78 // 3. allocate the lists
79 DoLog(2) && (Log() << Verbose(2) << "Allocating cells ... ");
80 if (LC != NULL) {
81 DoeLog(1) && (eLog()<< Verbose(1) << "Linked Cell list is already allocated, I do nothing." << endl);
82 return;
83 }
84 LC = new LinkedNodes[N[0]*N[1]*N[2]];
85 for (index=0;index<N[0]*N[1]*N[2];index++) {
86 LC [index].clear();
87 }
88 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
89
90 // 4. put each atom into its respective cell
91 DoLog(2) && (Log() << Verbose(2) << "Filling cells ... ");
92 set->GoToFirst();
93 while (!set->IsEnd()) {
94 Walker = set->GetPoint();
95 for (int i=0;i<NDIM;i++) {
96 n[i] = (int)floor((Walker->node->x[i] - min.x[i])/RADIUS);
97 }
98 index = n[0] * N[1] * N[2] + n[1] * N[2] + n[2];
99 LC[index].push_back(Walker);
100 //Log() << Verbose(2) << *Walker << " goes into cell " << n[0] << ", " << n[1] << ", " << n[2] << " with No. " << index << "." << endl;
101 set->GoToNext();
102 }
103 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
104 DoLog(1) && (Log() << Verbose(1) << "End of LinkedCell" << endl);
105};
106
107
108/** Puts all atoms in \a *mol into a linked cell list with cell's lengths of \a RADIUS
109 * \param *set LCNodeSet class with all LCNode's
110 * \param RADIUS edge length of cells
111 */
112LinkedCell::LinkedCell(LinkedNodes *set, const double radius)
113{
114 class TesselPoint *Walker = NULL;
115 RADIUS = radius;
116 LC = NULL;
117 for(int i=0;i<NDIM;i++)
118 N[i] = 0;
119 index = -1;
120 max.Zero();
121 min.Zero();
122 DoLog(1) && (Log() << Verbose(1) << "Begin of LinkedCell" << endl);
123 if (set->empty()) {
124 DoeLog(1) && (eLog()<< Verbose(1) << "set contains no linked cell nodes!" << endl);
125 return;
126 }
127 // 1. find max and min per axis of atoms
128 LinkedNodes::iterator Runner = set->begin();
129 for (int i=0;i<NDIM;i++) {
130 max.x[i] = (*Runner)->node->x[i];
131 min.x[i] = (*Runner)->node->x[i];
132 }
133 for (LinkedNodes::iterator Runner = set->begin(); Runner != set->end(); Runner++) {
134 Walker = *Runner;
135 for (int i=0;i<NDIM;i++) {
136 if (max.x[i] < Walker->node->x[i])
137 max.x[i] = Walker->node->x[i];
138 if (min.x[i] > Walker->node->x[i])
139 min.x[i] = Walker->node->x[i];
140 }
141 }
142 DoLog(2) && (Log() << Verbose(2) << "Bounding box is " << min << " and " << max << "." << endl);
143
144 // 2. find then number of cells per axis
145 for (int i=0;i<NDIM;i++) {
146 N[i] = (int)floor((max.x[i] - min.x[i])/RADIUS)+1;
147 }
148 DoLog(2) && (Log() << Verbose(2) << "Number of cells per axis are " << N[0] << ", " << N[1] << " and " << N[2] << "." << endl);
149
150 // 3. allocate the lists
151 DoLog(2) && (Log() << Verbose(2) << "Allocating cells ... ");
152 if (LC != NULL) {
153 DoeLog(1) && (eLog()<< Verbose(1) << "Linked Cell list is already allocated, I do nothing." << endl);
154 return;
155 }
156 LC = new LinkedNodes[N[0]*N[1]*N[2]];
157 for (index=0;index<N[0]*N[1]*N[2];index++) {
158 LC [index].clear();
159 }
160 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
161
162 // 4. put each atom into its respective cell
163 DoLog(2) && (Log() << Verbose(2) << "Filling cells ... ");
164 for (LinkedNodes::iterator Runner = set->begin(); Runner != set->end(); Runner++) {
165 Walker = *Runner;
166 for (int i=0;i<NDIM;i++) {
167 n[i] = (int)floor((Walker->node->x[i] - min.x[i])/RADIUS);
168 }
169 index = n[0] * N[1] * N[2] + n[1] * N[2] + n[2];
170 LC[index].push_back(Walker);
171 //Log() << Verbose(2) << *Walker << " goes into cell " << n[0] << ", " << n[1] << ", " << n[2] << " with No. " << index << "." << endl;
172 }
173 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
174 DoLog(1) && (Log() << Verbose(1) << "End of LinkedCell" << endl);
175};
176
177/** Destructor for class LinkedCell.
178 */
179LinkedCell::~LinkedCell()
180{
181 if (LC != NULL)
182 for (index=0;index<N[0]*N[1]*N[2];index++)
183 LC[index].clear();
184 delete[](LC);
185 for(int i=0;i<NDIM;i++)
186 N[i] = 0;
187 index = -1;
188 max.Zero();
189 min.Zero();
190};
191
192/** Checks whether LinkedCell::n[] is each within [0,N[]].
193 * \return if all in intervals - true, else -false
194 */
195bool LinkedCell::CheckBounds() const
196{
197 bool status = true;
198 for(int i=0;i<NDIM;i++)
199 status = status && ((n[i] >=0) && (n[i] < N[i]));
200 if (!status)
201 DoeLog(1) && (eLog()<< Verbose(1) << "indices are out of bounds!" << endl);
202 return status;
203};
204
205/** Checks whether LinkedCell::n[] plus relative offset is each within [0,N[]].
206 * Note that for this check we don't admonish if out of bounds.
207 * \param relative[NDIM] relative offset to current cell
208 * \return if all in intervals - true, else -false
209 */
210bool LinkedCell::CheckBounds(const int relative[NDIM]) const
211{
212 bool status = true;
213 for(int i=0;i<NDIM;i++)
214 status = status && ((n[i]+relative[i] >=0) && (n[i]+relative[i] < N[i]));
215 return status;
216};
217
218
219/** Returns a pointer to the current cell.
220 * \return LinkedAtoms pointer to current cell, NULL if LinkedCell::n[] are out of bounds.
221 */
222const LinkedCell::LinkedNodes* LinkedCell::GetCurrentCell() const
223{
224 if (CheckBounds()) {
225 index = n[0] * N[1] * N[2] + n[1] * N[2] + n[2];
226 return (&(LC[index]));
227 } else {
228 return NULL;
229 }
230};
231
232/** Returns a pointer to the current cell.
233 * \param relative[NDIM] offset for each axis with respect to the current cell LinkedCell::n[NDIM]
234 * \return LinkedAtoms pointer to current cell, NULL if LinkedCell::n[]+relative[] are out of bounds.
235 */
236const LinkedCell::LinkedNodes* LinkedCell::GetRelativeToCurrentCell(const int relative[NDIM]) const
237{
238 if (CheckBounds(relative)) {
239 index = (n[0]+relative[0]) * N[1] * N[2] + (n[1]+relative[1]) * N[2] + (n[2]+relative[2]);
240 return (&(LC[index]));
241 } else {
242 return NULL;
243 }
244};
245
246/** Set the index to the cell containing a given Vector *x.
247 * \param *x Vector with coordinates
248 * \return Vector is inside bounding box - true, else - false
249 */
250bool LinkedCell::SetIndexToVector(const Vector * const x) const
251{
252 for (int i=0;i<NDIM;i++)
253 n[i] = (int)floor((x->x[i] - min.x[i])/RADIUS);
254
255 return CheckBounds();
256};
257
258/** Calculates the index for a given LCNode *Walker.
259 * \param *Walker LCNode to set index tos
260 * \return if the atom is also found in this cell - true, else - false
261 */
262bool LinkedCell::SetIndexToNode(const TesselPoint * const Walker) const
263{
264 bool status = false;
265 for (int i=0;i<NDIM;i++) {
266 n[i] = (int)floor((Walker->node->x[i] - min.x[i])/RADIUS);
267 }
268 index = n[0] * N[1] * N[2] + n[1] * N[2] + n[2];
269 if (CheckBounds()) {
270 for (LinkedNodes::iterator Runner = LC[index].begin(); Runner != LC[index].end(); Runner++)
271 status = status || ((*Runner) == Walker);
272 return status;
273 } else {
274 DoeLog(1) && (eLog()<< Verbose(1) << "Node at " << *Walker << " is out of bounds." << endl);
275 return false;
276 }
277};
278
279/** Calculates the interval bounds of the linked cell grid.
280 * \param *lower lower bounds
281 * \param *upper upper bounds
282 * \param step how deep to check the neighbouring cells (i.e. number of layers to check)
283 */
284void LinkedCell::GetNeighbourBounds(int lower[NDIM], int upper[NDIM], int step) const
285{
286 for (int i=0;i<NDIM;i++) {
287 lower[i] = n[i];
288 for (int s=step; s>0;--s)
289 if ((n[i]-s) >= 0) {
290 lower[i] = n[i]-s;
291 break;
292 }
293 upper[i] = n[i];
294 for (int s=step; s>0;--s)
295 if ((n[i]+s) < N[i]) {
296 upper[i] = n[i]+s;
297 break;
298 }
299 //Log() << Verbose(0) << "axis " << i << " has bounds [" << lower[i] << "," << upper[i] << "]" << endl;
300 }
301};
302
303/** Returns a list with all neighbours from the current LinkedCell::index.
304 * \param distance (if no distance, then adjacent cells are taken)
305 * \return list of tesselpoints
306 */
307LinkedCell::LinkedNodes* LinkedCell::GetallNeighbours(const double distance) const
308{
309 int Nlower[NDIM], Nupper[NDIM];
310 TesselPoint *Walker = NULL;
311 LinkedNodes *TesselList = new LinkedNodes;
312
313 // then go through the current and all neighbouring cells and check the contained points for possible candidates
314 const int step = (distance == 0) ? 1 : (int)floor(distance/RADIUS + 1.);
315 GetNeighbourBounds(Nlower, Nupper, step);
316
317 //Log() << Verbose(0) << endl;
318 for (n[0] = Nlower[0]; n[0] <= Nupper[0]; n[0]++)
319 for (n[1] = Nlower[1]; n[1] <= Nupper[1]; n[1]++)
320 for (n[2] = Nlower[2]; n[2] <= Nupper[2]; n[2]++) {
321 const LinkedNodes *List = GetCurrentCell();
322 //Log() << Verbose(1) << "Current cell is " << n[0] << ", " << n[1] << ", " << n[2] << " with No. " << index << "." << endl;
323 if (List != NULL) {
324 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
325 Walker = *Runner;
326 TesselList->push_back(Walker);
327 }
328 }
329 }
330 return TesselList;
331};
332
333/** Set the index to the cell containing a given Vector *x, which is not inside the LinkedCell's domain
334 * Note that as we have to check distance from every corner of the closest cell, this function is faw more
335 * expensive and if Vector is known to be inside LinkedCell's domain, then SetIndexToVector() should be used.
336 * \param *x Vector with coordinates
337 * \return minimum squared distance of cell to given vector (if inside of domain, distance is 0)
338 */
339double LinkedCell::SetClosestIndexToOutsideVector(const Vector * const x) const
340{
341 for (int i=0;i<NDIM;i++) {
342 n[i] = (int)floor((x->x[i] - min.x[i])/RADIUS);
343 if (n[i] < 0)
344 n[i] = 0;
345 if (n[i] >= N[i])
346 n[i] = N[i]-1;
347 }
348
349 // calculate distance of cell to vector
350 double distanceSquared = 0.;
351 bool outside = true; // flag whether x is found in- or outside of LinkedCell's domain/closest cell
352 Vector corner; // current corner of closest cell
353 Vector tester; // Vector pointing from corner to center of closest cell
354 Vector Distance; // Vector from corner of closest cell to x
355
356 Vector center; // center of the closest cell
357 for (int i=0;i<NDIM;i++)
358 center.x[i] = min.x[i]+((double)n[i]+.5)*RADIUS;
359
360 int c[NDIM];
361 for (c[0]=0;c[0]<=1;c[0]++)
362 for (c[1]=0; c[1]<=1;c[1]++)
363 for (c[2]=0; c[2]<=1;c[2]++) {
364 // set up corner
365 for (int i=0;i<NDIM;i++)
366 corner.x[i] = min.x[i]+RADIUS*((double)n[i]+c[i]);
367 // set up distance vector
368 Distance.CopyVector(x);
369 Distance.SubtractVector(&corner);
370 const double dist = Distance.NormSquared();
371 // check whether distance is smaller
372 if (dist< distanceSquared)
373 distanceSquared = dist;
374 // check whether distance vector goes inside or outside
375 tester.CopyVector(&center);
376 tester.SubtractVector(&corner);
377 if (tester.ScalarProduct(&Distance) < 0)
378 outside = false;
379 }
380 return (outside ? distanceSquared : 0.);
381};
382
383/** Returns a list of all TesselPoint with distance less than \a radius to \a *Center.
384 * \param radius radius of sphere
385 * \param *center center of sphere
386 * \return list of all points inside sphere
387 */
388LinkedCell::LinkedNodes* LinkedCell::GetPointsInsideSphere(const double radius, const Vector * const center) const
389{
390 const double radiusSquared = radius*radius;
391 TesselPoint *Walker = NULL;
392 LinkedNodes *TesselList = new LinkedNodes;
393 LinkedNodes *NeighbourList = NULL;
394
395 // set index of LC to center of sphere
396 const double dist = SetClosestIndexToOutsideVector(center);
397 if (dist > 2.*radius) {
398 DoeLog(1) && (eLog()<< Verbose(1) << "Vector " << *center << " is too far away from any atom in LinkedCell's bounding box." << endl);
399 return TesselList;
400 } else
401 DoLog(1) && (Log() << Verbose(1) << "Distance of closest cell to center of sphere with radius " << radius << " is " << dist << "." << endl);
402
403 // gather all neighbours first, then look who fulfills distance criteria
404 NeighbourList = GetallNeighbours(2.*radius-dist);
405 //Log() << Verbose(1) << "I found " << NeighbourList->size() << " neighbours to check." << endl;
406 if (NeighbourList != NULL) {
407 for (LinkedNodes::const_iterator Runner = NeighbourList->begin(); Runner != NeighbourList->end(); Runner++) {
408 Walker = *Runner;
409 //Log() << Verbose(1) << "Current neighbour is at " << *Walker->node << "." << endl;
410 if ((center->DistanceSquared(Walker->node) - radiusSquared) < MYEPSILON) {
411 TesselList->push_back(Walker);
412 }
413 }
414 delete(NeighbourList);
415 } else
416 DoeLog(2) && (eLog()<< Verbose(2) << "Around vector " << *center << " there are no atoms." << endl);
417 return TesselList;
418};
Note: See TracBrowser for help on using the repository browser.