Skip to content

Commit 6e24839

Browse files
committed
Some code reorg to help profiling
(#722)
1 parent e297238 commit 6e24839

File tree

3 files changed

+143
-110
lines changed

3 files changed

+143
-110
lines changed

include/galsim/Silicon.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ namespace galsim
3737
class Silicon
3838
{
3939
public:
40-
Silicon(int NumVertices, int NumElec, int Nx, int Ny, int QDist, int Nrecalc,
41-
double DiffStep, double PixelSize, double* vertex_data);
40+
Silicon(int numVertices, int numElec, int nx, int ny, int qDist, int nrecalc,
41+
double diffStep, double pixelSize, double* vertex_data);
4242

4343
template <typename T>
4444
bool insidePixel(int ix, int iy, double x, double y, double zconv,

src/Polygon.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ namespace galsim {
6262
// Calculate angle between centroid and point
6363
std::vector<double> angle(npoints);
6464
for (int i=0; i<npoints; i++) {
65-
angle[i] = atan2(_points[i].y - cy, _points[i].x - cx);
65+
angle[i] = std::atan2(_points[i].y - cy, _points[i].x - cx);
6666
}
6767

6868
//sort _points in place using the angles

src/Silicon.cpp

Lines changed: 140 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -143,23 +143,23 @@ namespace galsim {
143143
}
144144

145145
#if 0
146-
Got a start on implementing the absorption length lookup,
147-
but couldn't get the python - C++ wrapper working, so I went
148-
back to the analytic function - Craig Lage 17-Feb-17
149-
double Silicon::AbsLength(double lambda)
150-
{
151-
// Looks up the absorption length and returns
152-
// an interpolated value
153-
int nminus;
154-
double aminus, aplus, dlambda;
155-
dlambda = _abs_data[2] - _abs_data[0];
156-
// index of
157-
nminus = (int) ((lambda - _abs_data[0]) / dlambda) * 2;
158-
if (nminus < 0) return _abs_data[1];
159-
else if (nminus > _nabs - 4) return _abs_data[_nabs - 1];
160-
else return _abs_data[nminus+1] +
161-
(lambda - _abs_data[nminus]) * (_abs_data[nminus+3] - _abs_data[nminus+1]);
162-
}
146+
// Got a start on implementing the absorption length lookup,
147+
// but couldn't get the python - C++ wrapper working, so I went
148+
// back to the analytic function - Craig Lage 17-Feb-17
149+
double Silicon::AbsLength(double lambda)
150+
{
151+
// Looks up the absorption length and returns
152+
// an interpolated value
153+
int nminus;
154+
double aminus, aplus, dlambda;
155+
dlambda = _abs_data[2] - _abs_data[0];
156+
// index of
157+
nminus = (int) ((lambda - _abs_data[0]) / dlambda) * 2;
158+
if (nminus < 0) return _abs_data[1];
159+
else if (nminus > _nabs - 4) return _abs_data[_nabs - 1];
160+
else return _abs_data[nminus+1] +
161+
(lambda - _abs_data[nminus]) * (_abs_data[nminus+3] - _abs_data[nminus+1]);
162+
}
163163
#endif
164164

165165
template <typename T>
@@ -236,7 +236,7 @@ namespace galsim {
236236
if (!target.getBounds().includes(Position<int>(ix,iy))) return false;
237237

238238
const double zfit = 12.0;
239-
const double zfactor = tanh(zconv / zfit);
239+
const double zfactor = std::tanh(zconv / zfit);
240240
const int minx = target.getXMin();
241241
const int miny = target.getYMin();
242242
const int maxx = target.getXMax();
@@ -251,23 +251,94 @@ namespace galsim {
251251
return testpoly.contains(Point(x,y));
252252
}
253253

254-
template <typename T>
255-
double Silicon::accumulate(const PhotonArray& photons, UniformDeviate ud,
256-
ImageView<T> target)
254+
// Helper function to calculate how far down into the silicon the photon converts into
255+
// an electron.
256+
void calculateConversionDepth(const PhotonArray& photons, std::vector<double>& depth,
257+
UniformDeviate ud)
257258
{
258259
const double log10_over_250 = std::log(10.) / 250.;
259260

260-
// Create and read in pixel distortions
261-
const int xoff[9] = {0,1,1,0,-1,-1,-1,0,1}; // Displacements to neighboring pixels
262-
const int yoff[9] = {0,0,1,1,1,0,-1,-1,-1}; // Displacements to neighboring pixels
263-
int n=0;
261+
const int nphotons = photons.size();
262+
for (int i=0; i<nphotons; ++i) {
263+
// Determine the distance the photon travels into the silicon
264+
double si_length;
265+
if (photons.hasAllocatedWavelengths()) {
266+
double lambda = photons.getWavelength(i); // in nm
267+
// The below is an approximation. ToDo: replace with lookup table
268+
//double abs_length = pow(10.0,((lambda - 500.0) / 250.0)); // in microns
269+
double abs_length = std::exp((lambda - 500.0) * log10_over_250); // in microns
270+
//double abs_length = AbsLength(lambda); // in microns
271+
si_length = -abs_length * log(1.0 - ud()); // in microns
272+
#ifdef DEBUGLOGGING
273+
if (i % 1000 == 0) {
274+
dbg<<"lambda = "<<lambda<<std::endl;
275+
dbg<<"si_length = "<<si_length<<std::endl;
276+
}
277+
#endif
278+
} else {
279+
// If no wavelength info, assume conversion takes place near the top.
280+
si_length = 5.0;
281+
}
264282

265-
// PhotonArray
266-
GaussianDeviate gd(ud,0,1); // Random variable from Standard Normal dist.
267-
int zerocount = 0, nearestcount = 0, othercount = 0, misscount = 0;
283+
// Next we partition the si_length into x,y,z. Assuming dz is positive downward
284+
if (photons.hasAllocatedAngles()) {
285+
double dxdz = photons.getDXDZ(i);
286+
double dydz = photons.getDYDZ(i);
287+
double dz = si_length / std::sqrt(1.0 + dxdz*dxdz + dydz*dydz); // in microns
288+
depth[i] = std::min(95.0, dz); // max 95 microns
289+
#ifdef DEBUGLOGGING
290+
if (i % 1000 == 0) {
291+
dbg<<"dxdz = "<<dxdz<<std::endl;
292+
dbg<<"dydz = "<<dydz<<std::endl;
293+
dbg<<"dz = "<<dz<<std::endl;
294+
}
295+
#endif
296+
} else {
297+
depth[i] = si_length;
298+
}
299+
}
300+
}
268301

269-
Bounds<int> b = target.getBounds();
302+
static const int xoff[9] = {0,1,1,0,-1,-1,-1,0,1}; // Displacements to neighboring pixels
303+
static const int yoff[9] = {0,0,1,1,1,0,-1,-1,-1}; // Displacements to neighboring pixels
270304

305+
// Break this bit out mostly to make it easier when profiling to see how much it would help
306+
// to further optimize this part of the code.
307+
template <typename T>
308+
bool searchNeighbors(const Silicon& silicon, int& ix, int& iy, double x, double y, double zconv,
309+
ImageView<T> target, int& step)
310+
{
311+
// The following code finds which pixel we are in given
312+
// pixel distortion due to the brighter-fatter effect
313+
// The following are set up to start the search in the undistorted pixel, then
314+
// search in the nearest neighbor first if it's not in the undistorted pixel.
315+
if ((x > y) && (x > 1.0 - y)) step = 1;
316+
else if ((x < y) && (x < 1.0 - y)) step = 7;
317+
else if ((x < y) && (x > 1.0 - y)) step = 3;
318+
else step = 5;
319+
int n=step;
320+
for (int m=1; m<9; m++) {
321+
int ix_off = ix + xoff[n];
322+
int iy_off = iy + yoff[n];
323+
double x_off = x - xoff[n];
324+
double y_off = y - yoff[n];
325+
if (silicon.insidePixel(ix_off, iy_off, x_off, y_off, zconv, target)) {
326+
xdbg<<"Found in pixel "<<n<<", ix = "<<ix<<", iy = "<<iy
327+
<<", x="<<x<<", y = "<<y<<", target(ix,iy)="<<target(ix,iy)<<std::endl;
328+
ix = ix_off;
329+
iy = iy_off;
330+
return true;
331+
}
332+
n = ((n-1) + step) % 8 + 1;
333+
// This is intended to start with the nearest neighbor, then cycle through others.
334+
}
335+
return false;
336+
}
337+
338+
template <typename T>
339+
double Silicon::accumulate(const PhotonArray& photons, UniformDeviate ud, ImageView<T> target)
340+
{
341+
Bounds<int> b = target.getBounds();
271342
if (!b.isDefined())
272343
throw std::runtime_error("Attempting to PhotonArray::addTo an Image with"
273344
" undefined Bounds");
@@ -279,6 +350,9 @@ namespace galsim {
279350
dbg<<"total nphotons = "<<photons.size()<<std::endl;
280351
dbg<<"hasAllocatedWavelengths = "<<photons.hasAllocatedWavelengths()<<std::endl;
281352
dbg<<"hasAllocatedAngles = "<<photons.hasAllocatedAngles()<<std::endl;
353+
double Irr = 0.;
354+
double Irr0 = 0.;
355+
int zerocount=0, neighborcount=0, misscount=0;
282356
#endif
283357

284358
int nx = b.getXMax() - b.getXMin() + 1;
@@ -287,50 +361,30 @@ namespace galsim {
287361
buildPolylist(_imagepolys, nx, ny, _numVertices);
288362
dbg<<"Built poly list\n";
289363

290-
#ifdef DEBUGLOGGING
291-
double Irr = 0.;
292-
double Irr0 = 0.;
293-
#endif
364+
const int nphotons = photons.size();
365+
std::vector<double> depth(nphotons);
366+
calculateConversionDepth(photons, depth, ud);
367+
368+
GaussianDeviate gd(ud,0,1); // Random variable from Standard Normal dist.
369+
294370
double addedFlux = 0.;
295371
double next_recalc = _nrecalc;
296-
const int nphotons = photons.size();
297372
for (int i=0; i<nphotons; i++) {
298373
// Update shapes every _nrecalc electrons
299374
if (addedFlux > next_recalc) {
300375
updatePixelDistortions(target);
301376
next_recalc = addedFlux + _nrecalc;
302377
}
303378

304-
// First we get the location where the photon strikes the silicon:
379+
// Get the location where the photon strikes the silicon:
305380
double x0 = photons.getX(i); // in pixels
306381
double y0 = photons.getY(i); // in pixels
307-
// Next we determine the distance the photon travels into the silicon
308-
double si_length;
309-
if (photons.hasAllocatedWavelengths()) {
310-
double lambda = photons.getWavelength(i); // in nm
311-
// The below is an approximation. ToDo: replace with lookup table
312-
//double abs_length = pow(10.0,((lambda - 500.0) / 250.0)); // in microns
313-
double abs_length = std::exp((lambda - 500.0) * log10_over_250); // in microns
314-
//double abs_length = AbsLength(lambda); // in microns
315-
si_length = -abs_length * log(1.0 - ud()); // in microns
316-
#ifdef DEBUGLOGGING
317-
if (i % 1000 == 0) {
318-
dbg<<"lambda = "<<lambda<<std::endl;
319-
dbg<<"si_length = "<<si_length<<std::endl;
320-
}
321-
#endif
322-
} else {
323-
// If no wavelength info, assume conversion takes place near the top.
324-
si_length = 5.0;
325-
}
326382

327-
// Next we partition the si_length into x,y,z. Assuming dz is positive downward
328-
double zconv;
383+
double zconv; // This is the reverse of depth. zconv is how far above the substrate.
329384
if (photons.hasAllocatedAngles()) {
330385
double dxdz = photons.getDXDZ(i);
331386
double dydz = photons.getDYDZ(i);
332-
double dz = si_length / std::sqrt(1.0 + dxdz*dxdz + dydz*dydz); // in microns
333-
dz = std::min(95.0, dz); // max 95 microns
387+
double dz = depth[i];
334388
x0 += dxdz * dz / 10.0; // in pixels
335389
y0 += dydz * dz / 10.0; // in pixels
336390
zconv = 100.0 - dz; // Conversion depth in microns
@@ -342,14 +396,14 @@ namespace galsim {
342396
}
343397
#endif
344398
} else {
345-
zconv = 100.0 - si_length;
399+
zconv = 100.0 - depth[i];
346400
}
347401
if (zconv < 0.0) continue; // Throw photon away if it hits the bottom
348402
// TODO: Do something more realistic if it hits the bottom.
349403

350404
// Now we add in a displacement due to diffusion
351405
if (_diffStep != 0.) {
352-
double diffStep = fmax(0.0, _diffStep * (zconv - 10.0) / 100.0); // in microns
406+
double diffStep = std::max(0.0, _diffStep * (zconv - 10.0) / 100.0); // in microns
353407
x0 += diffStep * gd() / 10.0; // in pixels
354408
y0 += diffStep * gd() / 10.0; // in pixels
355409
}
@@ -367,65 +421,44 @@ namespace galsim {
367421
// Now we find the undistorted pixel
368422
int ix = int(floor(x0 + 0.5));
369423
int iy = int(floor(y0 + 0.5));
424+
425+
#ifdef DEBUGLOGGING
370426
int ix0 = ix;
371427
int iy0 = iy;
428+
#endif
372429

373430
double x = x0 - ix + 0.5;
374431
double y = y0 - iy + 0.5;
375432
// (ix,iy) are the undistorted pixel coordinates.
376433
// (x,y) are the coordinates within the pixel, centered at the lower left
377434

378-
// The following code finds which pixel we are in given
379-
// pixel distortion due to the brighter-fatter effect
380-
bool foundPixel = false;
381-
// The following are set up to start the search in the undistorted pixel, then
382-
// search in the nearest neighbor first if it's not in the undistorted pixel.
383-
int step;
384-
if ((x > y) && (x > 1.0 - y)) step = 1;
385-
else if ((x < y) && (x < 1.0 - y)) step = 7;
386-
else if ((x < y) && (x > 1.0 - y)) step = 3;
387-
else step = 5;
388-
int n=0;
389-
int m_found;
390-
for (int m=0; m<9; m++) {
391-
int ix_off = ix + xoff[n];
392-
int iy_off = iy + yoff[n];
393-
double x_off = x - xoff[n];
394-
double y_off = y - yoff[n];
395-
if (insidePixel(ix_off, iy_off, x_off, y_off, zconv, target)) {
396-
xdbg<<"Found in pixel "<<n<<", ix = "<<ix<<", iy = "<<iy
397-
<<", x="<<x<<", y = "<<y<<", target(ix,iy)="<<target(ix,iy)<<std::endl;
398-
if (m == 0) zerocount += 1;
399-
else if (m == 1) nearestcount += 1;
400-
else othercount +=1;
401-
ix = ix_off;
402-
iy = iy_off;
403-
m_found = m;
404-
foundPixel = true;
405-
break;
406-
}
407-
n = ((n-1)+step) % 8 + 1;
408-
// This is intended to start with the nearest neighbor, then cycle through others.
435+
// First check the obvious choice, since this will usually work.
436+
bool foundPixel = insidePixel(ix, iy, x, y, zconv, target);
437+
#ifdef DEBUGLOGGING
438+
if (foundPixel) ++zerocount;
439+
#endif
440+
441+
// Then check neighbors
442+
int step; // We might need this below, so let searchNeighbors return it.
443+
if (!foundPixel) {
444+
foundPixel = searchNeighbors(*this, ix, iy, x, y, zconv, target, step);
445+
#ifdef DEBUGLOGGING
446+
if (foundPixel) ++neighborcount;
447+
#endif
409448
}
449+
450+
// Rarely, we won't find it in the undistorted pixel or any of the neighboring pixels.
451+
// If we do arrive here due to roundoff error of the pixel boundary, put the electron
452+
// in the undistorted pixel or the nearest neighbor with equal probability.
410453
if (!foundPixel) {
411454
xdbg<<"Not found in any pixel\n";
412455
xdbg<<"ix,iy = "<<ix<<','<<iy<<" x,y = "<<x<<','<<y<<std::endl;
413-
// We should never arrive here, since this means we didn't find it in the
414-
// undistorted pixel or any of the neighboring pixels. However, sometimes (about
415-
// 0.1% of the time) we do arrive here due to roundoff error of the pixel boundary.
416-
// When this happens, I put the electron in the undistorted pixel or the nearest
417-
// neighbor with equal probability.
418-
misscount += 1;
419-
if (ud() > 0.5) {
420-
n = 0;
421-
zerocount +=1;
422-
} else {
423-
n = step;
424-
nearestcount +=1;
425-
}
456+
int n = (ud() > 0.5) ? 0 : step;
426457
ix = ix + xoff[n];
427458
iy = iy + yoff[n];
428-
foundPixel = true;
459+
#ifdef DEBUGLOGGING
460+
++misscount;
461+
#endif
429462
}
430463
#if 0
431464
// (ix, iy) now give the actual pixel which will receive the charge
@@ -455,8 +488,8 @@ namespace galsim {
455488
Irr /= addedFlux;
456489
Irr0 /= addedFlux;
457490
dbg<<"Irr = "<<Irr<<" cf. Irr0 = "<<Irr0<<std::endl;
458-
dbg << "Found "<< zerocount << " photons in undistorted pixel, " << nearestcount;
459-
dbg << " in closest neighbor, " << othercount << " in other neighbor. " << misscount;
491+
dbg << "Found "<< zerocount << " photons in undistorted pixel, " << neighborcount;
492+
dbg << " in one of the neighbors, and "<<misscount;
460493
dbg << " not in any pixel\n" << std::endl;
461494
#endif
462495
return addedFlux;

0 commit comments

Comments
 (0)