Commit db97908e4eecd708999e1e74e4424232bb6981ac
1 parent
28cac9e0
Implementation of visibility computation using the Sun constraint (Moon constraint is still missing)
Showing
3 changed files
with
330 additions
and
103 deletions
cscripts/csviscube.par
| ... | ... | @@ -28,7 +28,9 @@ outfile, f, a, viscube.fits,,, "Visibility cube output file" |
| 28 | 28 | # |
| 29 | 29 | # Visibility cube parameters |
| 30 | 30 | #=========================== |
| 31 | -binsz, r, h, 1.0,,, "Image scale (in degrees/pixel)" | |
| 31 | +binsz, r, h, 1.0,,, "Image scale (deg/pixel)" | |
| 32 | +dz, r, h, 1.0,,, "Zenith angle bin size (deg)" | |
| 33 | +zmax, r, h, 60.0,,, "Maximum zenith angle (deg)" | |
| 32 | 34 | |
| 33 | 35 | # |
| 34 | 36 | # Standard parameters | ... | ... |
cscripts/csviscube.py
| ... | ... | @@ -37,7 +37,7 @@ class csviscube(ctools.cscript): |
| 37 | 37 | # Constructor |
| 38 | 38 | def __init__(self, *argv): |
| 39 | 39 | """ |
| 40 | - Constructor. | |
| 40 | + Constructor | |
| 41 | 41 | |
| 42 | 42 | Parameters |
| 43 | 43 | ---------- |
| ... | ... | @@ -54,8 +54,10 @@ class csviscube(ctools.cscript): |
| 54 | 54 | self._name = 'csviscube' |
| 55 | 55 | self._version = '1.0.0' |
| 56 | 56 | |
| 57 | - # Initialise application by calling the appropriate class | |
| 58 | - # constructor. | |
| 57 | + # Initialise members | |
| 58 | + self._cube = gammalib.GSkyMap() | |
| 59 | + | |
| 60 | + # Initialise application by calling the appropriate class constructor | |
| 59 | 61 | self._init_cscript(argv) |
| 60 | 62 | |
| 61 | 63 | # Return |
| ... | ... | @@ -72,10 +74,7 @@ class csviscube(ctools.cscript): |
| 72 | 74 | self['tmax'].real() |
| 73 | 75 | self['geolon'].real() |
| 74 | 76 | self['geolat'].real() |
| 75 | - self['sunzenith'].real() | |
| 76 | - self['moonzenith'].real() | |
| 77 | 77 | self['outfile'].filename() |
| 78 | - self['binsz'].real() | |
| 79 | 78 | |
| 80 | 79 | # Write input parameters into logger |
| 81 | 80 | self._log_parameters(gammalib.TERSE) |
| ... | ... | @@ -83,38 +82,301 @@ class csviscube(ctools.cscript): |
| 83 | 82 | # Return |
| 84 | 83 | return |
| 85 | 84 | |
| 86 | - def _hour_angle_weight(self): | |
| 85 | + def _zenith_angle_map(self, nx, ny, dx, dy): | |
| 86 | + """ | |
| 87 | + Compute zenith angle map | |
| 88 | + | |
| 89 | + Parameters | |
| 90 | + ---------- | |
| 91 | + nx : int | |
| 92 | + Number of Right Ascension pixels. | |
| 93 | + ny : int | |
| 94 | + Number of Declination pixels. | |
| 95 | + dx : float | |
| 96 | + Right Ascension pixel size in degrees. | |
| 97 | + dy : float | |
| 98 | + Declination pixel size in degrees. | |
| 99 | + | |
| 100 | + Returns | |
| 101 | + ------- | |
| 102 | + map : `~gammalib.GSkyMap` | |
| 103 | + Allsky map comprising the zenith angle for an hour angle of 0. | |
| 104 | + | |
| 105 | + The zenith angle of a position (ra,dec) depends on the declination and | |
| 106 | + the hour angle h and is given by | |
| 107 | + | |
| 108 | + zenith(h,dec) = arccos( sin(lat) * sin(dec) + cos(lat) * cos(dec) * cos(h) ) | |
| 109 | + | |
| 110 | + The hour angle h (or local hour angle, LHA) is defined as the difference | |
| 111 | + between local siderial time (LST) and the Right Ascension | |
| 112 | + | |
| 113 | + h = LST - ra | |
| 114 | + | |
| 115 | + The map is computed for h=-ra which is equivalent to GST=lon (or LST=0). | |
| 116 | + In other words, the map corresponds to the time when ra=0 passes through | |
| 117 | + the local meridian. | |
| 87 | 118 | """ |
| 88 | - Compute hour angle weight vector | |
| 119 | + # Initialise zenith angle map | |
| 120 | + map = gammalib.GSkyMap('CAR','CEL',0.0,0.0,-dx,dy,nx,ny) | |
| 121 | + | |
| 122 | + # Set hour angle and declination vectors | |
| 123 | + hours = [(float(i)+0.5)*dx for i in range(nx)] | |
| 124 | + decs = [(float(i)+0.5)*dy-90.0 for i in range(ny)] | |
| 125 | + | |
| 126 | + # Get array geographic latitude | |
| 127 | + geolat = self['geolat'].real() | |
| 128 | + | |
| 129 | + # Precompute latitude terms | |
| 130 | + cos_lat = math.cos(geolat*gammalib.deg2rad) | |
| 131 | + sin_lat = math.sin(geolat*gammalib.deg2rad) | |
| 132 | + | |
| 133 | + # Loop over all declinations and hour angles and compute the zenith | |
| 134 | + # angle. Store the zenith angle in the map | |
| 135 | + index = 0 | |
| 136 | + for dec in decs: | |
| 137 | + cos_dec = math.cos(dec*gammalib.deg2rad) | |
| 138 | + sin_dec = math.sin(dec*gammalib.deg2rad) | |
| 139 | + for h in hours: | |
| 140 | + cos_h = math.cos(h*gammalib.deg2rad) | |
| 141 | + zenith = math.acos(sin_lat*sin_dec + | |
| 142 | + cos_lat*cos_dec*cos_h)*gammalib.rad2deg | |
| 143 | + map[index] = zenith | |
| 144 | + index += 1 | |
| 145 | + | |
| 146 | + # Log zenith angle map | |
| 147 | + self._log_header2(gammalib.EXPLICIT, 'Zenith angle map') | |
| 148 | + self._log_string(gammalib.EXPLICIT, str(map)) | |
| 149 | + | |
| 150 | + # Return zenith angle map | |
| 151 | + return map | |
| 152 | + | |
| 153 | + def _sun_radec(self, time): | |
| 154 | + """ | |
| 155 | + Compute Right Ascension and Declination of the Sun | |
| 156 | + | |
| 157 | + Parameters | |
| 158 | + ---------- | |
| 159 | + time : `~gammalib.GTime()` | |
| 160 | + Time for which declination is to be computed | |
| 161 | + | |
| 162 | + Returns | |
| 163 | + ------- | |
| 164 | + ra, dec : tuple of float | |
| 165 | + Right Ascension and Declination of the Sun in degrees | |
| 166 | + | |
| 167 | + The formulae are inspired from | |
| 168 | + https://en.wikipedia.org/wiki/Position_of_the_Sun | |
| 169 | + """ | |
| 170 | + # Compute number of days since Greenwich noon, Terrestrial Time, on | |
| 171 | + # 1 January 2000 | |
| 172 | + n = time.jd() - 2451545.0 | |
| 173 | + | |
| 174 | + # Compute mean longitude of the Sun in degrees, corrected for the | |
| 175 | + # aberration of light | |
| 176 | + L = 280.460 + 0.9856474 * n | |
| 177 | + while L < 0.0: | |
| 178 | + L += 360.0 | |
| 179 | + while L >= 360.0: | |
| 180 | + L -= 360.0 | |
| 181 | + | |
| 182 | + # Compute the mean anomaly of the Sun in radians | |
| 183 | + g = (357.528 + 0.9856003 * n) * gammalib.deg2rad | |
| 184 | + | |
| 185 | + # Compute the ecliptic longitude of the Sun in degrees | |
| 186 | + lam = L + 1.915 * math.sin(g) + 0.020 * math.sin(2.0*g) | |
| 187 | + | |
| 188 | + # Compute Right Ascension and Declination of the Sun in degrees | |
| 189 | + ra = math.atan(math.cos(23.43711*gammalib.deg2rad) * | |
| 190 | + math.tan(lam*gammalib.deg2rad))*gammalib.rad2deg | |
| 191 | + dec = math.asin(math.sin(23.43711*gammalib.deg2rad) * | |
| 192 | + math.sin(lam*gammalib.deg2rad))*gammalib.rad2deg | |
| 193 | + | |
| 194 | + # Put ra in the right quadrant (same quadrant as lam) | |
| 195 | + while lam < 0.0: | |
| 196 | + lam += 360.0 | |
| 197 | + while lam >= 360.0: | |
| 198 | + lam -= 360.0 | |
| 199 | + while ra < 0.0: | |
| 200 | + ra += 360.0 | |
| 201 | + while ra >= 360.0: | |
| 202 | + ra -= 360.0 | |
| 203 | + q_lam = int(lam / 90.0) | |
| 204 | + q_ra = int(ra / 90.0) | |
| 205 | + ra += (q_lam-q_ra)*90.0 | |
| 206 | + | |
| 207 | + # Return declination of the Sun | |
| 208 | + return ra, dec | |
| 209 | + | |
| 210 | + def _sun_ra_exclusion(self, time): | |
| 211 | + """ | |
| 212 | + Compute the Right Ascension difference in degrees before and after | |
| 213 | + noon that are excluded due to the Sun constraint | |
| 214 | + | |
| 215 | + Parameters | |
| 216 | + ---------- | |
| 217 | + time : `~gammalib.GTime()` | |
| 218 | + Time for which the Sun exclusion is to be computed | |
| 219 | + | |
| 220 | + Returns | |
| 221 | + ------- | |
| 222 | + dra : float | |
| 223 | + Positive Right Ascension difference in degrees. | |
| 224 | + """ | |
| 225 | + # Get array geographic latitude and minimum Sun zenith angle in radians | |
| 226 | + geolat = self['geolat'].real() * gammalib.deg2rad | |
| 227 | + sunzenith = self['sunzenith'].real() * gammalib.deg2rad | |
| 228 | + | |
| 229 | + # Compute Right Ascension and Declination of Sun in degrees and | |
| 230 | + # convert the Declination into radians | |
| 231 | + sunra, sundec = self._sun_radec(time) | |
| 232 | + sundec *= gammalib.deg2rad | |
| 233 | + | |
| 234 | + # Compute some sines and cosines | |
| 235 | + cos_sunzenith = math.cos(sunzenith) | |
| 236 | + sin_geolat = math.sin(geolat) | |
| 237 | + cos_geolat = math.cos(geolat) | |
| 238 | + sin_sundec = math.sin(sundec) | |
| 239 | + cos_sundec = math.cos(sundec) | |
| 89 | 240 | |
| 241 | + # Compute Right Ascension difference when Sun is below the mimimum | |
| 242 | + # zenith angle in degrees | |
| 243 | + dra = math.acos((cos_sunzenith - sin_geolat * sin_sundec) / | |
| 244 | + (cos_geolat * cos_sundec)) * gammalib.rad2deg | |
| 245 | + | |
| 246 | + # Return | |
| 247 | + return dra | |
| 248 | + | |
| 249 | + def _hour_angle_weight(self): | |
| 250 | + """ | |
| 251 | + Compute hour angle weights | |
| 252 | + | |
| 253 | + Computes an array specifying how many hours the array was observing | |
| 254 | + for a given hour angle during the time interval [tmin,tmax]. The hour | |
| 255 | + angle runs from 0 to 360 degrees. | |
| 256 | + | |
| 90 | 257 | Compute during which time the array was observing due to hour angle |
| 91 | 258 | constraints. We take here a very simple model where the night lasts |
| 92 | 259 | between 6 and 10 hours (or 90-150 degrees), with a sinusoidal variation |
| 93 | 260 | along the year. Every day the hour angle of the Sun set is advancing by |
| 94 | 261 | 4 minutes. |
| 95 | 262 | """ |
| 96 | - # Set number of hour angle bins | |
| 263 | + # Write header | |
| 264 | + self._log_header2(gammalib.NORMAL, 'Hour angle weights') | |
| 265 | + | |
| 266 | + # Get array geographic longitude | |
| 267 | + geolon = self['geolon'].real() | |
| 268 | + | |
| 269 | + # Get time interval | |
| 270 | + tmin = gammalib.GTime(self['tmin'].real(), 's') | |
| 271 | + tmax = gammalib.GTime(self['tmax'].real(), 's') | |
| 272 | + | |
| 273 | + # Initialise hour angle list | |
| 274 | + hour_angles = [] | |
| 275 | + | |
| 276 | + # Set number of hour angle bins and compute conversion factor and weight | |
| 97 | 277 | nsteps = 1000 |
| 98 | - d_min = 6.0/24.0*nsteps | |
| 99 | - d_max = 10.0/24.0*nsteps | |
| 278 | + ra2inx = float(nsteps)/360.0 # Conversion from RA (deg) to index | |
| 279 | + weight = 24.0/float(nsteps) # Weight per hour angle step | |
| 100 | 280 | |
| 101 | 281 | # Initialise hour angle array and weight |
| 102 | 282 | hours = [0.0 for i in range(nsteps)] |
| 103 | - weight = 24.0/float(nsteps) # Weight per hour angle step | |
| 104 | 283 | |
| 105 | - # Loop over all days in one year | |
| 106 | - for day in range(nsteps): | |
| 107 | - h_set = day | |
| 108 | - h_rise = day + \ | |
| 109 | - int(d_min + (d_max-d_min)*math.sin(day/float(nsteps)*gammalib.pi)) | |
| 110 | - for i in range(h_set,h_rise): | |
| 111 | - if i >= nsteps: | |
| 112 | - hours[i-nsteps] += weight | |
| 113 | - else: | |
| 284 | + # Initialise time and loop until the end time is reached | |
| 285 | + time = tmin | |
| 286 | + while time <= tmax: | |
| 287 | + | |
| 288 | + # Compute Right Ascension and Declination of Sun in degrees | |
| 289 | + sunra, sundec = self._sun_radec(time) | |
| 290 | + | |
| 291 | + # Compute by how much the zenith angle map needs to be shifted | |
| 292 | + # to correspond to the actual time | |
| 293 | + # | |
| 294 | + # NOTE: The local apparent siderial time only is relevant if | |
| 295 | + # the time interval is shorter than a day. Only in that case | |
| 296 | + # we have to set the corresponding hour angles to zero. We need | |
| 297 | + # to think how to properly implement that. | |
| 298 | + #last = time.last(geolon) * 15.0 | |
| 299 | + #print(last) | |
| 300 | + | |
| 301 | + # Compute the time from now when the Sun will culminate. The time | |
| 302 | + # is here expressed in degrees | |
| 303 | + dra_sun = self._sun_ra_exclusion(time) | |
| 304 | + | |
| 305 | + # Set [0,ra_start] and [ra_stop,360.0] | |
| 306 | + ra_start = sunra - dra_sun | |
| 307 | + ra_stop = sunra + dra_sun | |
| 308 | + | |
| 309 | + # Case 1: The RA interval during which the Sun is above the zenith | |
| 310 | + # angle constraint is fully comprised within the [0,360] interval. | |
| 311 | + # In that case the dark time is comprised of two intervals: | |
| 312 | + # [0,ra_start] and [ra_stop,360] | |
| 313 | + if ra_start >= 0.0 and ra_stop <= 360.0: | |
| 314 | + inx_stop = int(ra_start * ra2inx + 0.5) | |
| 315 | + inx_start = int(ra_stop * ra2inx + 0.5) | |
| 316 | + for i in range(0,inx_stop): | |
| 317 | + hours[i] += weight | |
| 318 | + for i in range(inx_start,nsteps): | |
| 114 | 319 | hours[i] += weight |
| 115 | 320 | |
| 116 | - # Return | |
| 117 | - return hours | |
| 321 | + # Log setting | |
| 322 | + logs = 'Sun=(%.3f,%.3f) dRA=%.3f RA_excl=[%.3f,%.3f] '\ | |
| 323 | + 'Indices=[0-%d] & [%d-%d] Dark time=%.2f h %s' % \ | |
| 324 | + (sunra, sundec, dra_sun, ra_start, ra_stop, inx_stop, inx_start, | |
| 325 | + nsteps, float(inx_stop+(nsteps-inx_start))*weight, | |
| 326 | + '(Case 1)') | |
| 327 | + self._log_value(gammalib.VERBOSE, time.utc(), logs) | |
| 328 | + | |
| 329 | + # Case 2: The RA interval during which the Sun is above the zenith | |
| 330 | + # angle constraint is starting at negative RA. In that case the | |
| 331 | + # dark time is comprised of a single interval | |
| 332 | + # [ra_stop,ra_start+360] | |
| 333 | + elif ra_start < 0.0: | |
| 334 | + inx_start = int(ra_stop * ra2inx + 0.5) | |
| 335 | + inx_stop = int((ra_start+360.0) * ra2inx + 0.5) | |
| 336 | + for i in range(inx_start,inx_stop): | |
| 337 | + hours[i] += weight | |
| 338 | + | |
| 339 | + # Log setting | |
| 340 | + logs = 'Sun=(%.3f,%.3f) dRA=%.3f RA_excl=[%.3f,%.3f] '\ | |
| 341 | + 'Indices=[%d-%d] Dark time=%.2f h %s' % \ | |
| 342 | + (sunra, sundec, dra_sun, ra_start, ra_stop, inx_start, inx_stop, | |
| 343 | + float(inx_stop-inx_start)*weight, '(Case 2)') | |
| 344 | + self._log_value(gammalib.VERBOSE, time.utc(), logs) | |
| 345 | + | |
| 346 | + # Case 3: The RA interval during which the Sun is above the zenith | |
| 347 | + # angle constraint is stopping at RA>360. In that case the dark | |
| 348 | + # time is comprised of a single interval [ra_stop-360,ra_start] | |
| 349 | + elif ra_stop > 360.0: | |
| 350 | + inx_start = int((ra_stop-360.0) * ra2inx + 0.5) | |
| 351 | + inx_stop = int(ra_start * ra2inx + 0.5) | |
| 352 | + for i in range(inx_start,inx_stop): | |
| 353 | + hours[i] += weight | |
| 354 | + | |
| 355 | + # Log setting | |
| 356 | + logs = 'Sun=(%.3f,%.3f) dRA=%.3f RA_excl=[%.3f,%.3f] '\ | |
| 357 | + 'Indices=[%d-%d] Dark time=%.2f h %s' % \ | |
| 358 | + (sunra, sundec, dra_sun, ra_start, ra_stop, inx_start, inx_stop, | |
| 359 | + float(inx_stop-inx_start)*weight, '(Case 3)') | |
| 360 | + self._log_value(gammalib.VERBOSE, time.utc(), logs) | |
| 361 | + | |
| 362 | + # Add seconds of one day and start with next day | |
| 363 | + time += 86400.0 | |
| 364 | + | |
| 365 | + # Build hour angle list | |
| 366 | + dh = 360.0/float(nsteps) | |
| 367 | + for i in range(nsteps): | |
| 368 | + hour_angle = {'angle': dh*float(i), 'hours': hours[i]} | |
| 369 | + hour_angles.append(hour_angle) | |
| 370 | + | |
| 371 | + # Log hour angle weights | |
| 372 | + total = 0.0 | |
| 373 | + for hour_angle in hour_angles: | |
| 374 | + total += hour_angle['hours'] | |
| 375 | + self._log_value(gammalib.EXPLICIT, 'Observing time', str(total)+' h') | |
| 376 | + self._log_value(gammalib.EXPLICIT, 'Number of hour angle bins', len(hour_angles)) | |
| 377 | + | |
| 378 | + # Return hour angle weights | |
| 379 | + return hour_angles | |
| 118 | 380 | |
| 119 | 381 | def _visibility_cube(self): |
| 120 | 382 | """ |
| ... | ... | @@ -126,102 +388,64 @@ class csviscube(ctools.cscript): |
| 126 | 388 | Summing over all zenith angle intervals specifies for how long a given |
| 127 | 389 | celestial position will be visible. |
| 128 | 390 | """ |
| 391 | + # Write header | |
| 392 | + self._log_header1(gammalib.TERSE, 'Compute visibility cube') | |
| 393 | + | |
| 394 | + # Set visibility cube and zenith angle map dimensions and bin size | |
| 395 | + binsz = self['binsz'].real() | |
| 396 | + nx = int(360.0/binsz+0.5) | |
| 397 | + ny = int(180.0/binsz+0.5) | |
| 398 | + dx = 360.0/float(nx) | |
| 399 | + dy = 180.0/float(ny) | |
| 400 | + | |
| 401 | + # Set zenith angle dimension and bin size | |
| 402 | + dz = self['dz'].real() | |
| 403 | + zmax = self['zmax'].real() | |
| 404 | + nz = int(zmax/dz+0.5) | |
| 405 | + dz = zmax/float(nz) | |
| 406 | + | |
| 407 | + # Log dimensions | |
| 408 | + self._log_header2(gammalib.NORMAL, 'Visibility cube dimensions') | |
| 409 | + self._log_value(gammalib.NORMAL, 'Number of RA bins', nx) | |
| 410 | + self._log_value(gammalib.NORMAL, 'Number of Dec bins', ny) | |
| 411 | + self._log_value(gammalib.NORMAL, 'Number of zenith angles', nz) | |
| 412 | + self._log_value(gammalib.NORMAL, 'RA pixel size', str(dx)+' deg') | |
| 413 | + self._log_value(gammalib.NORMAL, 'Dec pixel size', str(dy)+' deg') | |
| 414 | + self._log_value(gammalib.NORMAL, 'Zenith angle bin size', str(dz)+' deg') | |
| 415 | + self._log_value(gammalib.NORMAL, 'Maximum zenith angle', str(zmax)+' deg') | |
| 416 | + | |
| 129 | 417 | # Compute zenith angle map |
| 130 | - map = self._zenith_angle_map() | |
| 131 | - | |
| 132 | - # Set zenith angle range and bin size | |
| 133 | - dz = 1.0 | |
| 134 | - nz = int(60.0/dz) | |
| 135 | - | |
| 136 | - # Initialise visibility cube | |
| 137 | - self._cube = gammalib.GSkyMap('CAR','CEL',0.0,0.0,-1.0,1.0,360,180,nz) | |
| 418 | + map = self._zenith_angle_map(nx,ny,dx,dy) | |
| 138 | 419 | |
| 139 | 420 | # Setup hour angle weights. They specify for how many hours a given |
| 140 | - # hour angle will be observed during one year. | |
| 141 | - hours = self._hour_angle_weight() | |
| 421 | + # hour angle is observed during the covered time period. | |
| 422 | + hour_angles = self._hour_angle_weight() | |
| 142 | 423 | |
| 143 | - # Compute normalisation factor | |
| 144 | - norm = 365.0/float(len(hours)) | |
| 424 | + # Initialise visibility cube | |
| 425 | + self._cube = gammalib.GSkyMap('CAR','CEL',0.0,0.0,-dx,dy,nx,ny,nz) | |
| 145 | 426 | |
| 146 | 427 | # Loop over all hour angle weights |
| 147 | - for h, weight in enumerate(hours): | |
| 428 | + for hour_angle in hour_angles: | |
| 148 | 429 | |
| 149 | - # Compute temporal shift | |
| 150 | - shift = 360.0/float(len(hours)) * float(h) | |
| 430 | + # Compute temporal shift in degrees | |
| 431 | + shift = hour_angle['angle'] | |
| 151 | 432 | |
| 152 | 433 | # Initialise shifted zenith angle map |
| 153 | - map_shift = gammalib.GSkyMap('CAR','CEL',shift,0.0,-1.0,1.0,360,180) | |
| 434 | + map_shift = gammalib.GSkyMap('CAR','CEL',shift,0.0,-dx,dy,nx,ny) | |
| 154 | 435 | |
| 155 | 436 | # Merge zenith angle map into shifted map |
| 156 | 437 | map_shift += map |
| 157 | 438 | |
| 158 | - # Loop over all pixels of shifted map | |
| 439 | + # Loop over all pixels of the shifted map and add the hours during | |
| 440 | + # which the shifted map occurs to the relevant zenith angle bin | |
| 159 | 441 | for i, zenith in enumerate(map_shift): |
| 160 | - iz = int(zenith/dz) | |
| 442 | + iz = int(zenith/dz) | |
| 161 | 443 | if iz < nz: |
| 162 | - self._cube[i,iz] += weight * norm | |
| 444 | + self._cube[i,iz] += hour_angle['hours'] | |
| 163 | 445 | |
| 164 | 446 | # Return |
| 165 | 447 | return |
| 166 | 448 | |
| 167 | - def _zenith_angle_map(self): | |
| 168 | - """ | |
| 169 | - Compute zenith angle map | |
| 170 | - | |
| 171 | - The zenith angle of a position (ra,dec) depends on the declination and | |
| 172 | - the hour angle h and is given by | |
| 173 | - | |
| 174 | - zenith(h,dec) = arccos( sin(lat) * sin(dec) + cos(lat) * cos(dec) * cos(h) ) | |
| 175 | - | |
| 176 | - The hour angle h (or local hour angle, LHA) is defined as the difference | |
| 177 | - between local siderial time (LST) and the Right Ascension | |
| 178 | - | |
| 179 | - h = LST - ra | |
| 180 | - | |
| 181 | - LST is the difference between the Greenwich siderial time (GST) and the | |
| 182 | - geographic longitude of the observer | |
| 183 | - | |
| 184 | - LST = GST - lon | |
| 185 | - | |
| 186 | - where lon is counted positive west from the meridian. Hence | |
| 187 | - | |
| 188 | - h = GST - lon - ra | |
| 189 | - | |
| 190 | - The map is computed for h=-ra which is equivalent to GST=lon (or LST=0). | |
| 191 | - In other words, the map corresponds to the time when ra=0 passes the | |
| 192 | - local meridian. | |
| 193 | - """ | |
| 194 | - # Initialise zenith angle map | |
| 195 | - map = gammalib.GSkyMap('CAR','CEL',0.0,0.0,-1.0,1.0,360,180) | |
| 196 | - | |
| 197 | - # Set hour angle and declination vectors | |
| 198 | - hours = [float(i) for i in range(360)] | |
| 199 | - decs = [float(i)-89.5 for i in range(180)] | |
| 200 | - | |
| 201 | - # Get array geographic longitude and latitude | |
| 202 | - geolon = self['geolon'].real() | |
| 203 | - geolat = self['geolat'].real() | |
| 204 | - | |
| 205 | - # Precompute latitude terms | |
| 206 | - cos_lat = math.cos(geolat*gammalib.deg2rad) | |
| 207 | - sin_lat = math.sin(geolat*gammalib.deg2rad) | |
| 208 | - | |
| 209 | - # Loop over all declination and hour angles and compute the zenith | |
| 210 | - # angle. Store the zenith angle in the map | |
| 211 | - index = 0 | |
| 212 | - for dec in decs: | |
| 213 | - cos_dec = math.cos(dec*gammalib.deg2rad) | |
| 214 | - sin_dec = math.sin(dec*gammalib.deg2rad) | |
| 215 | - for h in hours: | |
| 216 | - cos_h = math.cos(h*gammalib.deg2rad) | |
| 217 | - zenith = math.acos(sin_lat*sin_dec + | |
| 218 | - cos_lat*cos_dec*cos_h)*gammalib.rad2deg | |
| 219 | - map[index] = zenith | |
| 220 | - index += 1 | |
| 221 | - | |
| 222 | - # Return zenith angle map | |
| 223 | - return map | |
| 224 | - | |
| 225 | 449 | |
| 226 | 450 | # Public methods |
| 227 | 451 | def run(self): |
| ... | ... | @@ -252,7 +476,7 @@ class csviscube(ctools.cscript): |
| 252 | 476 | outfile = self['outfile'].filename() |
| 253 | 477 | |
| 254 | 478 | # Log file name |
| 255 | - self._log_value(gammalib.TERSE, 'Visibility cube file', outfile.url()) | |
| 479 | + self._log_value(gammalib.NORMAL, 'Visibility cube file', outfile.url()) | |
| 256 | 480 | |
| 257 | 481 | # Save the visibility cube |
| 258 | 482 | self._cube.save(outfile, self['clobber'].boolean()) | ... | ... |
test/test_csviscube.py
| ... | ... | @@ -67,7 +67,7 @@ class Test(test): |
| 67 | 67 | |
| 68 | 68 | # Setup csviscube command |
| 69 | 69 | cmd = csviscube+' tmin=0.0 tmax=31557600.0 geolon=79.4041'+\ |
| 70 | - ' geolat=-24.6272 outfile=csviscube_cmd1.fits'+\ | |
| 70 | + ' geolat=-24.6272 binsz=3.0 outfile=csviscube_cmd1.fits'+\ | |
| 71 | 71 | ' logfile="csviscube_cmd1.log" chatter=1' |
| 72 | 72 | |
| 73 | 73 | # Check if execution of wrong command fails |
| ... | ... | @@ -92,6 +92,7 @@ class Test(test): |
| 92 | 92 | viscube['tmax'] = 31557600.0 |
| 93 | 93 | viscube['geolon'] = 79.4041 |
| 94 | 94 | viscube['geolat'] = -24.6272 |
| 95 | + viscube['binsz'] = 3.0 | |
| 95 | 96 | viscube['outfile'] = 'csviscube_py1.fits' |
| 96 | 97 | viscube['logfile'] = 'csviscube_py1.log' |
| 97 | 98 | viscube['chatter'] = 2 | ... | ... |