diff --git a/gracedb/api.py b/gracedb/api.py index 40d14484c25db1f2dc83b3af694b03a249add6f4..57c49600266f2a25b46493ed81c5b799582937d2 100644 --- a/gracedb/api.py +++ b/gracedb/api.py @@ -14,13 +14,16 @@ from django.contrib.auth.models import Group as AuthGroup from django.contrib.contenttypes.models import ContentType from gracedb.models import Event, Group, Search, Pipeline, EventLog, Tag from gracedb.models import EMGroup, EMBBEventLog, EMSPECTRUM +#from gracedb.models import EMObservation, EMFootprint from gracedb.models import VOEvent from view_logic import create_label, get_performance_info from view_logic import _createEventFromForm from view_logic import create_eel +from view_logic import create_emobservation from view_utils import fix_old_creation_request from view_utils import eventToDict, eventLogToDict, labelToDict from view_utils import embbEventLogToDict, voeventToDict +from view_utils import emObservationToDict from view_utils import reverse from translator import handle_uploaded_data @@ -898,6 +901,77 @@ class EMBBEventLogDetail(APIView): return Response(embbEventLogToDict(rv, request=request)) + +#================================================================== +# EMObservation (EMO) + +class EMObservationList(APIView): + """EMObservation Record List Resource + + POST param 'message' + """ + authentication_classes = (LigoAuthentication,) + permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) + + @event_and_auth_required + def get(self, request, event): + emo_set = event.emobservation_set.order_by("created","N") + count = emo_set.count() + + emo = [ emObservationToDict(emo, request) + for emo in emo_set.iterator() ] + + rv = { + 'start': 0, + 'numRows' : count, + 'links' : { + 'self' : request.build_absolute_uri(), + 'first' : request.build_absolute_uri(), + 'last' : request.build_absolute_uri(), + }, + 'observations' : emo, + } + return Response(rv) + + @event_and_auth_required + def post(self, request, event): + try: + emo = create_emobservation(request.DATA, event, request.user) + except ValueError, e: + return Response("%s" % str(e), status=status.HTTP_400_BAD_REQUEST) + except IntegrityError, e: + return Response("Failed to save EMBB observation record: %s" % str(e), + status=status.HTTP_503_SERVICE_UNAVAILABLE) + except Exception, e: + return Response("Problem creating EMBB Observation: %s" % str(e), + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + rv = emObservationToDict(emo, request=request) + response = Response(rv, status=status.HTTP_201_CREATED) + response['Location'] = rv['self'] + + # Issue alert. + description = "New EMBB observation record." + issueAlertForUpdate(event, description, doxmpp=True, + filename="", serialized_object=rv) + + return response + +class EMObservationDetail(APIView): + authentication_classes = (LigoAuthentication,) + permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) + + @event_and_auth_required + def get(self, request, event, n): + try: + rv = event.emobservation_set.filter(N=n)[0] + except: + return Response("Observation record not nound", + status=status.HTTP_404_NOT_FOUND) + + return Response(emObservationToDict(rv, request=request)) + + #================================================================== # Tags @@ -1292,6 +1366,8 @@ class GracedbRoot(APIView): voevent = voevent.replace("G1200", "{graceid}") embb = reverse("embbeventlog-list", args=["G1200"], request=request) embb = embb.replace("G1200", "{graceid}") + emo = reverse("emobservation-list", args=["G1200"], request=request) + emo = emo.replace("G1200", "{graceid}") files = reverse("files", args=["G1200", "filename"], request=request) files = files.replace("G1200", "{graceid}") @@ -1320,6 +1396,7 @@ class GracedbRoot(APIView): "event-detail-template" : detail, "voevent-list-template" : voevent, "event-log-template" : log, + "emobservation-list-template": emo, "embb-event-log-template" : embb, "event-label-template" : labels, "files-template" : files, diff --git a/gracedb/migrations/0039_auto__add_emobservation__add_unique_emobservation_event_N__add_emfootp.py b/gracedb/migrations/0039_auto__add_emobservation__add_unique_emobservation_event_N__add_emfootp.py new file mode 100644 index 0000000000000000000000000000000000000000..66fcae90abb273432a5aca847002c34eb38a496a --- /dev/null +++ b/gracedb/migrations/0039_auto__add_emobservation__add_unique_emobservation_event_N__add_emfootp.py @@ -0,0 +1,356 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'EMObservation' + db.create_table(u'gracedb_emobservation', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('N', self.gf('django.db.models.fields.IntegerField')()), + ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gracedb.Event'])), + ('submitter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gracedb.EMGroup'])), + ('ra', self.gf('django.db.models.fields.FloatField')(null=True)), + ('dec', self.gf('django.db.models.fields.FloatField')(null=True)), + ('raWidth', self.gf('django.db.models.fields.FloatField')(null=True)), + ('decWidth', self.gf('django.db.models.fields.FloatField')(null=True)), + )) + db.send_create_signal(u'gracedb', ['EMObservation']) + + # Adding unique constraint on 'EMObservation', fields ['event', 'N'] + db.create_unique(u'gracedb_emobservation', ['event_id', 'N']) + + # Adding model 'EMFootprint' + db.create_table(u'gracedb_emfootprint', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('N', self.gf('django.db.models.fields.IntegerField')()), + ('observation', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gracedb.EMObservation'])), + ('ra', self.gf('django.db.models.fields.FloatField')()), + ('dec', self.gf('django.db.models.fields.FloatField')()), + ('raWidth', self.gf('django.db.models.fields.FloatField')()), + ('decWidth', self.gf('django.db.models.fields.FloatField')()), + ('start_time', self.gf('django.db.models.fields.DateTimeField')()), + ('exposure_time', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal(u'gracedb', ['EMFootprint']) + + # Adding unique constraint on 'EMFootprint', fields ['observation', 'N'] + db.create_unique(u'gracedb_emfootprint', ['observation_id', 'N']) + + + def backwards(self, orm): + # Removing unique constraint on 'EMFootprint', fields ['observation', 'N'] + db.delete_unique(u'gracedb_emfootprint', ['observation_id', 'N']) + + # Removing unique constraint on 'EMObservation', fields ['event', 'N'] + db.delete_unique(u'gracedb_emobservation', ['event_id', 'N']) + + # Deleting model 'EMObservation' + db.delete_table(u'gracedb_emobservation') + + # Deleting model 'EMFootprint' + db.delete_table(u'gracedb_emfootprint') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.approval': { + 'Meta': {'object_name': 'Approval'}, + 'approvedEvent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'approvingCollaboration': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'gracedb.coincinspiralevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'CoincInspiralEvent', '_ormbases': [u'gracedb.Event']}, + 'combined_far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'mass': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'minimum_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.embbeventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMBBEventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'durationList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'eel_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'extra_info_dict': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'footprintID': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'gpstimeList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instrument': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'obs_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'waveband': ('django.db.models.fields.CharField', [], {'max_length': '25'}) + }, + u'gracedb.emfootprint': { + 'Meta': {'ordering': "['-N']", 'unique_together': "(('observation', 'N'),)", 'object_name': 'EMFootprint'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'dec': ('django.db.models.fields.FloatField', [], {}), + 'decWidth': ('django.db.models.fields.FloatField', [], {}), + 'exposure_time': ('django.db.models.fields.PositiveIntegerField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'observation': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMObservation']"}), + 'ra': ('django.db.models.fields.FloatField', [], {}), + 'raWidth': ('django.db.models.fields.FloatField', [], {}), + 'start_time': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'gracedb.emgroup': { + 'Meta': {'object_name': 'EMGroup'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.emobservation': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMObservation'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.event': { + 'Meta': {'ordering': "['-id']", 'object_name': 'Event'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'gpstime': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '16', 'decimal_places': '6'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instruments': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'labels': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.Label']", 'through': u"orm['gracedb.Labelling']", 'symmetrical': 'False'}), + 'likelihood': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'nevents': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'perms': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pipeline': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Pipeline']"}), + 'search': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Search']", 'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.eventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.grbevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'GrbEvent', '_ormbases': [u'gracedb.Event']}, + 'author_ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'author_shortname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'coord_system': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error_radius': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'how_description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'how_reference_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}), + 'ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'observatory_location_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + u'gracedb.label': { + 'Meta': {'object_name': 'Label'}, + 'defaultColor': ('django.db.models.fields.CharField', [], {'default': "'black'", 'max_length': '20'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.labelling': { + 'Meta': {'object_name': 'Labelling'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Label']"}) + }, + u'gracedb.multiburstevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'MultiBurstEvent', '_ormbases': [u'gracedb.Event']}, + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bandwidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'central_freq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'confidence': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'ligo_angle': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_angle_sig': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'peak_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'peak_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'start_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'start_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}) + }, + u'gracedb.pipeline': { + 'Meta': {'object_name': 'Pipeline'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.search': { + 'Meta': {'object_name': 'Search'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.singleinspiral': { + 'Gamma0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma7': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma8': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma9': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Meta': {'object_name': 'SingleInspiral'}, + 'alpha': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'beta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'chi': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'coa_phase': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eff_distance': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'end_time_gmst': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'event_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'f_final': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ifo': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'impulse_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'impulse_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'kappa': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mtotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'rsqveto_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'search': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'sigmasq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'template_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ttotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.tag': { + 'Meta': {'object_name': 'Tag'}, + 'displayName': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'eventlogs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.EventLog']", 'symmetrical': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.voevent': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'VOEvent'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'ivorn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200'}), + 'voevent_type': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + } + } + + complete_apps = ['gracedb'] \ No newline at end of file diff --git a/gracedb/migrations/0040_migrate_eels_to_observations.py b/gracedb/migrations/0040_migrate_eels_to_observations.py new file mode 100644 index 0000000000000000000000000000000000000000..52482ee39b96d010911ed9fbb7b105a5afd2e299 --- /dev/null +++ b/gracedb/migrations/0040_migrate_eels_to_observations.py @@ -0,0 +1,433 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models +import json +from utils import gpsToUtc + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Don't use "from appname.models import ModelName". + # Use orm.ModelName to refer to models in this application, + # and orm['appname.ModelName'] for models in other applications. + + # Loop through these by event so that the numbering will + # be correct + + for event in orm.Event.objects.all(): + for eel in event.embbeventlog_set.all(): + # We only want to do this for things that really have a footprint. + if not eel.raList: + continue + if eel.eel_status == 'FO': + # Create the new observation object with common fields. + obs = orm.EMObservation.objects.create( + N = eel.N, + created = eel.created, + event = event, + submitter = eel.submitter, + group = eel.group) + + # Next, work on the footprints. + # Much code here lifted from validateMakeRects + # get all the list based position and times and their widths + raRealList = [] + rawRealList = [] + # add a [ and ] to convert the input csv list to a json parsable text + + if eel.raList: raRealList = json.loads('['+eel.raList+']') + if eel.raWidthList: rawRealList = json.loads('['+eel.raWidthList+']') + + if eel.decList: decRealList = json.loads('['+eel.decList+']') + if eel.decWidthList: decwRealList = json.loads('['+eel.decWidthList+']') + + if eel.gpstimeList: gpstimeRealList = json.loads('['+eel.gpstimeList+']') + if eel.durationList: durationRealList = json.loads('['+eel.durationList+']') + + error_msg = "Cannot use EEL %d for event %s: " % (eel.N, event.id) + + # is there anything in the ra list? + nList = len(raRealList) + if nList > 0: + if decRealList and len(decRealList) != nList: + print error_msg + 'RA and Dec lists are different lengths.' + continue + if gpstimeRealList and len(gpstimeRealList) != nList: + print error_msg + 'RA and GPS lists are different lengths.' + continue + + # is there anything in the raWidth list? + mList = len(rawRealList) + if mList > 0: + if decwRealList and len(decwRealList) != mList: + print error_msg + 'RAwidth and Decwidth lists are different lengths.' + continue + if durationRealList and len(durationRealList) != mList: + print error_msg + 'RAwidth and Duration lists are different lengths.' + continue + + # There can be 1 width for the whole list, or one for each ra/dec/gps + if mList != 1 and mList != nList: + print error_msg + 'Width and duration lists must be length 1 or same length as coordinate lists' + continue + else: + mList = 0 + + for i in range(nList): + try: + ra = float(raRealList[i]) + except: + print error_msg +'Cannot read RA list element %d of %s'%(i, eel.raList) + continue + try: + dec = float(decRealList[i]) + except: + print error_msg +'Cannot read Dec list element %d of %s'%(i, eel.decList) + continue + try: + gps = int(gpstimeRealList[i]) + except: + print error_msg +'Cannot read GPStime list element %d of %s'%(i, eel.gpstimeList) + continue + + # the widths list can have 1 member to cover all, or one for each + if mList==1: j=0 + else : j=i + + try: + raWidth = float(rawRealList[j]) + except: + print error_msg +'Cannot read raWidth list element %d of %s'%(i, eel.raWidthList) + continue + + try: + decWidth = float(decwRealList[j]) + except: + print error_msg +'Cannot read raWidth list element %d of %s'%(i, eel.decWidthList) + continue + + try: + duration = int(durationRealList[j]) + except: + print error_msg +'Cannot read duration list element %d of %s'%(i, eel.durationList) + continue + + # Now calculate the start time + start_gps = gps - duration/2.0 + start_time = gpsToUtc(start_gps) + + # Create footprint object + orm.EMFootprint.objects.create(N=i, observation=obs, ra=ra, dec=dec, + raWidth=raWidth, decWidth=decWidth, start_time=start_time, + exposure_time=duration) + + # This has to do be done in a management command, since South cannot re-create these + # custom methods. + # Calculate covering region for observation + #obs.calculateCoveringRegion() + # XXX Save method should not increment N + #obs.save() + + def backwards(self, orm): + "Write your backwards methods here." + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.approval': { + 'Meta': {'object_name': 'Approval'}, + 'approvedEvent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'approvingCollaboration': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'gracedb.coincinspiralevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'CoincInspiralEvent', '_ormbases': [u'gracedb.Event']}, + 'combined_far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'mass': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'minimum_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.embbeventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMBBEventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'durationList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'eel_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'extra_info_dict': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'footprintID': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'gpstimeList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instrument': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'obs_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'waveband': ('django.db.models.fields.CharField', [], {'max_length': '25'}) + }, + u'gracedb.emfootprint': { + 'Meta': {'ordering': "['-N']", 'unique_together': "(('observation', 'N'),)", 'object_name': 'EMFootprint'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'dec': ('django.db.models.fields.FloatField', [], {}), + 'decWidth': ('django.db.models.fields.FloatField', [], {}), + 'exposure_time': ('django.db.models.fields.PositiveIntegerField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'observation': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMObservation']"}), + 'ra': ('django.db.models.fields.FloatField', [], {}), + 'raWidth': ('django.db.models.fields.FloatField', [], {}), + 'start_time': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'gracedb.emgroup': { + 'Meta': {'object_name': 'EMGroup'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.emobservation': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMObservation'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.event': { + 'Meta': {'ordering': "['-id']", 'object_name': 'Event'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'gpstime': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '16', 'decimal_places': '6'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instruments': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'labels': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.Label']", 'through': u"orm['gracedb.Labelling']", 'symmetrical': 'False'}), + 'likelihood': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'nevents': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'perms': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pipeline': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Pipeline']"}), + 'search': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Search']", 'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.eventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.grbevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'GrbEvent', '_ormbases': [u'gracedb.Event']}, + 'author_ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'author_shortname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'coord_system': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error_radius': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'how_description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'how_reference_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}), + 'ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'observatory_location_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + u'gracedb.label': { + 'Meta': {'object_name': 'Label'}, + 'defaultColor': ('django.db.models.fields.CharField', [], {'default': "'black'", 'max_length': '20'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.labelling': { + 'Meta': {'object_name': 'Labelling'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Label']"}) + }, + u'gracedb.multiburstevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'MultiBurstEvent', '_ormbases': [u'gracedb.Event']}, + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bandwidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'central_freq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'confidence': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'ligo_angle': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_angle_sig': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'peak_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'peak_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'start_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'start_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}) + }, + u'gracedb.pipeline': { + 'Meta': {'object_name': 'Pipeline'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.search': { + 'Meta': {'object_name': 'Search'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.singleinspiral': { + 'Gamma0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma7': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma8': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma9': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Meta': {'object_name': 'SingleInspiral'}, + 'alpha': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'beta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'chi': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'coa_phase': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eff_distance': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'end_time_gmst': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'event_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'f_final': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ifo': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'impulse_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'impulse_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'kappa': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mtotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'rsqveto_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'search': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'sigmasq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'template_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ttotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.tag': { + 'Meta': {'object_name': 'Tag'}, + 'displayName': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'eventlogs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.EventLog']", 'symmetrical': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.voevent': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'VOEvent'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'ivorn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200'}), + 'voevent_type': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + } + } + + complete_apps = ['gracedb'] + symmetrical = True diff --git a/gracedb/models.py b/gracedb/models.py index 210caea14783dfe60c9013bcff999d893470d506..2d7daa84c90d6cf3925a21948d5c317c334919a6 100644 --- a/gracedb/models.py +++ b/gracedb/models.py @@ -396,6 +396,153 @@ EMSPECTRUM = ( ('em.radio.20-100MHz', 'Radio between 20 and 100 MHz'), ) +class EMObservation(models.Model): + """ + EMObservation: An observation record for EM followup. + """ + class Meta: + ordering = ['-created', '-N'] + unique_together = ("event","N") + + def __unicode__(self): + return "%s-%s-%d" % (self.event.graceid(), self.group.name, self.N) + + N = models.IntegerField(null=False) + created = models.DateTimeField(auto_now_add=True) + event = models.ForeignKey(Event) + submitter = models.ForeignKey(DjangoUser) + + # The MOU group responsible + group = models.ForeignKey(EMGroup) # from a table of facilities + + # The following fields should be calculated from the footprint info provided + # by the user. These fields are just for convenience and fast searching + + # The center of the bounding box of the rectangular footprints ra,dec + # in J2000 in decimal degrees + ra = models.FloatField(null=True) + dec = models.FloatField(null=True) + + # The width and height (RA range and Dec range) in decimal degrees + raWidth = models.FloatField(null=True) + decWidth = models.FloatField(null=True) + + # We overload the 'save' method to avoid race conditions, since the Eels are numbered. + def save(self, *args, **kwargs): + success = False + attempts = 0 + while (not success and attempts < 5): + attempts = attempts + 1 + # If I've already got an N assigned, let's not assign another. + if not self.N: + if self.event.emobservation_set.count(): + self.N = int(self.event.emobservation_set.aggregate(models.Max('N'))['N__max']) + 1 + else: + self.N = 1 + try: + super(EMObservation, self).save(*args, **kwargs) + success = True + except IntegrityError: + # IntegrityError means an attempt to insert a duplicate + # key or to violate a foreignkey constraint. + # We are under race conditions. Let's try again. + pass + + if not success: + # XXX Should this be a custom exception? That way we could catch it + # in the views that use it and give an informative error message. + raise Exception("Too many attempts to save EMObservation entry. Something is wrong.") + + def calculateCoveringRegion(self): + # How to access the related footprint objects? + footprints = self.emfootprint_set.all() + if not footprints: + return + + ramin = 360.0 + ramax = 0.0 + decmin = 90.0 + decmax = -90.0 + + for f in footprints: + + # evaluate bounding box + w = float(f.raWidth)/2 + if f.ra-w < ramin: ramin = f.ra-w + if f.ra+w > ramax: ramax = f.ra+w + + w = float(f.decWidth)/2 + if f.dec-w < decmin: decmin = f.dec-w + if f.dec+w > decmax: decmax = f.dec+w + + # Make sure the min/max ra and dec are within bounds: + ramin = max(0.0, ramin) + ramax = min(360.0, ramax) + decmin = max(-90.0, decmin) + decmax = min(90.0, decmax) + + # Calculate sky rectangle bounds + self.ra = (ramin + ramax)/2 + self.dec = (decmin + decmax)/2 + self.raWidth = ramax-ramin + self.decWidth = decmax-decmin + +class EMFootprint(models.Model): + """ + A single footprint associated with an observation. + Each EMObservation can have many footprints underneath. + + None of the fields are optional here. + """ + class Meta: + ordering = ['-N'] + unique_together = ("observation","N") + + N = models.IntegerField(null=False) + + observation = models.ForeignKey(EMObservation, null = False) + + # The center of the rectangular footprint, right ascension and declination + # in J2000 in decimal degrees + ra = models.FloatField() + dec = models.FloatField() + + # The width and height (RA range and Dec range) in decimal degrees + raWidth = models.FloatField() + decWidth = models.FloatField() + + # The start time of the observation for this footprint + start_time = models.DateTimeField() + + # The exposure time in seconds for this footprint + exposure_time = models.PositiveIntegerField() + + # We overload the 'save' method to avoid race conditions, since the Eels are numbered. + def save(self, *args, **kwargs): + success = False + attempts = 0 + while (not success and attempts < 5): + attempts = attempts + 1 + # If I've already got an N assigned, let's not assign another. + if not self.N: + if self.observation.emfootprint_set.count(): + self.N = int(self.observation.emfootprint_set.aggregate(models.Max('N'))['N__max']) + 1 + else: + self.N = 1 + try: + super(EMFootprint, self).save(*args, **kwargs) + success = True + except IntegrityError: + # IntegrityError means an attempt to insert a duplicate + # key or to violate a foreignkey constraint. + # We are under race conditions. Let's try again. + pass + + if not success: + # XXX Should this be a custom exception? That way we could catch it + # in the views that use it and give an informative error message. + raise Exception("Too many attempts to save Footprint. Something is wrong.") + class EMBBEventLog(models.Model): """EMBB EventLog: A multi-purpose annotation for EM followup. diff --git a/gracedb/urls_rest.py b/gracedb/urls_rest.py index 1f12d8f5da1e6b2b3624cd9bde148caee45cff0c..2ed93e93be997be2dfb249be918f55400aefedbf 100644 --- a/gracedb/urls_rest.py +++ b/gracedb/urls_rest.py @@ -8,6 +8,8 @@ from gracedb.api import GracedbRoot from gracedb.api import EventList, EventDetail from gracedb.api import EventLogList, EventLogDetail from gracedb.api import EMBBEventLogList, EMBBEventLogDetail +from gracedb.api import EMObservationList, EMObservationDetail +#from gracedb.api import EMFootprintList, EMFootprintDetail from gracedb.api import TagList # from gracedb.api import TagDetail from gracedb.api import EventTagList, EventTagDetail @@ -46,12 +48,20 @@ urlpatterns = patterns('gracedb.api', url (r'events/(?P<graceid>[GEHMT]\d+)/voevent/(?P<n>\d+)$', VOEventDetail.as_view(), name='voevent-detail'), - # EMBB Event Log Resources + # EMBB Resources # events/{graceid}/logs/[{logid}] url (r'events/(?P<graceid>[GEHMT]\d+)/embb/$', EMBBEventLogList.as_view(), name='embbeventlog-list'), url (r'events/(?P<graceid>[GEHMT]\d+)/embb/(?P<n>\d+)$', EMBBEventLogDetail.as_view(), name='embbeventlog-detail'), + url (r'events/(?P<graceid>[GEHMT]\d+)/emobservation/$', + EMObservationList.as_view(), name='emobservation-list'), + url (r'events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)$', + EMObservationDetail.as_view(), name='emobservation-detail'), +# url (r'events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/$', +# EMFootprintList.as_view(), name='emfootprint-list'), +# url (r'events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/(?P<m>\d+)$', +# EMFootprintDetail.as_view(), name='emfootprint-detail'), # Tag Resources url (r'^tag/$', diff --git a/gracedb/view_logic.py b/gracedb/view_logic.py index dddf6f8d0144fa8ba9f3020ce4bd65a19b97adf6..2868f54ab88a1c85ab9ab024dd93f8c33c623fca 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 EMBBEventLog, EMGroup +from models import EMObservation, EMFootprint from alert import issueAlert, issueAlertForLabel, issueAlertForUpdate from translator import handle_uploaded_data @@ -25,6 +26,7 @@ from django.conf import settings import json import datetime +import dateutil def _createEventFromForm(request, form): saved = False @@ -365,3 +367,117 @@ def create_eel(d, event, user): eel.validateMakeRects() eel.save() return eel + +# +# Create an EMBB Observaton Record +# +def create_emobservation(d, event, user): + # create a log entry + emo = EMObservation(event=event) + emo.event = event + emo.submitter = user + # Assign a group name + try: + emo.group = EMGroup.objects.get(name=d.get('group')) + except: + raise ValueError('Please specify an EM followup MOU group') + + # Must do this so as to have an id. + emo.save() + + # Assign RA and Dec, plus widths + raList = d.get('raList', '') + raWidthList = d.get('raWidthList', '') + + decList = d.get('decList', '') + decWidthList = d.get('decWidthList', '') + + startTimeList = d.get('startTimeList', '') + durationList = d.get('durationList', '') + + # Much code here lifted from EMBBEventLog.validateMakeRects + # get all the list based position and times and their widths + raRealList = [] + rawRealList = [] + # add a [ and ] to convert the input csv list to a json parsable text + + if raList: raRealList = json.loads('['+raList+']') + if raWidthList: rawRealList = json.loads('['+raWidthList+']') + + if decList: decRealList = json.loads('['+decList+']') + if decWidthList: decwRealList = json.loads('['+decWidthList+']') + + # this will actually be a list of ISO times in double quotes + if startTimeList: startTimeRealList = json.loads('['+startTimeList+']') + if durationList: durationRealList = json.loads('['+durationList+']') + + # is there anything in the ra list? + nList = len(raRealList) + if nList > 0: + if decRealList and len(decRealList) != nList: + raise ValueError('RA and Dec lists are different lengths.') + if startTimeRealList and len(startTimeRealList) != nList: + raise ValueError('RA and start time lists are different lengths.') + + # is there anything in the raWidth list? + mList = len(rawRealList) + if mList > 0: + if decwRealList and len(decwRealList) != mList: + raise ValueError('RAwidth and Decwidth lists are different lengths.') + if durationRealList and len(durationRealList) != mList: + raise ValueError('RAwidth and Duration lists are different lengths.') + + # There can be 1 width for the whole list, or one for each ra/dec/gps + if mList != 1 and mList != nList: + raise ValueError('Width and duration lists must be length 1 or same length as coordinate lists') + else: + mList = 0 + + for i in range(nList): + try: + ra = float(raRealList[i]) + except: + raise ValueError('Cannot read RA list element %d of %s'%(i, emo.raList)) + try: + dec = float(decRealList[i]) + except: + raise ValueError('Cannot read Dec list element %d of %s'%(i, emo.decList)) + try: + start_time = startTimeRealList[i] + except: + raise ValueError('Cannot read GPStime list element %d of %s'%(i, emo.startTimeList)) + + # the widths list can have 1 member to cover all, or one for each + if mList==1: j=0 + else : j=i + + try: + raWidth = float(rawRealList[j]) + except: + raise ValueError('Cannot read raWidth list element %d of %s'%(i, emo.raWidthList)) + + try: + decWidth = float(decwRealList[j]) + except: + raise ValueError('Cannot read raWidth list element %d of %s'%(i, emo.decWidthList)) + + try: + duration = int(durationRealList[j]) + except: + raise ValueError('Cannot read duration list element %d of %s'%(i, emo.durationList)) + + try: + start_time = dateutil.parser.parse(start_time) + except: + raise ValueError('Could not parse start time list element %d of %s'%(i, emo.durationList)) + + + # Create footprint object + EMFootprint.objects.create(observation=emo, ra=ra, dec=dec, + raWidth=raWidth, decWidth=decWidth, start_time=start_time, + exposure_time=duration) + + # Calculate covering region for observation + emo.calculateCoveringRegion() + emo.save() + return emo diff --git a/gracedb/view_utils.py b/gracedb/view_utils.py index 457ab42e7c31453738e326ebcd39e7ccdf1dd26b..0ece02cff172865575d56d9048194dacaff48d87 100644 --- a/gracedb/view_utils.py +++ b/gracedb/view_utils.py @@ -283,6 +283,50 @@ def embbEventLogToDict(eel, request=None): "comment" : eel.comment, "extra_info_dict" : eel.extra_info_dict, } + +# EMObservation serializer. +def emObservationToDict(emo, request=None): + uri = None + if request: + uri = reverse("emobservation-detail", + args=[emo.event.graceid(), emo.N], + request=request) + + return { + "N" : emo.N, + "footprint_count" : emo.emfootprint_set.count(), + "self" : uri, + "created" : emo.created.isoformat(), + "submitter" : emo.submitter.username, + "group" : emo.group.name, + + "ra" : emo.ra, + "dec" : emo.dec, + "raWidth" : emo.raWidth, + "decWidth" : emo.decWidth, + "footprints" : [ emFootprintToDict(emf) for emf in emo.emfootprint_set.all()] + } + +# EMFootprint serializer +def emFootprintToDict(emf, request=None): +# uri = None +# if request: +# uri = reverse("emfootprint-detail", +# args=[emf.emobservation.event.graceid(), emf.emobservation.N, emf.N], +# request=request) + + return { +# FIXME: At this point, we're not exposing the individual footprints. +# It would probably be nice to expose these resources, at least to GET. +# "self" : uri, + "N" : emf.N, + "ra" : emf.ra, + "dec" : emf.dec, + "raWidth" : emf.raWidth, + "decWidth" : emf.decWidth, + "start_time" : emf.start_time.isoformat(), + "exposure_time" : emf.exposure_time, + } # VOEvent serializer def voeventToDict(voevent, request=None): diff --git a/static/css/style.css b/static/css/style.css index c3994835bab3346defc09a90ae44374b46876ec9..1ae24e1346bd4f616ea9f0d0900eb15c3a322bf9 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -423,6 +423,14 @@ div.dgrid-row.collapsed:hover { width: 10%; } +.dgrid-cell.field-footprint_count { + width: 8em; +} + +.dgrid-cell.field-group { + width: 10em; +} + th.dgrid-cell { vertical-align: bottom; } diff --git a/templates/gracedb/event_detail_script.js b/templates/gracedb/event_detail_script.js index 29fc76661aed84fcd105a877db663e32f34cf570..c502e34726ee9132308d885c8d913bd8e8fcc6bd 100644 --- a/templates/gracedb/event_detail_script.js +++ b/templates/gracedb/event_detail_script.js @@ -90,7 +90,55 @@ var tooltip=function(){ }(); +// This should probably also go somewhere else. +// Closure +(function() { + /** + * Decimal adjustment of a number. + * + * @param {String} type The type of adjustment. + * @param {Number} value The number. + * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base). + * @returns {Number} The adjusted value. + */ + function decimalAdjust(type, value, exp) { + // If the exp is undefined or zero... + if (typeof exp === 'undefined' || +exp === 0) { + return Math[type](value); + } + value = +value; + exp = +exp; + // If the value is not a number or the exp is not an integer... + if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) { + return NaN; + } + // Shift + value = value.toString().split('e'); + value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))); + // Shift back + value = value.toString().split('e'); + return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)); + } + // Decimal round + if (!Math.round10) { + Math.round10 = function(value, exp) { + return decimalAdjust('round', value, exp); + }; + } + // Decimal floor + if (!Math.floor10) { + Math.floor10 = function(value, exp) { + return decimalAdjust('floor', value, exp); + }; + } + // Decimal ceil + if (!Math.ceil10) { + Math.ceil10 = function(value, exp) { + return decimalAdjust('ceil', value, exp); + }; + } +})(); // A utility @@ -119,9 +167,7 @@ var tagListUrl = '{% url "api:tag-list" %}'; var tagUrlPattern = '{% url "taglogentry" object.graceid "000" "temp" %}'; var eventLogListUrl = '{% url "api:eventlog-list" object.graceid %}'; var eventLogSaveUrl = '{% url "logentry" object.graceid "" %}'; -var embbEventLogListUrl = '{% url "api:embbeventlog-list" object.graceid %}'; -// XXX Branson made this change on 3/3/15 -//var skymapJsonUrl = '{% url "file" object.graceid "skymap.json" %}'; +var emObservationListUrl = '{% url "api:emobservation-list" object.graceid %}'; var skymapJsonUrl = '{% url "file" object.graceid "" %}'; var skymapViewerUrl = '{{ SKYMAP_VIEWER_SERVICE_URL }}'; @@ -195,7 +241,7 @@ require([ if (!(initiallyOpen && initiallyOpen==true)) { put(expandGlyphNode, '.closed'); domStyle.set(contentNode, 'display', 'none'); - domStyle.set(addButtonNode, 'display', 'none'); + domStyle.set(addButtonNode, 'display', 'none'); } // This one is always closed initially domStyle.set(formNode, 'display', 'none'); @@ -203,7 +249,7 @@ require([ on(expandGlyphNode, "click", function() { if (domStyle.get(contentNode, 'display') == 'none') { domStyle.set(contentNode, 'display', 'block'); - domStyle.set(addButtonNode, 'display', 'block'); + domStyle.set(addButtonNode, 'display', 'block'); put(expandGlyphNode, '!closed'); } else { domStyle.set(contentNode, 'display', 'none'); @@ -215,7 +261,7 @@ require([ on(titleTextNode, "click", function() { if (domStyle.get(contentNode, 'display') == 'none') { domStyle.set(contentNode, 'display', 'block'); - domStyle.set(addButtonNode, 'display', 'block'); + domStyle.set(addButtonNode, 'display', 'block'); put(expandGlyphNode, '!closed'); } else { domStyle.set(contentNode, 'display', 'none'); @@ -235,6 +281,38 @@ require([ }); } + var createExpandingSectionNoForm = function (titleNode, contentNode, titleText, initiallyOpen) { + // Instead let's make a table. + var titleTableRow = put(titleNode, "table tr"); + var expandGlyphNode = put(titleTableRow, "td.title div.expandGlyph"); + var titleTextNode = put(titleTableRow, "td.title h2", titleText); + + if (!(initiallyOpen && initiallyOpen==true)) { + put(expandGlyphNode, '.closed'); + domStyle.set(contentNode, 'display', 'none'); + } + + on(expandGlyphNode, "click", function() { + if (domStyle.get(contentNode, 'display') == 'none') { + domStyle.set(contentNode, 'display', 'block'); + put(expandGlyphNode, '!closed'); + } else { + domStyle.set(contentNode, 'display', 'none'); + put(expandGlyphNode, '.closed'); + } + }); + + on(titleTextNode, "click", function() { + if (domStyle.get(contentNode, 'display') == 'none') { + domStyle.set(contentNode, 'display', 'block'); + put(expandGlyphNode, '!closed'); + } else { + domStyle.set(contentNode, 'display', 'none'); + put(expandGlyphNode, '.closed'); + } + }); + } + var timeChoicesData = [ {"id": "llo", "label": "LLO Local"}, {"id": "lho", "label": "LHO Local"}, @@ -280,51 +358,55 @@ require([ var embbContentDiv = put(embbDiv, 'div#embb_content'); // Put the EEL form into the content div - var oldEelFormDiv = dom.byId('eelFormContainer'); - var eelFormContents = oldEelFormDiv.innerHTML; - domConstruct.destroy('eelFormContainer'); - var embbAddDiv = put(embbContentDiv, 'div#add_eel_container'); - var embbAddFormDiv = put(embbAddDiv, 'div#add_eel_form_container'); - embbAddFormDiv.innerHTML = eelFormContents; + // FIXME This needs to be cleaned up. Empty div for now. + //var oldEelFormDiv = dom.byId('eelFormContainer'); + //var eelFormContents = oldEelFormDiv.innerHTML; + domConstruct.destroy('eelFormContainer'); + // var embbAddDiv = put(embbContentDiv, 'div#add_eel_container'); + /* var embbAddFormDiv = put(embbAddDiv, 'div#add_eel_form_container'); + embbAddFormDiv.innerHTML = eelFormContents; */ - createExpandingSection(embbTitleDiv, embbContentDiv, embbAddDiv, 'Electromagnetic Bulletin Board'); + createExpandingSectionNoForm(embbTitleDiv, embbContentDiv, 'Electromagnetic Bulletin Board'); // Append the div that will hold our dgrid - put(embbContentDiv, 'div#eel-grid'); + put(embbContentDiv, 'div#emo-grid'); - embbStore = new declare([Rest, RequestMemory])({target: embbEventLogListUrl}); - embbStore.get('').then(function(content) { + emoStore = new declare([Rest, RequestMemory])({target: emObservationListUrl}); + emoStore.get('').then(function(content) { // Pull the EELs out of the rest content and create a new simple store from them. - var eels = content.embblog; + var emos = content.observations; - if (eels.length == 0) { - eelDiv = dom.byId('eel-grid'); - eelDiv.innerHTML = '<p> (No EMBB log entries.) </p>'; + if (emos.length == 0) { + emoDiv = dom.byId('emo-grid'); + emoDiv.innerHTML = '<p> (No EM observation entries.) </p>'; } else { var columns = [ { field: 'created', label: 'Time Created (UTC)' }, { field: 'submitter', label: 'Submitter' }, { field: 'group', label: 'MOU Group' }, - { field: 'gpstime', label: 'GPS time of observation' }, - { field: 'duration', label: 'Exposure time (s)' }, + { field: 'footprint_count', label: 'N_regions' }, { field: 'radec', label: 'Covering (ra, dec)', get: function(object){ - var rastring = object.ra + " \xB1 " + object.raWidth/2.0; - var decstring = object.dec + " \xB1 " + object.decWidth/2.0; + var raLoc = Math.round10(object.ra, -2); + var raHalfWidthLoc = Math.round10(object.raWidth/2.0, -2); + var decLoc = Math.round10(object.dec, -2); + var decHalfWidthLoc = Math.round10(object.decWidth/2.0, -2); + var rastring = raLoc + " \xB1 " + raHalfWidthLoc; + var decstring = decLoc + " \xB1 " + decHalfWidthLoc; return "(" + rastring + ',' + decstring + ")"; }, } ]; var subRowColumns = [ - { field: 'instrument', label: 'Instrument' }, - { field: 'eel_status', label: 'Entry type' }, - { field: 'footprintID', label: 'Observation ID' }, - { field: 'waveband', label: 'Waveband' }, - { field: 'obs_status', label: 'Observation status' }, - { field: 'extra_info_dict', label: 'JSON info' }, + { field: 'start_time', label: 'Start Time (UTC)' }, + { field: 'exposure_time', label: 'Exposure Time (s)' }, + { field: 'ra', label: 'ra'}, + { field: 'raWidth', label: 'ra width'}, + { field: 'dec', label: 'dec'}, + { field: 'decWidth', label: 'dec width'} ]; // Add extra class names to our grid cells so we can style them separately @@ -352,14 +434,14 @@ require([ columns: subRowColumns, className: 'dgird-subgrid', }, subGridNode); - sg.renderArray([object]); + sg.renderArray(object.footprints); // Add the text comment - put(t, 'tr td[style="width: 5%"]+td div.subrid-text', object.comment); + //put(t, 'tr td[style="width: 5%"]+td div.subrid-text', object.comment); return div; } - }, 'eel-grid'); - grid.renderArray(eels); + }, 'emo-grid'); + grid.renderArray(emos); grid.set("sort", 'N', descending=true); var expandedNode = null; @@ -378,7 +460,7 @@ require([ // if the row clicked was previously expanded, nothing is expanded now expandedNode = collapsed ? node : null; }); - } // endif on whether we have any eels or not. + } // endif on whether we have any emos or not. });