From eca967d49527f107100ad0cdde65ae66656cfff2 Mon Sep 17 00:00:00 2001
From: Branson Stephens <branson.stephens@ligo.org>
Date: Tue, 5 Jan 2016 13:56:16 -0600
Subject: [PATCH] Added oLIB event subclass to ingest analysis-specific
 attributes, and added these to the event presentation. Also added frequency
 and fluence to the VOEvent for LIB events.

---
 gracedb/buildVOEvent.py                       | 29 +++++++++++++++++++
 .../migrations/0010_lalinferenceburstevent.py | 27 +++++++++++++++++
 gracedb/models.py                             |  8 +++++
 gracedb/query.py                              |  1 +
 gracedb/translator.py                         |  8 +++++
 gracedb/view_logic.py                         |  3 ++
 gracedb/view_utils.py                         | 13 +++++++++
 gracedb/views.py                              |  2 ++
 templates/gracedb/event_detail_LIB.html       | 29 +++++++++++++++++++
 utils/__init__.py                             | 11 ++++++-
 10 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 gracedb/migrations/0010_lalinferenceburstevent.py
 create mode 100644 templates/gracedb/event_detail_LIB.html

diff --git a/gracedb/buildVOEvent.py b/gracedb/buildVOEvent.py
index 5bd0c259a..c62b04f6d 100755
--- a/gracedb/buildVOEvent.py
+++ b/gracedb/buildVOEvent.py
@@ -26,6 +26,7 @@ from django.conf import settings
 from django.core.urlresolvers import reverse
 from models import CoincInspiralEvent, MultiBurstEvent
 from models import VOEvent as GraceDBVOEvent
+from models import LalInferenceBurstEvent
 
 import os
 
@@ -411,6 +412,34 @@ def buildVOEvent(event, serial_number, voevent_type, request=None, skymap_filena
                     Description=["Estimated fluence of GW burst signal"]))
             except Exception: 
                 pass
+        elif isinstance(event,LalInferenceBurstEvent):
+            w.add_Param(Param(name="frequency", 
+                dataType="float", 
+                ucd="gw.frequency", 
+                unit="Hz", 
+                value=float(event.frequency),
+                Description=["Frequency of GW burst signal"]))
+
+            # Calculate the fluence. 
+            # From Min-A Cho: fluence = pi*(c**3)*(freq**2)*(hrss_max**2)*(10**3)/(4*G)
+            # Note that hrss here actually has units of s^(-1/2)
+            # XXX obviously need to refactor here.
+            try:
+                pi = 3.14152
+                c = 2.99792E10
+                G = 6.674E-8
+                fluence = pi * pow(c,3) * pow(event.frequency,2) 
+                fluence = fluence * pow(event.hrss,2)
+                fluence = fluence / (4.0*G)
+
+                w.add_Param(Param(name="Fluence", 
+                    dataType="float", 
+                    ucd="gw.fluence", 
+                    unit="erg/cm^2", 
+                    value=fluence,
+                    Description=["Estimated fluence of GW burst signal"]))
+            except:
+                pass
         else:
             pass
 
diff --git a/gracedb/migrations/0010_lalinferenceburstevent.py b/gracedb/migrations/0010_lalinferenceburstevent.py
new file mode 100644
index 000000000..2b3ea4345
--- /dev/null
+++ b/gracedb/migrations/0010_lalinferenceburstevent.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('gracedb', '0009_lengthen_emgroup_name'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='LalInferenceBurstEvent',
+            fields=[
+                ('event_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='gracedb.Event')),
+                ('bci', models.FloatField(null=True)),
+                ('quality', models.FloatField(null=True)),
+                ('bsn', models.FloatField(null=True)),
+                ('omicron_snr', models.FloatField(null=True)),
+                ('hrss', models.FloatField(null=True)),
+                ('frequency', models.FloatField(null=True)),
+            ],
+            bases=('gracedb.event',),
+        ),
+    ]
diff --git a/gracedb/models.py b/gracedb/models.py
index 6b88f7fb7..c2343ddf8 100644
--- a/gracedb/models.py
+++ b/gracedb/models.py
@@ -822,6 +822,14 @@ class MultiBurstEvent(Event):
     ligo_angle       = models.FloatField(null=True)
     ligo_angle_sig   = models.FloatField(null=True)
 
+class LalInferenceBurstEvent(Event):
+    bci              = models.FloatField(null=True)
+    quality          = models.FloatField(null=True)
+    bsn              = models.FloatField(null=True)
+    omicron_snr      = models.FloatField(null=True)
+    hrss             = models.FloatField(null=True)
+    frequency        = models.FloatField(null=True)
+
 class SingleInspiral(models.Model):
     event             = models.ForeignKey(Event, null=False)
     ifo               = models.CharField(max_length=20, null=True)
diff --git a/gracedb/query.py b/gracedb/query.py
index 13f6f707c..5852ad5c8 100644
--- a/gracedb/query.py
+++ b/gracedb/query.py
@@ -231,6 +231,7 @@ tableTranslations = {
         'si': 'singleinspiral',
         'ci': 'coincinspiralevent',
         'mb': 'multiburstevent',
+        'li': 'lalinferenceburstevent',
         'coincinspiral': 'coincinspiralevent',
         'multiburst': 'multiburstevent',
         'grb': 'grbevent',
diff --git a/gracedb/translator.py b/gracedb/translator.py
index 53e015391..9fd5a25f7 100644
--- a/gracedb/translator.py
+++ b/gracedb/translator.py
@@ -409,6 +409,14 @@ def handle_uploaded_data(event, datafilename,
         event.instruments = event_dict['instruments']
         event.nevents     = event_dict.get('nevents', 1)
         event.likelihood  = event_dict.get('likelihood', None)
+
+        # Assign analysis-specific attributes
+        event.bci         = event_dict.get('BCI', None)
+        event.quality     = event_dict.get('quality', None)
+        event.bsn         = event_dict.get('BSN', None)
+        event.omicron_snr = event_dict.get('Omicron SNR', None)
+        event.hrss        = event_dict.get('hrss', None)
+        event.frequency   = event_dict.get('frequency', None)
         event.save()
 
     else:
diff --git a/gracedb/view_logic.py b/gracedb/view_logic.py
index a600fbc20..8c6ebfe1d 100644
--- a/gracedb/view_logic.py
+++ b/gracedb/view_logic.py
@@ -7,6 +7,7 @@ from models import CoincInspiralEvent
 from models import MultiBurstEvent
 from models import GrbEvent
 from models import SimInspiralEvent
+from models import LalInferenceBurstEvent
 from models import EMBBEventLog, EMGroup
 from models import EMObservation, EMFootprint
 from alert import issueAlert, issueAlertForLabel, issueAlertForUpdate
@@ -52,6 +53,8 @@ def _createEventFromForm(request, form):
             event = MultiBurstEvent() 
         elif pipeline.name in ['HardwareInjection',]:
             event = SimInspiralEvent()
+        elif pipeline.name in ['LIB',]:
+            event = LalInferenceBurstEvent()
         else:
             event = Event()
 
diff --git a/gracedb/view_utils.py b/gracedb/view_utils.py
index c16abbf63..636d20f3c 100644
--- a/gracedb/view_utils.py
+++ b/gracedb/view_utils.py
@@ -265,6 +265,19 @@ def eventToDict(event, columns=None, request=None):
                   }
         except:
             pass
+        try:
+            # LalInferenceBurstEvent
+            rv['extra_attributes']['LalInferenceBurst'] = {
+                  "bci" : event.bci,
+                  "bsn" : event.bsn,
+                  "quality" : event.quality,
+                  "omicron_snr" : event.omicron_snr,
+                  "hrss" : event.hrss,
+                  "frequency": event.frequency,
+                  }
+        except:
+            pass
+
 
         # Finally add extra attributes for any SingleInspiral objects associated with this event
         # This will be a list of dictionaries.
diff --git a/gracedb/views.py b/gracedb/views.py
index debb97475..f2fdda3a0 100644
--- a/gracedb/views.py
+++ b/gracedb/views.py
@@ -431,6 +431,8 @@ def view(request, event):
         templates.insert(0, 'gracedb/event_detail_CWB.html')
     elif event.pipeline.name in ['HardwareInjection',]:
         templates.insert(0, 'gracedb/event_detail_injection.html')
+    elif event.pipeline.name in ['LIB',]:
+        templates.insert(0, 'gracedb/event_detail_LIB.html')
 
     return render_to_response(templates, context, context_instance=RequestContext(request))
 
diff --git a/templates/gracedb/event_detail_LIB.html b/templates/gracedb/event_detail_LIB.html
new file mode 100644
index 000000000..ef101e9d4
--- /dev/null
+++ b/templates/gracedb/event_detail_LIB.html
@@ -0,0 +1,29 @@
+{% extends "gracedb/event_detail.html" %}
+
+{%load scientific %}
+
+{# Analysis-specific attributes for a cWB event#}
+{% block analysis_specific %}
+<h2>Analysis-Specific Attributes</h2>
+
+<table class="analysis_specific"> <tbody>
+    <tr>
+        <td>  <table class="event"> <tbody>
+                    <tr> <th> BCI </th> <td> {{object.bci|floatformat:"-4"}} </td> </tr>
+                    <tr> <th> BSN </th> <td> {{object.bsn|floatformat:"-4"}} </td> </tr>
+                    <tr> <th> quality </th> <td> {{object.quality|floatformat:"-4"}} </td> </tr>
+              </tbody></table>
+        </td>
+
+
+        <td>  <table class="event"> <tbody>
+                    <tr> <th> frequency </th> <td> {{object.frequency|floatformat:"-4"}} </td> </tr>
+                    <tr> <th> Omicron SNR </th> <td> {{object.omicron_snr|floatformat:"-4"}} </td> </tr>
+                    <tr> <th> hrss </th> <td> {{object.hrss|scientific}} </td> </tr>
+              </tbody></table>
+        </td>
+
+    </tr>
+</tbody> </table> 
+
+{% endblock %}
diff --git a/utils/__init__.py b/utils/__init__.py
index e9ed8276e..3457b897b 100644
--- a/utils/__init__.py
+++ b/utils/__init__.py
@@ -37,7 +37,16 @@ leapSeconds = map(calendar.timegm, [
 def gpsToPosixTime(gpsTime):
     if gpsTime is None:
         return None
-    t = gpsEpoch + gpsTime
+    # XXX
+    # So apparently this gpsTime occasionally comes in as a unicode string.
+    # I am not sure how this is possible, since the gpstime is a django DecimalField,
+    # and it should be a python decimal object. I don't want to cast it to a float unless 
+    # absolutely necessary, hence the try/except block.
+    #t = gpsEpoch + gpsTime
+    try:
+        t = gpsEpoch + gpsTime
+    except:
+        t = gpsEpoch + float(gpsTime)
     for leap in leapSeconds:
         if t >= leap:
             t = t - 1
-- 
GitLab