LSSTApplications  8.0.0.0+107,8.0.0.1+13,9.1+18,9.2,master-g084aeec0a4,master-g0aced2eed8+6,master-g15627eb03c,master-g28afc54ef9,master-g3391ba5ea0,master-g3d0fb8ae5f,master-g4432ae2e89+36,master-g5c3c32f3ec+17,master-g60f1e072bb+1,master-g6a3ac32d1b,master-g76a88a4307+1,master-g7bce1f4e06+57,master-g8ff4092549+31,master-g98e65bf68e,master-ga6b77976b1+53,master-gae20e2b580+3,master-gb584cd3397+53,master-gc5448b162b+1,master-gc54cf9771d,master-gc69578ece6+1,master-gcbf758c456+22,master-gcec1da163f+63,master-gcf15f11bcc,master-gd167108223,master-gf44c96c709
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 
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:287
int y
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 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.
Include files required for standard LSST Exception handling.
A decomposition of the unit sphere into zones, stripes, and chunks.
Definition: SpatialUtil.h:69
int x
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.
double const TWOPI
Definition: Angle.h:19
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
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
Class and helper functions related to spatial partitioning.