LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
SpatialUtil.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 
33 #include <cassert>
34 #include <stdexcept>
35 #include <algorithm>
36 
37 #include "lsst/pex/exceptions.h"
38 
39 #include "lsst/ap/SpatialUtil.h"
40 #include "lsst/afw/geom/Angle.h"
41 
42 namespace ex = lsst::pex::exceptions;
43 namespace afwGeom = lsst::afw::geom;
44 
45 
46 // -- ZoneStripeChunkDecomposition ----------------
47 
49  int const zonesPerDegree,
50  int const zonesPerStripe,
51  int const maxEntriesPerZoneEstimate
52 ) :
53  _chunksPerStripe(),
54  _zonesPerDegree(zonesPerDegree),
55  _zonesPerStripe(zonesPerStripe),
56  _maxEntriesPerZoneEstimate(maxEntriesPerZoneEstimate)
57 {
58  if (zonesPerDegree < 1 || zonesPerDegree > 3600) {
59  throw LSST_EXCEPT(ex::RangeError,
60  "zone height must be between 1 arc-second and 1 degree");
61  }
62  if (zonesPerStripe < 1) {
63  throw LSST_EXCEPT(ex::RangeError,
64  "there must be at least 1 zone per stripe");
65  }
66  if (maxEntriesPerZoneEstimate < 1) {
67  throw LSST_EXCEPT(ex::RangeError,
68  "the max entries per zone estimate must be at least 1");
69  }
70  _minZone = -90*zonesPerDegree;
71  _maxZone = 90*zonesPerDegree - 1;
72  _maxZoneAsDouble = static_cast<double>(_maxZone);
73 
74  // C89/C++ standard says: rounding direction of division when either operand is negative
75  // is implementation defined. Therefore, implement round to -Infinity by hand.
76  int const quo = (-_minZone) / zonesPerStripe;
77  int const rem = (-_minZone) % zonesPerStripe;
78  _minStripe = (rem == 0) ? -quo : -1 - quo;
79  _maxStripe = _maxZone/zonesPerStripe;
80 
81  int const numStripes = _maxStripe - _minStripe + 1;
82  double const minWidth = static_cast<double>(zonesPerStripe)/_zonesPerDegree;
83  if (numStripes >= 32768) {
84  throw LSST_EXCEPT(ex::RangeError,
85  "Requested spatial parameters result in more than 32767 stripes");
86  }
87  if (getNumChunksPerStripe(0, minWidth) >= 32768) {
88  throw LSST_EXCEPT(ex::RangeError,
89  "Requested spatial parameters result in more than 32767 chunks per stripe");
90  }
91 
92  _chunksPerStripe.reserve(numStripes);
93  for (int i = 0; i < numStripes; ++i) {
94  _chunksPerStripe.push_back(getNumChunksPerStripe(i + _minStripe, minWidth));
95  }
96 }
97 
98 
100  _chunksPerStripe(zsc._chunksPerStripe),
101  _zonesPerDegree (zsc._zonesPerDegree),
102  _maxZoneAsDouble(zsc._maxZoneAsDouble),
103  _zonesPerStripe (zsc._zonesPerStripe),
104  _maxEntriesPerZoneEstimate(zsc._maxEntriesPerZoneEstimate),
105  _minZone (zsc._minZone),
106  _maxZone (zsc._maxZone),
107  _minStripe (zsc._minStripe),
108  _maxStripe (zsc._maxStripe)
109 {}
110 
111 
113  using std::swap;
114 
115  if (this != &zsc) {
116  swap(_chunksPerStripe, zsc._chunksPerStripe);
117  swap(_zonesPerDegree, zsc._zonesPerDegree);
118  swap(_maxZoneAsDouble, zsc._maxZoneAsDouble);
119  swap(_maxEntriesPerZoneEstimate, zsc._maxEntriesPerZoneEstimate);
120  swap(_zonesPerStripe, zsc._zonesPerStripe);
121  swap(_minZone, zsc._minZone);
122  swap(_maxZone, zsc._maxZone);
123  swap(_minStripe, zsc._minStripe);
124  swap(_maxStripe, zsc._maxStripe);
125  }
126 }
127 
128 
139  int const stripeId,
140  double const minWidth
141 ) const {
142  assert(stripeId >= _minStripe && stripeId <= _maxStripe && "stripe id out of range");
143  assert(minWidth > 0.0 && minWidth < 90.0 && "chunk width out of range");
144 
145  double d1 = std::fabs(getStripeDecMin(stripeId));
146  double d2 = std::fabs(getStripeDecMax(stripeId));
147  double maxAbsDec = d1 < d2 ? d2 : d1;
148  if (maxAbsDec > 89.9) {
149  return 1;
150  }
151  double cosWidth = std::cos(afwGeom::degToRad(minWidth));
152  double sinDec = std::sin(afwGeom::degToRad(maxAbsDec));
153  double cosDec = std::cos(afwGeom::degToRad(maxAbsDec));
154  cosWidth = (cosWidth - sinDec*sinDec)/(cosDec*cosDec);
155  if (cosWidth < 0) {
156  return 1;
157  }
158  return static_cast<int>(std::floor(afwGeom::TWOPI/std::acos(cosWidth)));
159 }
160 
161 
176  int const stripeId,
177  double const cenRa,
178  double const cenDec,
179  double const rad
180 ) const {
181  assert(stripeId >= _minStripe && stripeId <= _maxStripe && "stripe id out of range");
182 
183  // find dec extents of stripe and circle
184  double const stripeDecMin = getStripeDecMin(stripeId);
185  double const stripeDecMax = getStripeDecMax(stripeId);
186  double circleDecMin = cenDec - rad;
187  double circleDecMax = cenDec + rad;
188  double a = 0.0;
189 
190  if (circleDecMax <= stripeDecMin || circleDecMin >= stripeDecMax) {
191  // the circle doesn't intersect the stripe
192  a = 0.0;
193  } else if (circleDecMax >= 89.9) {
194  // the circle contains (or is very close to) the north pole
195  if (circleDecMax > 90.0) {
196  circleDecMax = 180.0 - circleDecMax;
197  }
198  if (stripeDecMax >= circleDecMax) {
199  a = 180.0;
200  } else {
201  a = alpha(rad, cenDec, stripeDecMax);
202  }
203  } else if (circleDecMin <= -89.9) {
204  // the circle contains (or is very close to) the south pole
205  if (circleDecMin < -90.0) {
206  circleDecMin = -180.0 - circleDecMin;
207  }
208  if (stripeDecMin <= circleDecMin) {
209  a = 180.0;
210  } else {
211  a = alpha(rad, cenDec, stripeDecMin);
212  }
213  } else {
214  // the circle does not contain a pole
215  double decOfMaxAlpha = afwGeom::radToDeg(std::asin(std::sin(afwGeom::degToRad(cenDec))/std::cos(afwGeom::degToRad(rad))));
216  if (decOfMaxAlpha < stripeDecMin) {
217  a = alpha(rad, cenDec, stripeDecMin);
218  } else if (decOfMaxAlpha > stripeDecMax) {
219  a = alpha(rad, cenDec, stripeDecMax);
220  } else {
221  // dec of max alpha value is within the stripe
222  a = maxAlpha(rad, cenDec);
223  }
224  }
225  return a;
226 }
227 
228 
229 // -- Helper functions ----------------
230 
249  double const theta,
250  double const centerDec,
251  double const dec
252 ) {
253  assert(theta > 0.0 && theta < 10.0 && "radius out of range");
254  assert(centerDec >= -90.0 && centerDec <= 90.0 && "declination out of range");
255  assert(dec >= -90.0 && dec <= 90.0 && "declination out of range");
256 
257  if (std::fabs(centerDec) + theta > 89.9) {
258  return 180.0;
259  }
260  double x = std::cos(afwGeom::degToRad(theta)) - std::sin(afwGeom::degToRad(centerDec))*std::sin(afwGeom::degToRad(dec));
261  double u = std::cos(afwGeom::degToRad(centerDec))*std::cos(afwGeom::degToRad(dec));
262  double y = std::sqrt(std::fabs(u*u - x*x));
263  return afwGeom::radToDeg(std::fabs(std::atan2(y,x)));
264 }
265 
266 
280  double const theta,
281  double const centerDec
282 ) {
283  assert(theta > 0.0 && theta < 10.0 && "radius out of range");
284  assert(centerDec >= -90.0 && centerDec <= 90.0 && "declination out of range");
285 
286  if (std::fabs(centerDec) + theta > 89.9) {
287  return 180.0;
288  }
289  double y = std::sin(afwGeom::degToRad(theta));
290  double x = std::sqrt(std::fabs(cos(afwGeom::degToRad(centerDec - theta))*cos(afwGeom::degToRad(centerDec + theta))));
291  return afwGeom::radToDeg(std::fabs(std::atan(y/x)));
292 }
293 
294 
309  std::vector<int> & chunkIds,
310  CircularRegion const & region,
311  ZoneStripeChunkDecomposition const & zsc,
312  int const workerId,
313  int const numWorkers
314 ) {
315  if (numWorkers < 1) {
316  throw LSST_EXCEPT(ex::InvalidParameterError, "number of workers must be positive");
317  }
318  if (workerId < 0 || workerId >= numWorkers) {
319  throw LSST_EXCEPT(ex::InvalidParameterError,
320  "Worker id must be between 0 and N - 1, where N is the total number of workers");
321  }
322 
323  for (int s = zsc.decToStripe(region.getMinDec()); s <= zsc.decToStripe(region.getMaxDec()); ++s) {
324 
325  // round-robin stripes to workers
326  int rem = s % numWorkers;
327  if (rem < 0) {
328  rem += numWorkers;
329  }
330  if (rem != workerId) {
331  continue;
332  }
333 
334  int const fc = zsc.getFirstChunkForStripe(s);
335  int const nc = zsc.getNumChunksPerStripe(s);
336  double a = zsc.stripeAndCircleToRaRange(s,
337  region.getCenterRa(), region.getCenterDec(), region.getRadius());
338  double raMin = region.getCenterRa() - a;
339  double raMax = region.getCenterRa() + a;
340  bool wrap = false;
341 
342  if (raMin < 0.0) {
343  raMin += 360.0;
344  wrap = true;
345  }
346  if (raMax >= 360.0) {
347  raMax -= 360.0;
348  wrap = true;
349  }
350  int maxChunk = static_cast<int>(std::floor((raMax/360.0)*nc));
351  if (maxChunk == nc) {
352  --maxChunk;
353  }
354  int chunk = static_cast<int>(std::floor((raMin/360.0)*nc));
355  if (chunk == nc) {
356  --chunk;
357  }
358  chunk += fc;
359  maxChunk += fc;
360 
361  if (raMax < raMin || (raMax == raMin && wrap)) {
362  if (chunk == maxChunk) {
363  --maxChunk; // avoid adding the same chunk twice
364  }
365  for ( ; chunk < fc + nc; ++chunk) {
366  chunkIds.push_back(chunk);
367  }
368  for (chunk = 0; chunk <= maxChunk; ++chunk) {
369  chunkIds.push_back(chunk);
370  }
371  } else {
372  for ( ; chunk <= maxChunk; ++chunk) {
373  chunkIds.push_back(chunk);
374  }
375  }
376  }
377 }
378 
379 
394  std::vector<int> & chunkIds,
395  RectangularRegion const & region,
396  ZoneStripeChunkDecomposition const & zsc,
397  int const workerId,
398  int const numWorkers
399 ) {
400  if (numWorkers < 1) {
401  throw LSST_EXCEPT(ex::InvalidParameterError,
402  "number of workers must be positive");
403  }
404  if (workerId < 0 || workerId >= numWorkers) {
405  throw LSST_EXCEPT(ex::InvalidParameterError,
406  "Worker id must be between 0 and N - 1, where N is the total number of workers");
407  }
408 
409  double const raMin = region.getMinRa();
410  double const raMax = region.getMaxRa();
411 
412  for (int s = zsc.decToStripe(region.getMinDec()); s <= zsc.decToStripe(region.getMaxDec()); ++s) {
413 
414  // round-robin stripes to workers
415  int rem = s % numWorkers;
416  if (rem < 0) {
417  rem += numWorkers;
418  }
419  if (rem != workerId) {
420  continue;
421  }
422 
423  int const fc = zsc.getFirstChunkForStripe(s);
424  int const nc = zsc.getNumChunksPerStripe(s);
425 
426  int maxChunk = fc + static_cast<int>(std::floor((raMax*nc)/360.0)) % nc;
427  int chunk = fc + static_cast<int>(std::floor((raMin*nc)/360.0)) % nc;
428 
429  if (raMax < raMin) {
430  if (chunk == maxChunk) {
431  --maxChunk; // avoid adding the same chunk twice
432  }
433  for ( ; chunk < fc + nc; ++chunk) {
434  chunkIds.push_back(chunk);
435  }
436  for (chunk = 0; chunk <= maxChunk; ++chunk) {
437  chunkIds.push_back(chunk);
438  }
439  } else {
440  for (; chunk <= maxChunk; ++chunk) {
441  chunkIds.push_back(chunk);
442  }
443  }
444  }
445 }
446 
int y
A circular region of the unit sphere (sky).
int getFirstChunkForStripe(int const stripeId) const
Definition: SpatialUtil.h:112
void swap(Ellipse< DataT > &a, Ellipse< DataT > &b)
Definition: EllipseTypes.h:90
void computeChunkIds(std::vector< int > &chunkIds, CircularRegion const &region, ZoneStripeChunkDecomposition const &zsc, int const workerId=0, int const numWorkers=1)
Definition: SpatialUtil.cc:308
double getRadius() const
Returns the radius of the circle.
void swap(ImageBase< PixelT > &a, ImageBase< PixelT > &b)
Definition: Image.cc:291
ZoneStripeChunkDecomposition(int const zonesPerDegree, int const zonesPerStripe, int const maxEntriesPerZoneEstimate)
Definition: SpatialUtil.cc:48
int decToStripe(double const dec) const
Definition: SpatialUtil.h:156
double getMinDec() const
Returns the minimum declination of points in the region.
double getCenterDec() const
Returns the declination of the circle center.
double const TWOPI
Definition: Angle.h:19
double getMaxDec() const
Returns the maximum declination of points in the region.
double getMinRa() const
Returns the minimum right ascension of points in the region.
double radToDeg(long double angleInRadians)
Definition: RaDecStr.cc:61
double getCenterRa() const
Returns the right ascension of the circle center.
double getMaxRa() const
Returns the maximum right ascension of points in the region.
A decomposition of the unit sphere into zones, stripes, and chunks.
Definition: SpatialUtil.h:69
double maxAlpha(double const theta, double const centerDec)
Definition: SpatialUtil.cc:279
A rectangular region (in right ascension and declination) of the unit sphere.
double getMinDec() const
Returns the minimum declination of points in the region.
int x
double degToRad(long double angleInDegrees)
Definition: RaDecStr.cc:67
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
double alpha(double const theta, double const centerDec, double const dec)
Definition: SpatialUtil.cc:248
void swap(ZoneStripeChunkDecomposition &zsc)
Definition: SpatialUtil.cc:112
int getNumChunksPerStripe(int const stripeId, double const minWidth) const
Definition: SpatialUtil.cc:138
Extent< int, N > floor(Extent< double, N > const &input)
double getMaxDec() const
Returns the maximum declination of points in the region.
double stripeAndCircleToRaRange(int const stripeId, double const cenRa, double const cenDec, double const rad) const
Definition: SpatialUtil.cc:175
Include files required for standard LSST Exception handling.
Class and helper functions related to spatial partitioning.