diff --git a/gracedb/models.py b/gracedb/models.py index 8b352ce6f2f6678eb6c45383d97a2d592736c5f7..d4629b170630b5c8b3187dc38b5fd0f5842e0f67 100644 --- a/gracedb/models.py +++ b/gracedb/models.py @@ -1,6 +1,8 @@ from django.db import models from django.core.urlresolvers import reverse +from model_utils.managers import InheritanceManager + import datetime import thread import string @@ -49,6 +51,9 @@ class Label(models.Model): return self.name class Event(models.Model): + + objects = InheritanceManager() # Queries can return subclasses, if available. + ANALYSIS_TYPE_CHOICES = ( ("LM", "LowMass"), ("HM", "HighMass"), @@ -149,7 +154,10 @@ class Event(models.Model): @classmethod def getByGraceid(cls, id): - e = cls.objects.get(id=int(id[1:])) + try: + e = cls.objects.filter(id=int(id[1:])).select_subclasses()[0] + except IndexError: + raise cls.DoesNotExist("Event matching query does not exist") if (id[0] == "T") and (e.group.name == "Test"): return e if (id[0] == "H") and (e.analysisType == "HWINJ"): @@ -158,7 +166,7 @@ class Event(models.Model): return e if (id[0] == "G"): return e - raise cls.DoesNotExist() + raise cls.DoesNotExist("Event matching query does not exist") def __unicode__(self): return self.graceid() @@ -198,6 +206,40 @@ class Approval(models.Model): approvedEvent = models.ForeignKey(Event, null=False) approvingCollaboration = models.CharField(max_length=1, choices=COLLABORATION_CHOICES) +## Analysis Specific Attributes. + +class CoincInspiralEvent(Event): + ifos = models.CharField(max_length=20, default="") + end_time = models.PositiveIntegerField(null=True) + end_time_ns = models.PositiveIntegerField(null=True) + mass = models.FloatField(null=True) + mchirp = models.FloatField(null=True) + minimum_duration = models.FloatField(null=True) + snr = models.FloatField(null=True) + false_alarm_rate = models.FloatField(null=True) + combined_far = models.FloatField(null=True) + + +class MultiBurstEvent(Event): + ifos = models.CharField(max_length=20, default="") + start_time = models.PositiveIntegerField(null=True) + start_time_ns = models.PositiveIntegerField(null=True) + duration = models.FloatField(null=True) + peak_time = models.PositiveIntegerField(null=True) + peak_time_ns = models.PositiveIntegerField(null=True) + central_freq = models.FloatField(null=True) + bandwidth = models.FloatField(null=True) + amplitude = models.FloatField(null=True) + snr = models.FloatField(null=True) + confidence = models.FloatField(null=True) + false_alarm_rate = models.FloatField(null=True) + ligo_axis_ra = models.FloatField(null=True) + ligo_axis_dec = models.FloatField(null=True) + ligo_angle = models.FloatField(null=True) + ligo_angle_sig = models.FloatField(null=True) + +## Slots (user-defined event attributes) + class Slot(models.Model): """Slot Model""" # Does the slot need to have a submitter column? diff --git a/gracedb/translator.py b/gracedb/translator.py index 80a57c1bf937884d65ee4fde451ebd7738e4aa2c..0739dc04f3422ed888395618064bf465270e0676 100644 --- a/gracedb/translator.py +++ b/gracedb/translator.py @@ -105,6 +105,16 @@ def handle_uploaded_data(event, datafilename, event.nevents = coinc_table[0].nevents event.likelihood = coinc_table[0].likelihood + event.ifos = ifos + event.end_time = end_time[0] + event.end_time_ns = end_time[1] + event.mass = mass + event.mchirp = mchirp + event.minimum_duration = getattr(origdata[0][0], "minimum_duration", None) + event.snr = snr + event.false_alarm_rate = getattr(origdata[0][0], "false_alarm_rate", None) + event.combined_far = far + # XXX xml_filename unused #xml_filename = os.path.join(output_dir, coinc_table_filename) @@ -211,6 +221,21 @@ def handle_uploaded_data(event, datafilename, event.nevents = coinc_table[0].nevents event.likelihood = coinc_table[0].likelihood + # extended attributes + coinc_inspiral_table = glue.ligolw.table.getTablesByName( + xmldoc, + glue.ligolw.lsctables.CoincInspiralTable.tableName) + coinc_inspiral_table = coinc_inspiral_table[0] + event.ifos = coinc_inspiral_table[0].ifos + event.end_time = coinc_inspiral_table[0].end_time + event.end_time_ns = coinc_inspiral_table[0].end_time_ns + event.mass = coinc_inspiral_table[0].mass + event.mchirp = coinc_inspiral_table[0].mchirp + #event.minimum_duration = coinc_inspiral_table[0].minimum_duration + event.snr = coinc_inspiral_table[0].snr + event.false_alarm_rate = coinc_inspiral_table[0].false_alarm_rate + event.combined_far = coinc_inspiral_table[0].combined_far + # XXX xml_filename unused #xml_filename = os.path.join(output_dir, coinc_table_filename) @@ -287,18 +312,6 @@ def handle_uploaded_data(event, datafilename, comment="Log File Created" ) log.save() - elif event.analysisType == 'HWINJ': - try: - f = open(datafilename, "r") - for line in f.readlines(): - if line.startswith("gpstime:"): - times = line.split() - event.gpstime = int(float(times[1])) - event.save() - break - f.close() - except: - pass elif event.analysisType == 'GRB': # Get the event time from the VOEvent file try: @@ -351,8 +364,6 @@ class Translator(object): event.instruments = data.get('instruments') event.far = data.get('far') - event.save() - def logData(self): data = self.getData() logdata = [] @@ -400,6 +411,21 @@ class CwbData(Translator): self.castData(data) return self.data + def populateEvent(self, event): + Translator.populateEvent(self, event) + + # MultiBurst table attributes + data = self.getData() + event.ifo = data.get('ifo') + event.start_time = data.get('start_time') + event.start_time_ns = data.get('start_time_ns') + event.duration = data.get('duration') + event.central_freq = data.get('central_freq') + event.bandwidth = data.get('bandwidth') + event.snr = data.get('snr') + event.ligo_axis_ra = data.get('ligo_axis_ra') + event.ligo_axis_dec = data.get('ligo_axis_dec') + def readData(self, datafile): needToClose = False if isinstance(datafile, str) or isinstance(datafile, unicode): @@ -459,6 +485,26 @@ class CwbData(Translator): ifos.sort() data['instruments'] = ','.join(ifos) + # MultiBurst table attributes + start = rawdata.get('start',[None])[0] + if start is not None: + integer, frac = start.split('.') + data['start_time'] = int(integer) + data['start_time_ns'] = int(frac+(9-len(frac))*'0') + else: + data['start_time'] = None + data['start_time_ns'] = None + + data['ifo'] = ','.join(ifos) + data['duration'] = rawdata.get('duration',[None])[0] + data['central_freq'] = rawdata.get('frequency',[None])[0] + data['bandwidth'] = rawdata.get('bandwidth',[None])[0] + #data['snr'] = rawdata.get('snr',[None])[0] + # rho is what log file says is "effective snr" + data['snr'] = data['rawdata'].get('rho',[None])[0] + data['ligo_axis_ra'] = data['rawdata'].get('phi',[None,None,None])[2] + data['ligo_axis_dec'] = data['rawdata'].get('theta',[None,None,None])[2] + if needToClose: datafile.close() diff --git a/gracedb/views.py b/gracedb/views.py index 7568abb00b160cc9caed0de8bd1c0bc33059d2b8..9515fc37ee5dc821e13c9dc5b402fb44c2657dc5 100644 --- a/gracedb/views.py +++ b/gracedb/views.py @@ -11,6 +11,8 @@ from django.utils.safestring import mark_safe from django.views.generic.list_detail import object_detail, object_list from models import Event, Group, EventLog, Labelling, Label, User +from models import CoincInspiralEvent +from models import MultiBurstEvent from forms import CreateEventForm, EventSearchForm, SimpleSearchForm from alert import issueAlert, issueAlertForLabel, issueAlertForUpdate from translator import handle_uploaded_data @@ -201,12 +203,17 @@ def _createEventFromForm(request, form): warnings = [] try: group = Group.objects.filter(name=form.cleaned_data['group']) - type = form.cleaned_data['type'] + atype = form.cleaned_data['type'] # Create Event - event = Event() + if atype in ['LM', 'HM', 'MBTA']: + event = CoincInspiralEvent() + elif atype == "CWB": + event = MultiBurstEvent() + else: + event = Event() event.submitter = request.ligouser event.group = group[0] - event.analysisType = type + event.analysisType = atype # ARGH. We don't get a graceid until we save, # but we don't know in advance if we can actually # create all the things we need for success! @@ -531,7 +538,8 @@ def view(request, graceid): for event in a.neighbors()] context['skyalert_authorized'] = skyalert_authorized(request) return render_to_response( - 'gracedb/event_detail.html', + [ 'gracedb/event_detail_{0}.html'.format(a.analysisType), + 'gracedb/event_detail.html'], context, context_instance=RequestContext(request)) diff --git a/utils/vfile.py b/utils/vfile.py index b733e9ce1a1074f79984f79d44a4c069f45862cb..eeadd523f0e9bec77805759e70f734b8cb93fac6 100644 --- a/utils/vfile.py +++ b/utils/vfile.py @@ -106,7 +106,7 @@ class VersionedFile(file): os.close(fd) break except OSError, e: - if e.error != errno.EEXIST: + if e.errno != errno.EEXIST: raise version += 1 failedAttempts += 1