From 65b2e292649ad839471331a8cbf50003a738cec7 Mon Sep 17 00:00:00 2001
From: Ger van Diepen <diepen@astron.nl>
Date: Thu, 27 Jan 2011 14:21:10 +0000
Subject: [PATCH] bug 1634: Make cone searching possible

---
 CEP/pyparmdb/src/gsm.py | 201 +++++++++++++++++++++++++---------------
 1 file changed, 127 insertions(+), 74 deletions(-)

diff --git a/CEP/pyparmdb/src/gsm.py b/CEP/pyparmdb/src/gsm.py
index fc54364905c..b30365c8d34 100755
--- a/CEP/pyparmdb/src/gsm.py
+++ b/CEP/pyparmdb/src/gsm.py
@@ -7,7 +7,7 @@
 #  cat_id = 3 => NVSS
 #  cat_id = 4 => VLSS
 #  cat_id = 5 => WENSS
-def gsmSelect (outfile, ra_st, ra_end, dec_st, dec_end, fluxi_mins, cat_ids):
+def doSelect (outfile, dirSelect, fluxi_mins, cat_ids):
 
     import os
     import monetdb.sql as db
@@ -21,30 +21,24 @@ def gsmSelect (outfile, ra_st, ra_end, dec_st, dec_end, fluxi_mins, cat_ids):
     db_passwd = "msss"
     #db_lang = "sql"
 
-    # If RA crosses 360 degrees, split in two parts.
-    if ra_st <= ra_end:
-        ra_where = '(c1.ra BETWEEN %f AND %f)' % (ra_st, ra_end)
-    else:
-        ra_where = '(c1.ra BETWEEN %f AND 360 OR c1.ra BETWEEN 0 AND %f)' % (ra_st, ra_end)
     # If a single catalog, use =
     if len(cat_ids) == 1:
-        cat_where = '(c1.cat_id = %d AND c1.i_int_avg >= %f)' % (cat_ids[0], fluxi_mins[0])
+        catSelect = 'c1.cat_id = %d AND c1.i_int_avg >= %f' % (cat_ids[0], fluxi_mins[0])
     else:
         # Multiple catalogs.
         # If a single minimum flux, use it for all catalogs.
         # Note that the IN clause needs (), not [].
         if len(fluxi_mins) == 1:
-            cat_where = '(c1.cat_id IN (%s) AND c1.i_int_avg >= %f)' % (str(cat_ids)[1:-1], fluxi_mins[0])
+            catSelect = 'c1.cat_id IN (%s) AND c1.i_int_avg >= %f' % (str(cat_ids)[1:-1], fluxi_mins[0])
         else:
-            # We have a minimum flux per catalog.
-            cat_where = '('
+            # There is a minimum flux per catalog.
+            catSelect = ''
             for i in range(len(cat_ids)):
                 if i > 0:
-                    cat_where += ' OR ' 
-                cat_where += '(c1.cat_id = %d AND c1.i_int_avg >= %f)' % (cat_ids[i], fluxi_mins[i])
-            cat_where += ')'
+                    catSelect += ' OR ' 
+                catSelect += '(c1.cat_id = %d AND c1.i_int_avg >= %f)' % (cat_ids[i], fluxi_mins[i])
     # Form the entire where clause.
-    where = 'WHERE %s AND %s AND c1.decl BETWEEN %f AND %f' % (cat_where, ra_where, dec_st, dec_end)
+    where = 'WHERE (%s) AND (%s)' % (catSelect, dirSelect)
 
     conn = db.connect(hostname=db_host \
                           ,port=db_port \
@@ -83,36 +77,36 @@ def gsmSelect (outfile, ra_st, ra_end, dec_st, dec_end, fluxi_mins, cat_ids):
                   "                           END" + \
                   ")))))))))))))))))))))))" + \
                   "                          ) AS VARCHAR(300)) AS line " + \
-                  "          FROM (SELECT CAST(TRIM(c1.catsrcname) AS VARCHAR(20)) AS catsrcname " + \
+                  "          FROM (SELECT CAST(TRIM(c1.catsrcname) AS VARCHAR(23)) AS catsrcname " + \
                   "                      ,CASE WHEN c1.pa IS NULL " + \
-                  "                            THEN CAST('POINT' AS VARCHAR(20)) " + \
-                  "                            ELSE CAST('GAUSSIAN' AS VARCHAR(20)) " + \
+                  "                            THEN CAST('POINT' AS VARCHAR(23)) " + \
+                  "                            ELSE CAST('GAUSSIAN' AS VARCHAR(23)) " + \
                   "                       END AS src_type " + \
-                  "                      ,CAST(c1.ra AS VARCHAR(20))  AS ra " + \
-                  "                      ,CAST(c1.decl AS VARCHAR(20)) AS decl " + \
-                  "                      ,CAST(c1.i_int_avg AS VARCHAR(20)) AS i " + \
-                  "                      ,CAST(0 AS VARCHAR(20)) AS q " + \
-                  "                      ,CAST(0 AS VARCHAR(20)) AS u " + \
-                  "                      ,CAST(0 AS VARCHAR(20)) AS v " + \
+                  "                      ,CAST(c1.ra AS VARCHAR(23))  AS ra " + \
+                  "                      ,CAST(c1.decl AS VARCHAR(23)) AS decl " + \
+                  "                      ,CAST(c1.i_int_avg AS VARCHAR(23)) AS i " + \
+                  "                      ,CAST(0 AS VARCHAR(23)) AS q " + \
+                  "                      ,CAST(0 AS VARCHAR(23)) AS u " + \
+                  "                      ,CAST(0 AS VARCHAR(23)) AS v " + \
                   "                      ,CASE WHEN c1.pa IS NULL " + \
-                  "                            THEN CAST('' AS VARCHAR(20)) " + \
+                  "                            THEN CAST('' AS VARCHAR(23)) " + \
                   "                            ELSE CASE WHEN c1.major IS NULL " + \
-                  "                                      THEN CAST('' AS VARCHAR(20)) " + \
-                  "                                      ELSE CAST(c1.major AS varchar(20)) " + \
+                  "                                      THEN CAST('' AS VARCHAR(23)) " + \
+                  "                                      ELSE CAST(c1.major AS varchar(23)) " + \
                   "                                 END " + \
                   "                       END AS MajorAxis " + \
                   "                      ,CASE WHEN c1.pa IS NULL " + \
-                  "                            THEN CAST('' AS VARCHAR(20)) " + \
+                  "                            THEN CAST('' AS VARCHAR(23)) " + \
                   "                            ELSE CASE WHEN c1.minor IS NULL " + \
-                  "                                      THEN CAST('' AS VARCHAR(20)) " + \
-                  "                                      ELSE CAST(c1.minor AS varchar(20)) " + \
+                  "                                      THEN CAST('' AS VARCHAR(23)) " + \
+                  "                                      ELSE CAST(c1.minor AS varchar(23)) " + \
                   "                                 END " + \
                   "                       END AS MinorAxis " + \
                   "                      ,CASE WHEN c1.pa IS NULL " + \
-                  "                            THEN CAST('' AS VARCHAR(20)) " + \
-                  "                            ELSE CAST(c1.pa AS varchar(20)) " + \
+                  "                            THEN CAST('' AS VARCHAR(23)) " + \
+                  "                            ELSE CAST(c1.pa AS varchar(23)) " + \
                   "                       END AS Orientation " + \
-                  "                      ,CAST(c1.freq_eff AS VARCHAR(20)) AS ReferenceFrequency " + \
+                  "                      ,CAST(c1.freq_eff AS VARCHAR(23)) AS ReferenceFrequency " + \
                   "                      ,CASE WHEN si.spindx_degree IS NULL " + \
                   "                            THEN 0 " + \
                   "                            ELSE si.spindx_degree " + \
@@ -149,55 +143,108 @@ def gsmSelect (outfile, ra_st, ra_end, dec_st, dec_end, fluxi_mins, cat_ids):
     return len(y)
 
 
+def gsmSelectCone (outfile, ra, dec, radius, fluxi_mins, cat_ids):
+    if ra < 0  or  ra > 360:
+        print 'RA', ra, 'is invalid: <0 or >360 degrees'
+        return -1
+    if dec < -90  or  dec > 90:
+        print 'DEC', dec, 'is invalid: <-90 or >90 degrees'
+        return -1
+    if radius < 0  or  radius > 90:
+        print 'radius', radius, 'is invalid: <0 or >90 degrees'
+        return -1
+    # Determine DEC boundaries (for hopefully faster query).
+    # Convert degrees to radians.
+    import math
+    mindec = dec - radius
+    maxdec = dec + radius
+    d2r = math.pi / 180.
+    ra  *= d2r
+    dec *= d2r
+    radius *= d2r
+    # Source (srcRA,srcDEC) is inside the cone if:
+    #  sin(dec)*sin(srcDEC) + cos(dec)*cos(srcDEC)*cos(ra-srcRA) >= cos(radius)
+    select = '(c1.decl BETWEEN %16.12f AND %16.12f) AND (%16.14f*sin(c1.decl*%16.14f) + %16.14f*cos(c1.decl*%16.14f)*cos(%16.14f-c1.ra*%16.14f) > %16.14f)' % (mindec, maxdec, math.sin(dec), d2r, math.cos(dec), d2r, ra, d2r, math.cos(radius))
+    return doSelect (outfile, select, fluxi_mins, cat_ids)
+
+def gsmSelectBox (outfile, ra_st, ra_end, dec_st, dec_end, fluxi_mins, cat_ids):
+    for ra in [ra_st,ra_end]:
+        if ra < 0  or  ra > 360:
+            print 'RA', ra, 'is invalid: <0 or >360 degrees'
+            return -1
+    for dec in [dec_st,dec_end]:
+        if dec < -90  or  dec > 90:
+            print 'DEC', dec, 'is invalid: <-90 or >90 degrees'
+            return -1
+    if dec_st > dec_end:
+        print 'invalid DEC: start', dec_st, '> end', dec_end
+        return -1
+    # Form the selection for the RA,DEC.
+    # If RA crosses 360 degrees, split in two parts.
+    if ra_st <= ra_end:
+        select = '(c1.ra BETWEEN %16.12f AND %16.12f)' % (ra_st, ra_end)
+    else:
+        select = '(c1.ra BETWEEN %16.12f AND 360 OR c1.ra BETWEEN 0 AND %16.12f)' % (ra_st, ra_end)
+    select += ' AND (c1.decl BETWEEN %16.12f AND %16.12f)' % (dec_st, dec_end)
+    return doSelect (outfile, select, fluxi_mins, cat_ids)
+
+# Interpret the arguments and do the selection.
 def gsmMain (name, argv):
-    if len(argv) < 5:
+    useBox = False
+    starg = 0
+    optarg = 4
+    if len(argv) > 0  and  argv[0] == '-b':
+        # select using a box
+        useBox = True
+        starg = 1
+        optarg = 6
+    if len(argv) < optarg:
         print ''
         print 'Insufficient arguments given; run as:'
         print ''
-        print '   %s outfile stRA endRA stDEC endDEC [minFluxI [catalogs]]' % name
+        print '   %s outfile RA DEC radius [minFluxI [catalogs]]' % name
+        print 'to select using a cone'
+        print ''
+        print '   %s -b outfile stRA endRA stDEC endDEC [minFluxI [catalogs]]' % name
+        print 'to select using a box'
+        print ''
+        print '   outfile    path-name of the output file'
+        print '              It will be overwritten if already existing'
+        print '   RA         cone center Right Ascension (J2000, degrees)'
+        print '   DEC        cone center Declination     (J2000, degrees)'
+        print '   radius     cone radius                 (degrees)'
+        print '   stRA       box start   Right Ascension (J2000, degrees)'
+        print '   endRA      box end     Right Ascension (J2000, degrees)'
+        print '      stRA can be > endRA indicating crossing 360 deg'
+        print '   minDEC     box start   Declination     (J2000, degrees)'
+        print '   maxDEC     box end     Declination     (J2000, degrees)'
+        print '   minFluxI   minimum flux (integrated Stokes I flux in Jy)'
+        print '              If a single value is given, it is used for all catalogs.'
+        print '              If multiple values given (separated by commas), each applies'
+        print '              to the corresponding catalog.' 
+        print '              Default is 0.5'
+        print '   catalogs   names of catalogs to search (case-insensitive)'
+        print '              (NVSS, VLSS, and/or WENSS)'
+        print '              If multiple, separate by commas'
+        print '              Default is WENSS'
         print ''
-        print '      outfile    path-name of the output file'
-        print '                 It will be overwritten if already existing'
-        print '      stRA       start Right Ascension (J2000, degrees)'
-        print '      endRA      end   Right Ascension (J2000, degrees)'
-        print '         stRA can be > endRA indicating crossing 360 deg'
-        print '      minDEC     start Declination (J2000, degrees)'
-        print '      maxDEC     end   Declination (J2000, degrees)'
-        print '      minFluxI   minimum flux (integrated Stokes I in Jy)'
-        print '                 default = 0.5'
-        print '                 If a single value is given, it is used for all catalogs.'
-        print '                 If multiple values (separated by commas), each applies'
-        print '                 to the corresponding catalog.' 
-        print '      catalogs   names of catalogs to search (case-insensitive)'
-        print '                 (NVSS, VLSS, and/or WENSS)'
-        print '                 If multiple, separate by commas'
-        print '                 Default is WENSS'
-        return False
-    outfile = argv[0]
-    stRA    = float(argv[1])
-    endRA   = float(argv[2])
-    stDEC   = float(argv[3])
-    endDEC  = float(argv[4])
-    for ra in [stRA,endRA]:
-        if ra < 0  or  ra > 360:
-            print 'RA', ra, 'is invalid: <0 or >360 degrees'
-            return False
-    for dec in [stDEC,endDEC]:
-        if dec < -90  or  dec > 90:
-            print 'DEC', dec, 'is invalid: <-90 or >90 degrees'
-            return False
-    if stDEC > endDEC:
-        print 'invalid DEC: start', stDEC, '> end', endDEC
         return False
+    # Get the arguments.
+    outfile = argv[starg]
+    a1 = float(argv[starg+1])
+    a2 = float(argv[starg+2])
+    a3 = float(argv[starg+3])
+    if useBox:
+        a4 = float(argv[starg+4])
     minFlux = [0.5]
-    if len(argv) > 5  and  len(argv[5]) > 0:
-        minFlux = [float(x) for x in argv[5].split(',')]
+    if len(argv) > optarg  and  len(argv[optarg]) > 0:
+        minFlux = [float(x) for x in argv[optarg].split(',')]
     #  cat_id = 3 => NVSS
     #  cat_id = 4 => VLSS
     #  cat_id = 5 => WENSS
     cats = ['WENSS']
-    if len(argv) > 6  and  len(argv[6]) > 0:
-        cats = argv[6].split (',')
+    if len(argv) > optarg+1  and  len(argv[optarg+1]) > 0:
+        cats = argv[optarg+1].split (',')
     cat_ids = []
     for cat in cats:
         cat = cat.upper()
@@ -214,13 +261,19 @@ def gsmMain (name, argv):
         print 'Nr of minFlux values (%s) must be 1 or match nr of catalogs' % argv[5]
         return False;
     # Do the selection and create the makesourcedb file.
-    nr = gsmSelect (outfile, stRA, endRA, stDEC, endDEC, minFlux, cat_ids)
+    if useBox:
+        nr = gsmSelectBox  (outfile, a1, a2, a3, a4, minFlux, cat_ids)
+    else:
+        nr = gsmSelectCone (outfile, a1, a2, a3, minFlux, cat_ids)
     if nr < 0:
         return False
-    if nr == 0:
+    elif nr == 0:
         print 'Warning: no matching sources found in GSM for'
-        print '  stRA=%f endRA=%f stDEC=%f endDEC=%f' % (stRA,endRA,stDEC,endDEC)
-        print '  minFluxI=%f catalogs=%s' % (minFlux, cats)
+        if useBox:
+            print '  stRA=%f endRA=%f stDEC=%f endDEC=%f' % (a1,a2,a3,a4)
+        else:
+            print '  RA=%f DEC=%f radius=%f' % (a1,a2,a3)
+        print '  minFluxI=%s catalogs=%s' % (str(minFlux), cats)
     else:
         print '%d sources written into %s' % (nr, outfile)
     return True
-- 
GitLab