libatomprobe
Library for Atom Probe Tomography (APT) computation
axialdf.cpp
Go to the documentation of this file.
1 /* axialdf.cpp: Axial distribution functions
2  * Copyright (C) 2020 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
19 
20 #include <cstring>
21 
22 #ifdef _OPENMP
23  #include <omp.h>
24 #endif
25 
26 #ifdef DEBUG
27 #include <limits>
28 #endif
29 
31 
32 namespace AtomProbe
33 {
34 
35 using std::vector;
36 
37 unsigned int generate1DAxialDistHist(const vector<Point3D> &pointList, K3DTreeExact &tree,
38  const Point3D &axisDir, float distMax, vector<unsigned int> &histogram)
39 {
40  ASSERT(fabs(axisDir.sqrMag() -1.0f) < sqrt(std::numeric_limits<float>::epsilon()));
41  ASSERT(!histogram.empty());
42 
43  std::fill(histogram.begin(),histogram.end(),0);
44 
45  if(pointList.empty())
46  return 0;
47 
48  BoundCube cube;
49  cube.setBounds(pointList);
50 
51  float maxSqrDist = distMax*distMax;
52 
53 #ifdef _OPENMP
54  vector<vector<unsigned int> > threadHistograms;
55  threadHistograms.resize(omp_get_num_threads());
56  for(unsigned int ui=0;ui<threadHistograms.size();ui++)
57  {
58  threadHistograms[ui].resize(histogram.size(),0);
59  }
60 #endif
61 
62 
63 
64 
65  //Main r-max searching routine
66 #pragma omp parallel for
67  for(unsigned int ui=0; ui<pointList.size(); ui++)
68  {
69  Point3D sourcePoint;
70  //Go through each point and grab all points within the maximum distance
71  //that we need
72 
73  vector<size_t> inSphereIdx;
74 
75  sourcePoint=pointList[ui];
76 
77  //Grab the nearest point. Will tag on completion
78  tree.ptsInSphere(sourcePoint, distMax, inSphereIdx);
79 
80  //Loop through the points within the search radius and
81  // update the tag radius
82  for(size_t uj=0;uj<inSphereIdx.size();uj++)
83  {
84  float sqrDist;
85  const Point3D &nearPt=tree.getPtRef(inSphereIdx[uj]);
86 
87  //Calculate the sq of the distance to the point
88  sqrDist = nearPt.sqrDist(sourcePoint);
89 
90  //if sqrDist is = maxSqrdist then this will cause
91  //the histogram indexing to trash alternate memory
92  //- this is bad - prevent this please.
93  // also skip self matching (zero distance)
94  if(sqrDist == 0.0f || sqrDist >= maxSqrDist)
95  continue;
96 
97  //Compute the projection of
98  // the point onto the axis of the
99  // primary analysis direction
100  float distance;
101  distance=(nearPt-sourcePoint).dotProd(axisDir);
102 
103  //update the histogram with the new position.
104  // centre of the distribution function lies at the analysis point,
105  // and can be either negative or positive.
106  // Shift the zero to the center of the histogram
107  int offset=(int)(((0.5f*distance)/distMax+0.5f)*(float)histogram.size());
108  if(offset < (int)histogram.size() && offset >=0)
109  {
110 #ifdef _OPENMP
111  threadHistograms[omp_get_thread_num()][offset]++;
112 #else
113  histogram[offset]++;
114 #endif
115  }
116 
117  }
118 
119  }
120 #ifdef _OPENMP
121  for(unsigned int ui=0;ui<threadHistograms.size();ui++)
122  {
123  for(unsigned int uj=0;uj<histogram.size();uj++)
124  histogram[uj]+=threadHistograms[ui][uj];
125  }
126 #endif
127 
128  return 0;
129 }
130 
131 unsigned int generate1DAxialDistHistSweep(const vector<Point3D> &pointList, K3DTreeExact &tree,
132  float distMax, float dTheta, float dPhi, ProgressBar &p,
133  vector<vector<vector<unsigned int> > > &histogram)
134 {
135  ASSERT(!histogram.empty());
136  ASSERT(dTheta > 0.0f);
137  ASSERT(dPhi > 0.0f);
138 
139  if(pointList.empty())
140  return 0;
141 
142  BoundCube cube;
143  cube.setBounds(pointList);
144 
145  float maxSqrDist = distMax*distMax;
146 
147  const size_t NUM_THETA=histogram.size();
148  const size_t NUM_PHI=histogram[0].size();
149  const size_t DIST_BINS=histogram[0][0].size();
150 
151 
152  unsigned int *hist = new unsigned int[NUM_THETA*NUM_PHI*DIST_BINS];
153  memset(hist,0,NUM_THETA*NUM_PHI*DIST_BINS*sizeof(unsigned int));
154 
155  Point3D **axisDir= new Point3D*[NUM_THETA];
156  for(size_t ui=0;ui<NUM_THETA;ui++)
157  axisDir[ui] = new Point3D[NUM_PHI];
158 
159  //Construct a ball of unit vectors, facing outwards
160  for(size_t ui=0; ui<NUM_THETA; ui++)
161  {
162  for(size_t uj=0; uj<NUM_PHI; uj++)
163  {
164  float tmpPhi,tmpTheta;
165  tmpTheta= dTheta*ui;
166  tmpPhi = dPhi*uj;
167 
168  //theta is the angle from +z, to prevent duplication of the vector
169  // and its negative, we restrict it to 0->90 degrees from +z
170  ASSERT(tmpTheta>=0.0f && tmpTheta<=M_PI/2);
171  //This should like somewhere between 0 and 360 degrees
172  ASSERT(tmpPhi>=0&& tmpPhi<=2.1f*M_PI);
173  axisDir[ui][uj].setISOSpherical(1.0,tmpTheta,tmpPhi);
174 
175  ASSERT(fabs(acos(axisDir[ui][uj][2]) - tmpTheta) < 0.001);
176 
177  }
178  }
179 
180 
181  //Main r-max searching routine
182 
183 //construct worker threads
184 #pragma omp parallel for schedule(dynamic)
185  for(unsigned int uSrcPt=0; uSrcPt<pointList.size(); uSrcPt++)
186  {
187  Point3D sourcePoint;
188  sourcePoint=pointList[uSrcPt];
189 
190  //Go through each point and grab up to the maximum distance
191  //that we need
192  vector<size_t> inSphereIdx;
193  tree.ptsInSphere(sourcePoint,distMax, inSphereIdx);
194 
195 
196 
197  //Loop through the points within the search radius and
198  // update the tag radius
199  for(size_t uPt=0; uPt<inSphereIdx.size(); uPt++)
200  {
201  float sqrDist;
202  ASSERT(inSphereIdx[uPt] < tree.size());
203  const Point3D &nearPt=tree.getPtRef(inSphereIdx[uPt]);
204 
205  //Calculate the sq of the distance to the point
206  sqrDist = nearPt.sqrDist(sourcePoint);
207 
208  if(sqrDist == 0.0f)
209  continue;
210 
211  //if sqrDist is = maxSqrdist then this will cause
212  //the histogram indexing to trash alternate memory
213  //- this is bad - prevent this please.
214  if(sqrDist < maxSqrDist)
215  {
216  Point3D deltaPt;
217  deltaPt=nearPt-sourcePoint;
218  //Compute the SDM fit for all angular space
219  for(size_t ui=0; ui<NUM_THETA; ui++)
220  {
221  for(size_t uj=0; uj<NUM_PHI; uj++)
222  {
223 
224  //Compute the projection of
225  // the point onto the axis of the
226  // primary analysis direction
227  float distance;
228  distance=deltaPt.dotProd(axisDir[ui][uj]);
229  int offset;
230 
231  offset=(int)(((0.5f*distance)/distMax+0.5f)*(float)DIST_BINS);
232  if(offset >=0 && offset < (int)DIST_BINS)
233  {
234  #pragma omp atomic
235  hist[ui*DIST_BINS*NUM_PHI + uj*DIST_BINS+ offset]++;
236  }
237  }
238  }
239  }
240 
241  }
242 #ifdef _OPENMP
243  if(!omp_get_thread_num())
244 #endif
245  p.update((float)uSrcPt/(float)pointList.size()*100.0f);
246  }
247 
248  for(unsigned int ui=0;ui<histogram.size();ui++)
249  {
250  for(unsigned int uj=0;uj<histogram[ui].size();uj++)
251  {
252  for(unsigned int uk=0;uk<histogram[ui][uj].size();uk++)
253  {
254  histogram[ui][uj][uk]=hist[ui*DIST_BINS*NUM_PHI + uj*DIST_BINS+ uk];
255  }
256  }
257  }
258 
259 
260  delete[] hist;
261 
262  for(size_t ui=0;ui<NUM_THETA;ui++)
263  delete[] axisDir[ui];
264 
265  delete[] axisDir;
266  return 0;
267 }
268 }
float sqrDist(const Point3D &pt) const
Returns the square of distance to another Point3D.
Definition: point3D.cpp:272
unsigned int generate1DAxialDistHistSweep(const std::vector< Point3D > &pointList, K3DTreeExact &tree, float distMax, float dTheta, float dPhi, AtomProbe::ProgressBar &prog, std::vector< std::vector< std::vector< unsigned int > > > &histogram)
Generate a series of 1D distribution functions, one per pixel in a 2D grid of spherical coordinate di...
Definition: axialdf.cpp:131
3D specific KD tree
Definition: K3DTree-exact.h:54
float sqrMag() const
Returns magnitude^2, taking this as a position vector.
Definition: point3D.cpp:332
A 3D point data class storage.
Definition: point3D.h:39
void setISOSpherical(float radius, float theta, float phi)
Assign the vector using spherical coordinates.
Definition: point3D.cpp:425
#define M_PI
Definition: kd-example.cpp:34
unsigned int generate1DAxialDistHist(const std::vector< Point3D > &pointList, K3DTreeExact &tree, const Point3D &axisDir, float distMax, std::vector< unsigned int > &histogram)
Generate a 1D axial distribution function,.
Definition: axialdf.cpp:37
Helper class to define a bounding cube.
Definition: boundcube.h:29
#define ASSERT(f)
float dotProd(const Point3D &pt) const
Calculate the dot product of this and another point.
Definition: point3D.cpp:279
void update(unsigned int newProgress)
Draw the progress bar as needed, using the given progress value [0,100].
Definition: progress.cpp:58
const Point3D & getPtRef(size_t index) const
void ptsInSphere(const Point3D &origin, float radius, std::vector< size_t > &pts) const
void setBounds(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax)
Set the bounds by passing in minima and maxima of each dimension.
Definition: boundcube.cpp:49