Commit 20133af489caec0efc4be818c501c97a8fa678a1

Authored by Andreas Specovius
Committed by Jürgen Knödlseder
1 parent a9168621

Created a sub method to compute the necessary reflected regions separation angle…

…. As the necessary separation angle depends on the rotation angle but also on the rectangle extension (overlaps may easily occur) the computation is not so easy: I implemented a rough (slightly overestimating) algorithm which chooses the maximum opening angle between the corners of the rectangle with respect to the pointing position. Extended implementation of _reflected_regions() method to allow the placement of rectangular off regions, which is essentially finally placing a rectangle instead of a circle.
Showing 1 changed file with 121 additions and 3 deletions
cscripts/csphagen.py
... ... @@ -363,6 +363,116 @@ class csphagen(ctools.csobservation):
363 363 # Return
364 364 return
365 365  
  366 + def _compute_region_separation(self, pnt_dir):
  367 + """ Compute the separation angle for reflected off regions in radians.
  368 +
  369 + Returns
  370 + -------
  371 + angle : `float`
  372 + Separation angle of two off regions (rad)
  373 + """
  374 + # Initialise the result
  375 + separation = -1
  376 +
  377 + # Compute offset of reflected regions to pointing position
  378 + offset = pnt_dir.dist_deg(self._src_dir)
  379 +
  380 + if self._srcshape == 'CIRCLE':
  381 +
  382 + # Compute apparent diameter of the circle
  383 + separation = 2.0 * self._rad / offset
  384 +
  385 + elif self._srcshape == 'RECT':
  386 +
  387 + # Compute the opening angle towards combinations of rectangle corners.
  388 + # This method overestimates the real need of space between the
  389 + # rectangles, so the method may be optimised to gain more off regions!
  390 + # Anyway, it is assured that the off regions will never overlap.
  391 +
  392 + # Get the corners
  393 + cs = [self._src_reg[0].get_corner(icorner) for icorner in range(4)]
  394 +
  395 + # Auxillary, local method for opening angle computation
  396 + def __compute_posang(pnt_dir,a,b):
  397 + """ Compute the difference in position angle to the pointing in
  398 + degrees.
  399 + """
  400 + posang_a = pnt_dir.posang_deg(a) %360
  401 + posang_b = pnt_dir.posang_deg(b) %360
  402 + posang = abs(posang_a - posang_b)
  403 + return posang
  404 +
  405 + # Compute the 6 opening angles
  406 + combinations = [[0,1], [0,2], [0,3], [1,2], [1,3], [2,3]]
  407 + angles = [__compute_posang(pnt_dir, cs[i], cs[j]) for i,j in combinations]
  408 +
  409 + # The desired separation is the maximum opening angle
  410 + separation = max(angles) *gammalib.deg2rad
  411 +
  412 +
  413 + ## Different approach:
  414 + ## Find the separation angle for which two rectangles to not overlap
  415 + ## Issue: Scanning not optimal.
  416 + # posang = pnt_dir.posang_deg(self._src_dir)
  417 + # dphi_incr = 0.1
  418 + # dphi = dphi_incr
  419 + # print("Src ctr direction: ra={} dec={}".format(self._src_dir.ra_deg(), self._src_dir.dec_deg()))
  420 + # print(self._src_reg)
  421 + # while dphi<360:
  422 +
  423 + # ctr_dir = pnt_dir.clone()
  424 + # ctr_dir.rotate_deg(posang + dphi, offset)
  425 + # print("Query ctr direction: ra={} dec={}".format(ctr_dir.ra_deg(), ctr_dir.dec_deg()))
  426 +
  427 + # # Create test rectangle
  428 + # reg = gammalib.GSkyRegionRect(ctr_dir
  429 + # ,self._reg_width
  430 + # ,self._reg_height
  431 + # ,self._reg_posang + dphi
  432 + # )
  433 + # print(reg)
  434 +
  435 + # # Check test rectangle corner containment in reference rectangle
  436 + # is_corner_contained = self._src_reg.overlaps(reg)
  437 + # # is_corner_contained = False
  438 + # # for icorner in range(4):
  439 + # # corner_dir = reg.get_corner(icorner)
  440 + # # is_corner_contained |= self._src_reg.contains(corner_dir)
  441 +
  442 + # # Check if any corner was contained
  443 + # if not is_corner_contained:
  444 + # diameter = dphi
  445 + # break
  446 +
  447 + # # Increment dphi
  448 + # dphi += dphi_incr
  449 +
  450 +
  451 + ## Very different approach: Compute the width along the circular
  452 + ## region placement path.
  453 + ## Issue: Long regions will overlap in the inner part.
  454 + # def l(w,h,phi):
  455 + # """ Super complicated method to compute the height along dec-axis
  456 + # of a rotated rectangle.
  457 + # """
  458 + # phi = np.deg2rad(phi) % (2*np.pi)
  459 + # phi_c = np.arctan2(w,h)
  460 + # if phi>=(0.5*np.pi) and (phi<np.pi):
  461 + # phi = np.pi-phi
  462 + # elif (phi>=np.pi) and (phi<(1.5*np.pi)):
  463 + # phi -=np.pi
  464 + # elif (phi>=(1.5*np.pi)) and (phi<(2*np.pi)):
  465 + # phi = 2*np.pi - phi
  466 +
  467 + # if (0<=phi) and (phi<phi_c):
  468 + # result = h/2/np.cos(phi)
  469 + # else:
  470 + # result = w/2/np.sin(phi)
  471 + # return 2*result
  472 +
  473 + # Return
  474 + return separation
  475 +
366 476 def _reflected_regions(self, obs):
367 477 """
368 478 Calculate list of reflected regions for a single observation (pointing)
... ... @@ -402,7 +512,7 @@ class csphagen(ctools.csobservation):
402 512 # ... otherwise
403 513 else:
404 514 posang = pnt_dir.posang_deg(self._src_dir)
405   - if self._srcshape == 'CIRCLE':
  515 + if (self._srcshape == 'CIRCLE') or (self._srcshape == 'RECT'):
406 516  
407 517 # Determine number of background regions to skip
408 518 N_skip = self['bkgregskip'].integer()
... ... @@ -412,7 +522,7 @@ class csphagen(ctools.csobservation):
412 522 # Compute the angular separation of reflected regions wrt
413 523 # camera center. The factor 1.05 ensures background regions
414 524 # do not overlap due to numerical precision issues
415   - alpha = 1.05 * 2.0 * self._rad / offset
  525 + alpha = 1.05 * self._compute_region_separation(pnt_dir)
416 526  
417 527 # Compute number of reflected regions by dividing the angular
418 528 # separation by 2 pi.
... ... @@ -437,7 +547,15 @@ class csphagen(ctools.csobservation):
437 547 while dphi <= dphi_max:
438 548 ctr_dir = pnt_dir.clone()
439 549 ctr_dir.rotate_deg(posang + dphi, offset)
440   - region = gammalib.GSkyRegionCircle(ctr_dir, self._rad)
  550 + if self._srcshape == 'CIRCLE':
  551 + region = gammalib.GSkyRegionCircle(ctr_dir, self._rad)
  552 + elif self._srcshape == 'RECT':
  553 + # Adjust the posang of the rectangle correspondingly
  554 + region = gammalib.GSkyRegionRect(ctr_dir
  555 + ,self._reg_width
  556 + ,self._reg_height
  557 + ,self._reg_posang + dphi
  558 + )
441 559 if self._has_exclusion:
442 560 if self._excl_reg.overlaps(region):
443 561  
... ...