diff --git a/YSE_App/api_views.py b/YSE_App/api_views.py index 1a88807b..42fce820 100755 --- a/YSE_App/api_views.py +++ b/YSE_App/api_views.py @@ -41,6 +41,7 @@ class FollowupStatusViewSet(viewsets.ReadOnlyModelViewSet): class SurveyFieldFilter(django_filters.FilterSet): field_id = django_filters.Filter(field_name="field_id") obs_group = django_filters.Filter(field_name="obs_group__name") + instrument = django_filters.Filter(field_name="instrument__name") class Meta: model = SurveyField fields = () @@ -49,6 +50,7 @@ class Meta: class SurveyFieldMSBFilter(django_filters.FilterSet): name = django_filters.Filter(field_name="name") active = django_filters.Filter(field_name="active") + instrument = django_filters.Filter(field_name='survey_fields__instrument__name') class Meta: model = SurveyFieldMSB fields = ('name','active') @@ -83,7 +85,8 @@ class SurveyObsFilter(django_filters.FilterSet): ra_lt = django_filters.Filter(field_name="survey_field__ra_cen", lookup_expr='lt') dec_gt = django_filters.Filter(field_name="survey_field__dec_cen", lookup_expr='gt') dec_lt = django_filters.Filter(field_name="survey_field__dec_cen", lookup_expr='lt') - + instrument = django_filters.Filter(field_name="survey_field__instrument__name") + class Meta: model = SurveyObservation fields = () @@ -111,11 +114,21 @@ class InternalSurveyViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = InternalSurveySerializer permission_classes = (permissions.IsAuthenticated,) +### `ObservationGroup` Filter Set ### +class ObservationGroupFilter(django_filters.FilterSet): + name = django_filters.Filter(field_name="name") + + class Meta: + model = ObservationGroup + fields = () + class ObservationGroupViewSet(viewsets.ReadOnlyModelViewSet): queryset = ObservationGroup.objects.all() serializer_class = ObservationGroupSerializer permission_classes = (permissions.IsAuthenticated,) - + filter_backends = (DjangoFilterBackend,) + filter_class = ObservationGroupFilter + class SEDTypeViewSet(viewsets.ReadOnlyModelViewSet): queryset = SEDType.objects.all() serializer_class = SEDTypeSerializer @@ -190,13 +203,23 @@ class HostSEDViewSet(custom_viewsets.ListCreateRetrieveUpdateViewSet): serializer_class = HostSEDSerializer permission_classes = (permissions.IsAuthenticated,) +### `Instrument` Filter Set ### +class InstrumentFilter(django_filters.FilterSet): + name = django_filters.Filter(field_name="name") + class Meta: + model = Instrument + fields = () + ### `Instrument` ViewSets ### class InstrumentViewSet(custom_viewsets.ListCreateRetrieveUpdateViewSet): queryset = Instrument.objects.all() serializer_class = InstrumentSerializer lookup_field = "id" permission_classes = (permissions.IsAuthenticated,) + filter_backends = (DjangoFilterBackend,) + filter_class = InstrumentFilter + class InstrumentConfigViewSet(custom_viewsets.ListCreateRetrieveUpdateViewSet): queryset = InstrumentConfig.objects.all() serializer_class = InstrumentConfigSerializer diff --git a/YSE_App/data_ingest/DECam_upload.py b/YSE_App/data_ingest/DECam_upload.py index 25e08aac..f8d16fa4 100644 --- a/YSE_App/data_ingest/DECam_upload.py +++ b/YSE_App/data_ingest/DECam_upload.py @@ -180,7 +180,7 @@ def add_options(self, parser=None, usage=None, config=None): parser.add_argument('--SMTP_PORT', default=config.get('SMTP_provider','SMTP_PORT'), type=str, help='SMTP port (default=%default)') - parser.add_argument('--max_decam_days', default=config.get('main','max_days_decam'), type=float, + parser.add_argument('--max_decam_days', default=config.get('yse','max_days_decam'), type=float, help='grab photometry/objects from the last x days') else: diff --git a/YSE_App/data_ingest/DECam_upload_clusters.py b/YSE_App/data_ingest/DECam_upload_clusters.py index fbf5c263..2d071933 100644 --- a/YSE_App/data_ingest/DECam_upload_clusters.py +++ b/YSE_App/data_ingest/DECam_upload_clusters.py @@ -264,7 +264,7 @@ def add_options(self, parser=None, usage=None, config=None): parser.add_argument('--SMTP_PORT', default=config.get('SMTP_provider','SMTP_PORT'), type=str, help='SMTP port (default=%default)') - parser.add_argument('--max_decam_days', default=config.get('main','max_days_decam'), type=float, + parser.add_argument('--max_decam_days', default=config.get('yse','max_days_decam'), type=float, help='grab photometry/objects from the last x days') else: diff --git a/YSE_App/data_ingest/QUB_data.py b/YSE_App/data_ingest/QUB_data.py index f3554d57..d7888649 100644 --- a/YSE_App/data_ingest/QUB_data.py +++ b/YSE_App/data_ingest/QUB_data.py @@ -199,20 +199,18 @@ def add_options(self, parser=None, usage=None, config=None): help='email password, if post=True (default=%default)') parser.add_argument('--dburl', default=config.get('main','dburl'), type=str, help='URL to POST transients to a database (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, + parser.add_argument('--ztfurl', default=config.get('ztf','ztfurl'), type=str, help='ZTF URL (default=%default)') parser.add_argument('--STATIC', default=config.get('site_settings','STATIC'), type=str, help='static directory (default=%default)') - parser.add_argument('--qubuser', default=config.get('main','qubuser'), type=str, + parser.add_argument('--qubuser', default=config.get('yse','qubuser'), type=str, help='QUB database username (default=%default)') - parser.add_argument('--qubpass', default=config.get('main','qubpass'), type=str, + parser.add_argument('--qubpass', default=config.get('yse','qubpass'), type=str, help='QUB database password (default=%default)') - parser.add_argument('--psstlink_summary', default=config.get('main','psstlink_summary'), type=str, + parser.add_argument('--psstlink_summary', default=config.get('yse','psstlink_summary'), type=str, help='PSST summary CSV (default=%default)') - parser.add_argument('--psstlink_lc', default=config.get('main','psstlink_lc'), type=str, + parser.add_argument('--psstlink_lc', default=config.get('yse','psstlink_lc'), type=str, help='PSST lightcurve CSV (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, - help='ZTF URL (default=%default)') parser.add_argument('--SMTP_LOGIN', default=config.get('SMTP_provider','SMTP_LOGIN'), type=str, @@ -222,7 +220,7 @@ def add_options(self, parser=None, usage=None, config=None): parser.add_argument('--SMTP_PORT', default=config.get('SMTP_provider','SMTP_PORT'), type=str, help='SMTP port (default=%default)') - parser.add_argument('--max_days', default=config.get('main','max_days_qub'), type=float, + parser.add_argument('--max_days', default=config.get('yse','max_days_qub'), type=float, help='grab photometry/objects from the last x days') else: @@ -540,24 +538,22 @@ def add_options(self, parser=None, usage=None, config=None): help='email password, if post=True (default=%default)') parser.add_argument('--dburl', default=config.get('main','dburl'), type=str, help='URL to POST transients to a database (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, + parser.add_argument('--ztfurl', default=config.get('ztf','ztfurl'), type=str, help='ZTF URL (default=%default)') parser.add_argument('--STATIC', default=config.get('site_settings','STATIC'), type=str, help='static directory (default=%default)') - parser.add_argument('--qubuser', default=config.get('main','qubuser'), type=str, + parser.add_argument('--qubuser', default=config.get('yse','qubuser'), type=str, help='QUB database username (default=%default)') - parser.add_argument('--qubpass', default=config.get('main','qubpass'), type=str, + parser.add_argument('--qubpass', default=config.get('yse','qubpass'), type=str, help='QUB database password (default=%default)') - parser.add_argument('--yselink_summary', default=config.get('main','yselink_summary'), type=str, + parser.add_argument('--yselink_summary', default=config.get('yse','yselink_summary'), type=str, help='YSE summary CSV (default=%default)') - parser.add_argument('--yselink_lc', default=config.get('main','yselink_lc'), type=str, + parser.add_argument('--yselink_lc', default=config.get('yse','yselink_lc'), type=str, help='YSE lightcurve CSV (default=%default)') - parser.add_argument('--yselink_genericsummary', default=config.get('main','yselink_genericsummary'), type=str, + parser.add_argument('--yselink_genericsummary', default=config.get('yse','yselink_genericsummary'), type=str, help='YSE summary CSV for possible candidates (default=%default)') - parser.add_argument('--yselink_genericlc', default=config.get('main','yselink_genericlc'), type=str, + parser.add_argument('--yselink_genericlc', default=config.get('yse','yselink_genericlc'), type=str, help='YSE lightcurve CSV for possible candidates (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, - help='ZTF URL (default=%default)') parser.add_argument('--SMTP_LOGIN', default=config.get('SMTP_provider','SMTP_LOGIN'), type=str, @@ -567,7 +563,7 @@ def add_options(self, parser=None, usage=None, config=None): parser.add_argument('--SMTP_PORT', default=config.get('SMTP_provider','SMTP_PORT'), type=str, help='SMTP port (default=%default)') - parser.add_argument('--max_days', default=config.get('main','max_days_yse'), type=float, + parser.add_argument('--max_days', default=config.get('yse','max_days_yse'), type=float, help='grab photometry/objects from the last x days') else: @@ -1004,31 +1000,29 @@ def add_options(self, parser=None, usage=None, config=None): help='email password, if post=True (default=%default)') parser.add_argument('--dburl', default=config.get('main','dburl'), type=str, help='URL to POST transients to a database (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, + parser.add_argument('--ztfurl', default=config.get('ztf','ztfurl'), type=str, help='ZTF URL (default=%default)') parser.add_argument('--STATIC', default=config.get('site_settings','STATIC'), type=str, help='static directory (default=%default)') - parser.add_argument('--qubuser', default=config.get('main','qubuser'), type=str, + parser.add_argument('--qubuser', default=config.get('yse','qubuser'), type=str, help='QUB database username (default=%default)') - parser.add_argument('--qubpass', default=config.get('main','qubpass'), type=str, + parser.add_argument('--qubpass', default=config.get('yse','qubpass'), type=str, help='QUB database password (default=%default)') - parser.add_argument('--yselink_stacksummary', default=config.get('main','yselink_stacksummary'), type=str, + parser.add_argument('--yselink_stacksummary', default=config.get('yse','yselink_stacksummary'), type=str, help='YSE summary CSV for possible candidates (default=%default)') - parser.add_argument('--yselink_stacklc', default=config.get('main','yselink_stacklc'), type=str, + parser.add_argument('--yselink_stacklc', default=config.get('yse','yselink_stacklc'), type=str, help='YSE lightcurve CSV for possible candidates (default=%default)') - parser.add_argument('--yselink_agnsummary', default=config.get('main','yselink_agnsummary'), type=str, + parser.add_argument('--yselink_agnsummary', default=config.get('yse','yselink_agnsummary'), type=str, help='YSE summary CSV for possible candidates (default=%default)') - parser.add_argument('--yselink_agnlc', default=config.get('main','yselink_agnlc'), type=str, + parser.add_argument('--yselink_agnlc', default=config.get('yse','yselink_agnlc'), type=str, help='YSE lightcurve CSV for possible candidates (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, - help='ZTF URL (default=%default)') - parser.add_argument('--max_days_ysestacklc', default=config.get('main','max_days_ysestacklc'), type=float, + parser.add_argument('--max_days_ysestacklc', default=config.get('yse','max_days_ysestacklc'), type=float, help='maximum days to look back for lightcurves (default=%default)') - parser.add_argument('--max_days_yseignore', default=config.get('main','max_days_ysestackignore'), type=float, + parser.add_argument('--max_days_yseignore', default=config.get('yse','max_days_ysestackignore'), type=float, help='maximum days to look back for lightcurves (default=%default)') - parser.add_argument('--max_days_yseagnlc', default=config.get('main','max_days_yseagnlc'), type=float, + parser.add_argument('--max_days_yseagnlc', default=config.get('yse','max_days_yseagnlc'), type=float, help='maximum days to look back for lightcurves (default=%default)') - parser.add_argument('--max_days_yseagnignore', default=config.get('main','max_days_yseagnignore'), type=float, + parser.add_argument('--max_days_yseagnignore', default=config.get('yse','max_days_yseagnignore'), type=float, help='maximum days to look back for lightcurves (default=%default)') parser.add_argument('--SMTP_LOGIN', default=config.get('SMTP_provider','SMTP_LOGIN'), type=str, @@ -1505,7 +1499,7 @@ def main(self): from YSE_App.models import Transient # 10HYSEkcp - transients = Transient.objects.filter(created_date__gt=datetime.datetime.now()-datetime.timedelta(1)).filter(name__startswith='10') + transients = Transient.objects.filter(created_date__gt=datetime.datetime.now()-datetime.timedelta(1)).filter(name__startswith='1') for t in transients: ramin,ramax,decmin,decmax = getRADecBox(t.ra,t.dec,size=0.00042) dups = Transient.objects.filter(Q(ra__gt=ramin) & Q(ra__lt=ramax) & diff --git a/YSE_App/data_ingest/Query_ZTF.py b/YSE_App/data_ingest/Query_ZTF.py index fed103ea..e05dee3b 100755 --- a/YSE_App/data_ingest/Query_ZTF.py +++ b/YSE_App/data_ingest/Query_ZTF.py @@ -545,7 +545,7 @@ def add_options(self, parser=None, usage=None, config=None): parser.add_option('--SMTP_PORT', default=config.get('SMTP_provider','SMTP_PORT'), type="string", help='SMTP port (default=%default)') - parser.add_option('--ztfurl', default=config.get('main','ztfurl'), type="string", + parser.add_option('--ztfurl', default=config.get('ztf','ztfurl'), type="string", help='ZTF URL (default=%default)') else: diff --git a/YSE_App/data_ingest/TNS_uploads.py b/YSE_App/data_ingest/TNS_uploads.py index f0c33376..47ca3af0 100644 --- a/YSE_App/data_ingest/TNS_uploads.py +++ b/YSE_App/data_ingest/TNS_uploads.py @@ -152,7 +152,7 @@ def add_options(self, parser=None, usage=None, config=None): help='time interval for grabbing very recent TNS events (default=%default)') parser.add_argument('--hostmatchrad', default=config.get('main','hostmatchrad'), type=float, help='matching radius for hosts (arcmin) (default=%default)') - parser.add_argument('--ztfurl', default=config.get('main','ztfurl'), type=str, + parser.add_argument('--ztfurl', default=config.get('ztf','ztfurl'), type=str, help='ZTF URL (default=%default)') parser.add_argument('--SMTP_LOGIN', default=config.get('SMTP_provider','SMTP_LOGIN'), type=str, diff --git a/YSE_App/data_ingest/YSE_Forced_Phot.py b/YSE_App/data_ingest/YSE_Forced_Phot.py index d2c9b303..586c62b4 100755 --- a/YSE_App/data_ingest/YSE_Forced_Phot.py +++ b/YSE_App/data_ingest/YSE_Forced_Phot.py @@ -248,17 +248,17 @@ def add_options(self, parser=None, usage=None, config=None): if config: parser.add_argument('--STATIC', default=config.get('site_settings','STATIC'), type=str, help='static directory (default=%default)') - parser.add_argument('--upload', default=config.get('yse_forcedphot','upload'), type=str, + parser.add_argument('--upload', default=config.get('yse','upload'), type=str, help='stamp upload server (default=%default)') - parser.add_argument('--stamp', default=config.get('yse_forcedphot','stamp'), type=str, + parser.add_argument('--stamp', default=config.get('yse','stamp'), type=str, help='stamp upload server (default=%default)') - parser.add_argument('--detectability', default=config.get('yse_forcedphot','detectability'), type=str, + parser.add_argument('--detectability', default=config.get('yse','detectability'), type=str, help='stamp upload server (default=%default)') - parser.add_argument('--skycell', default=config.get('yse_forcedphot','skycell'), type=str, + parser.add_argument('--skycell', default=config.get('yse','skycell'), type=str, help='stamp upload server (default=%default)') - parser.add_argument('--ifauser', default=config.get('yse_forcedphot','user'), type=str, + parser.add_argument('--ifauser', default=config.get('yse','user'), type=str, help='stamp upload server (default=%default)') - parser.add_argument('--ifapass', default=config.get('yse_forcedphot','pass'), type=str, + parser.add_argument('--ifapass', default=config.get('yse','pass'), type=str, help='stamp upload server (default=%default)') parser.add_argument('--dblogin', default=config.get('main','dblogin'), type=str, @@ -335,7 +335,8 @@ def main(self,transient_name=None,update_forced=False): warp_id_list += [s.warp_id] mjd_list += [s.obs_mjd] filt_list += [s.photometric_band.name] - + camera_list += [s.survey_field.instrument.name.lower()] + nt = len(np.unique(transient_list)) print('{} transients to upload!'.format(nt)) if nt == 0: return 0 @@ -348,7 +349,7 @@ def main(self,transient_name=None,update_forced=False): print('submitted stamp request {}'.format(stamp_request_name)) phot_request_names = self.forcedphot_request( - transient_list,ra_list,dec_list,mjd_list,filt_list,diff_id_list,skycelldict) + transient_list,ra_list,dec_list,mjd_list,filt_list,camera_list,diff_id_list,skycelldict) print('submitted phot requests:') for prn in phot_request_names: print(prn) @@ -463,9 +464,12 @@ def write_to_db(self,phot_dict,img_dict,stack_img_dict): PhotUploadAll = {"mjdmatchmin":0.0001, "clobber":True} - photometrydict = {'instrument':'GPC2', - 'obs_group':'YSE', - 'photdata':{}} + photometrydict_ps1 = {'instrument':'GPC1', + 'obs_group':'YSE', + 'photdata':{}} + photometrydict_ps2 = {'instrument':'GPC2', + 'obs_group':'YSE', + 'photdata':{}} tdict[k] = {'name':k, #'obs_group':'YSE', @@ -536,10 +540,15 @@ def write_to_db(self,phot_dict,img_dict,stack_img_dict): 'discovery_point':0, 'diffim':1, 'diffimg':diffimgdict} - - photometrydict['photdata']['%s_%i'%(mjd_to_date(img_dict[k]['diff_image_mjd'][i]),i)] = phot_upload_dict - - PhotUploadAll['PS1'] = photometrydict + if 'GPC1' in phot_upload_dict['band']: + photometrydict_ps1['photdata']['%s_%i'%(mjd_to_date(img_dict[k]['diff_image_mjd'][i]),i)] = phot_upload_dict + elif 'GPC2' in phot_upload_dict['band']: + photometrydict_ps2['photdata']['%s_%i'%(mjd_to_date(img_dict[k]['diff_image_mjd'][i]),i)] = phot_upload_dict + else: + raise RuntimeError("couldn't figure out the instrument") + + PhotUploadAll['PS1'] = photometrydict_ps1 + PhotUploadAll['PS2'] = photometrydict_ps2 tdict[k]['transientphotometry'] = PhotUploadAll self.send_data(tdict) @@ -744,7 +753,7 @@ def get_status(self,request_name): return done,success def stamp_request( - self,transient_list,ra_list,dec_list,diff_id_list, + self,transient_list,ra_list,dec_list,camera_list,diff_id_list, warp_id_list,stack_id_list,width=300,height=300,skycelldict=None): assert len(transient_list) == len(warp_id_list) or \ @@ -773,27 +782,27 @@ def stamp_request( skycelldict[snid] = skycells[-1] count = 1 - for snid,ra,dec,diff_id in \ - zip(transient_list,ra_list,dec_list,diff_id_list): + for snid,ra,dec,camera,diff_id in \ + zip(transient_list,ra_list,dec_list,camera_list,diff_id_list): if diff_id is None: continue skycell_str = skycelldict[snid] - data.add_row((count,'gpc2','null','null','stamp',2049,'byid','diff',diff_id,'RINGS.V3', + data.add_row((count,camera,'null','null','stamp',2049,'byid','diff',diff_id,'RINGS.V3', skycell_str,2,ra,dec,width,height,'null','null',0,0,'null',0,0,'diff.for.%s'%snid) ) count += 1 - for snid,ra,dec,warp_id in \ - zip(transient_list,ra_list,dec_list,warp_id_list): + for snid,ra,dec,camera,warp_id in \ + zip(transient_list,ra_list,dec_list,camera_list,warp_id_list): if warp_id is None: continue skycell_str = skycelldict[snid] - data.add_row((count,'gpc2','null','null','stamp',2049,'byid','warp',warp_id,'RINGS.V3', + data.add_row((count,camera,'null','null','stamp',2049,'byid','warp',warp_id,'RINGS.V3', skycell_str,2,ra,dec,width,height,'null','null',0,0,'null',0,0,'warp.for.%s'%snid) ) count += 1 - for snid,ra,dec,stack_id in \ - zip(transient_list,ra_list,dec_list,stack_id_list): + for snid,ra,dec,camera,stack_id in \ + zip(transient_list,ra_list,dec_list,camera_list,stack_id_list): if stack_id is None: continue skycell_str = skycelldict[snid] - data.add_row((count,'gpc2','null','null','stamp',2049,'byid','stack',stack_id,'RINGS.V3', + data.add_row((count,camera,'null','null','stamp',2049,'byid','stack',stack_id,'RINGS.V3', skycell_str,2,ra,dec,width,height,'null','null',0,0,'null',0,0,'stack.for.%s'%snid) ) count += 1 @@ -810,7 +819,7 @@ def stamp_request( self.submit_to_ipp(s) return request_name,skycelldict - def forcedphot_request(self,transient_list,ra_list,dec_list,mjd_list,filt_list,diff_id_list,skycelldict): + def forcedphot_request(self,transient_list,ra_list,dec_list,mjd_list,filt_list,camera_list,diff_id_list,skycelldict): transient_list,ra_list,dec_list,mjd_list,filt_list,diff_id_list = \ np.atleast_1d(np.asarray(transient_list)),np.atleast_1d(np.asarray(ra_list)),\ @@ -822,11 +831,11 @@ def forcedphot_request(self,transient_list,ra_list,dec_list,mjd_list,filt_list,d for snid_unq in np.unique(transient_list): data = at.Table(names=('ROWNUM','PROJECT','RA1_DEG','DEC1_DEG','RA2_DEG','DEC2_DEG','FILTER','MJD-OBS','FPA_ID','COMPONENT_ID'), dtype=('S20','S16','>f8','>f8','>f8','>f8','S20','>f8','>i4','S64')) - for snid,ra,dec,mjd,filt,diff_id in \ + for snid,ra,dec,mjd,filt,camera,diff_id in \ zip(transient_list[transient_list == snid_unq],ra_list[transient_list == snid_unq],dec_list[transient_list == snid_unq], - mjd_list[transient_list == snid_unq],filt_list[transient_list == snid_unq],diff_id_list[transient_list == snid_unq]): + mjd_list[transient_list == snid_unq],filt_list[transient_list == snid_unq],camera_list[transient_list == snid_unq],diff_id_list[transient_list == snid_unq]): if diff_id is None or diff_id == 'NULL': continue - data.add_row(('forcedphot_ysebot_{}'.format(count),'gpc2',ra,dec,ra,dec,filt,mjd,diff_id,skycelldict[snid_unq]) ) + data.add_row(('forcedphot_ysebot_{}'.format(count),camera,ra,dec,ra,dec,filt,mjd,diff_id,skycelldict[snid_unq]) ) count += 1 if len(data) > 0: diff --git a/YSE_App/form_views.py b/YSE_App/form_views.py index 264898e1..103dfca6 100755 --- a/YSE_App/form_views.py +++ b/YSE_App/form_views.py @@ -29,9 +29,14 @@ from .basicauth import * from YSE_App.util import lcogt +# for getting YSE filter selection +from django.conf import settings as djangoSettings + +# reddest filter for YSE is from settings.py +_reddest_yse_filter = djangoSettings.REDYSEFILTER def is_ajax(request): - return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' + return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' class AddTransientFollowupFormView(FormView): form_class = TransientFollowupForm @@ -383,6 +388,11 @@ def form_valid(self, form): filter(Q(obs_mjd__lt=m) | Q(mjd_requested__lt=m)).order_by('-obs_mjd').\ order_by('-mjd_requested').select_related() + # reddest_yse_filter gives hard-coded YSE "mini-survey" filter choice + if s.instrument.name == 'GPC1': + reddest_yse_filter = _reddest_yse_filter[:] + else: + reddest_yse_filter = 'z' def previous_obs_func(illum_min,illum_max): filt = [] @@ -401,12 +411,12 @@ def previous_obs_func(illum_min,illum_max): filt = previous_obs_func(0,0.66) if filt is None: band1name,band2name = 'g','r' elif 'r' in filt: band1name,band2name = 'g','i' - elif 'i' in filt: band1name,band2name = 'g','z' + elif 'i' in filt: band1name,band2name = 'g',reddest_yse_filter else: band1name,band2name = 'g','r' else: filt = previous_obs_func(0.66,1) - if filt is None or 'z' in filt: band1name,band2name = 'r','i' - else: band1name,band2name = 'r','z' + if filt is None or 'z' in filt or 'y' in filt: band1name,band2name = 'r','i' + else: band1name,band2name = 'r',reddest_yse_filter else: if illum < 0.33: filt = previous_obs_func(0,0.33) @@ -414,12 +424,12 @@ def previous_obs_func(illum_min,illum_max): else: band1name,band2name = 'g','i' elif illum < 0.66: filt = previous_obs_func(0.33,0.66) - if filt is None or 'z' in filt: band1name,band2name = 'g','i' - else: band1name,band2name = 'g','z' + if filt is None or 'z' in filt or 'y' in filt: band1name,band2name = 'g','i' + else: band1name,band2name = 'g',reddest_yse_filter else: filt = previous_obs_func(0.66,1) - if filt is None or 'z' in filt: band1name,band2name = 'r','i' - else: band1name,band2name = 'r','z' + if filt is None or 'z' in filt or 'y' in filt: band1name,band2name = 'r','i' + else: band1name,band2name = 'r',reddest_yse_filter band1 = PhotometricBand.objects.filter( name=band1name,instrument__name=s.instrument.name)[0] diff --git a/YSE_App/serializers/surveyfield_serializers.py b/YSE_App/serializers/surveyfield_serializers.py index aeb2300d..414b1aaf 100755 --- a/YSE_App/serializers/surveyfield_serializers.py +++ b/YSE_App/serializers/surveyfield_serializers.py @@ -19,16 +19,28 @@ def create(self, validated_data): def update(self, instance, validated_data): instance.obs_group = validated_data.get('obs_group', instance.obs_group) instance.field_id = validated_data.get('field_id', instance.field_id) - instance.first_mjd = validated_data.get('first_mjd', instance.first_mjd) - instance.last_mjd = validated_data.get('last_mjd', instance.last_mjd) instance.cadence = validated_data.get('cadence', instance.cadence) instance.instrument = validated_data.get('instrument', instance.instrument) instance.ztf_field_id = validated_data.get('ztf_field_id', instance.ztf_field_id) - + instance.targeted_galaxies = validated_data.get('targeted_galaxies',instance.targeted_galaxies) + instance.ra_cen = validated_data.get('ra_cen', instance.ra_cen) instance.dec_cen = validated_data.get('dec_cen', instance.dec_cen) instance.width_deg = validated_data.get('width_deg', instance.width_deg) instance.height_deg = validated_data.get('height_deg', instance.height_deg) + + if 'targeted_transients' in validated_data.keys(): + # Disassociate existing `Targeted Transients` + targeted_transients = instance.targeted_transients.all() + for targeted_transient in targeted_transients: + instance.targeted_transients.remove(targeted_transients) + + targeted_transients = validated_data.pop('targeted_transients') + for targeted_transient in targeted_transients: + transient_result = Transient.objects.filter(pk=targeted_tansient.id) + if transient_result.exists(): + t = transient_result.first() + instance.targeted_transients.add(t) instance.save() @@ -56,7 +68,7 @@ def create(self, validated_data): surveyfieldmsb = SurveyFieldMSB.objects.create(**validated_data) surveyfieldmsb.save() instance.active = validated_data.get('active', instance.active) - + if survey_fields_exist: for field in survey_fields: survey_field_result = SurveyField.objects.filter(pk=tag.id) @@ -72,19 +84,19 @@ def update(self, instance, validated_data): instance.obs_group = validated_data.get('obs_group', instance.obs_group) instance.name = validated_data.get('name', instance.name) instance.active = validated_data.get('active', instance.active) - - if 'survey_fields' in validated_data.keys(): - # Disassociate existing `Transient Tags` - survey_fields = instance.survey_fields.all() - for field in survey_fields: - instance.survey_fields.remove(field) - survey_fields = validated_data.pop('tags') - for field in survey_fields: - survey_field_result = SurveyField.objects.filter(pk=tag.id) + + if len(self.context['request'].data['survey_fields']): + survey_fields = instance.survey_fields.all() + for survey_field in survey_fields: + instance.survey_fields.remove(survey_field) + + for survey_field in self.context['request'].data['survey_fields']: + + survey_field_result = SurveyField.objects.filter(pk=survey_field['id']) if survey_field_result.exists(): s = survey_field_result.first() - instance.tags.add(s) + instance.survey_fields.add(s) instance.save() diff --git a/YSE_App/templates/YSE_App/form_snippets/YSE_move_field_form.html b/YSE_App/templates/YSE_App/form_snippets/YSE_move_field_form.html index 1ae23899..635fe6be 100644 --- a/YSE_App/templates/YSE_App/form_snippets/YSE_move_field_form.html +++ b/YSE_App/templates/YSE_App/form_snippets/YSE_move_field_form.html @@ -42,6 +42,17 @@ {% render_field form.dec_str class+="form-control" %} +
+
+ + + {% render_field form.instrument class+="form-control" %} +
+
diff --git a/YSE_App/templates/YSE_App/select_yse_fields.html b/YSE_App/templates/YSE_App/select_yse_fields.html index aad514ff..28858104 100644 --- a/YSE_App/templates/YSE_App/select_yse_fields.html +++ b/YSE_App/templates/YSE_App/select_yse_fields.html @@ -5,7 +5,7 @@

- Active YSE Fields + PS1 YSE Fields

+
+
+ + +
+

+ PS2 YSE Fields +

+ +
+ +
+ +
+ +
+
+
+
+ Inactive YSE Fields +
+ + +
+ + + + + + + + + + + + {% for a in yse_gpc2_field_data %} + + + + + + + + {% endfor %} + +
NameRADecDays Since Last ObsAirmass
{{ a.0.name }}
{{a.0.CoordString.0}}{{a.0.CoordString.1}}{{ a.2|floatformat:0 }}{{a.3}}
+
+
+
+
+
+
+ Active YSE Fields +
+
+ + + + + + + + + + + + {% for a in active_yse_gpc2_field_data %} @@ -90,7 +170,6 @@

- {% include "YSE_App/form_snippets/YSE_move_field_form.html" with form=yse_move_field_form %} @@ -252,6 +331,104 @@

} }); + init_events($('#external-events2 div.external-event')) + init_events($('#associated-events2 div.external-event')) + + // Make target canvas draggable + $("#associated-events2").droppable({ + drop:function(e,source){ + + $("#associated-events2-list").append(source.draggable); + // Now, get all associated events and PATCH transient with them + var tag_ids = $("#associated-events2-list").children("div").map(function() {return $(this).attr("data-tag_id")}) + + var base_url = window.location.protocol + "//" + window.location.hostname + var port = window.location.port + if (port != "") { + base_url = base_url + ":" + port + } + + var tag_urls = [] + for (i=0; i< tag_ids.length; i++) { + + + var msb_target = "{% url 'surveyfieldmsb-detail' -1 %}".replace(-1,tag_ids[i]) + var api_url = base_url + msb_target + //alert(api_url) + var patchData = { "active": 1 } + var jsonData = JSON.stringify(patchData) + + $.ajax({ + type: "PATCH", + url: api_url, + csrfmiddlewaretoken: "{{ csrf_token }}", + data: jsonData, + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function(data, textStatus, jqXHR) { + if (textStatus == "success") { + + } else { + alert("YSE Field statuses may not have been changed -- please use YSE Admin and contact David J.") + } + }, + error: function(XMLHttpRequest, textStatus, errorThrown) { + // alert("Transient Tag may not have been created -- please use YSE Admin and contact Dave C or David J.") + alert("Error: " + String(errorThrown) + String(textStatus) + String(XMLHttpRequest.responseText)); + } + }); + } + + } + }); + + $("#external-events2").droppable({ + drop:function(e,source){ + + $("#external-events2-list").append(source.draggable); + // Now, get all associated events and PATCH transient with them + var tag_ids = $("#external-events2-list").children("div").map(function() {return $(this).attr("data-tag_id")}) + + var base_url = window.location.protocol + "//" + window.location.hostname + var port = window.location.port + if (port != "") { + base_url = base_url + ":" + port + } + + var tag_urls = [] + for (i=0; i< tag_ids.length; i++) { + + + var msb_target = "{% url 'surveyfieldmsb-detail' -1 %}".replace(-1,tag_ids[i]) + var api_url = base_url + msb_target + //alert(api_url) + var patchData = { "active": 0 } + var jsonData = JSON.stringify(patchData) + + $.ajax({ + type: "PATCH", + url: api_url, + csrfmiddlewaretoken: "{{ csrf_token }}", + data: jsonData, + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function(data, textStatus, jqXHR) { + if (textStatus == "success") { + + } else { + alert("YSE Field statuses may not have been changed -- please use YSE Admin and contact David J.") + } + }, + error: function(XMLHttpRequest, textStatus, errorThrown) { + // alert("Transient Tag may not have been created -- please use YSE Admin and contact Dave C or David J.") + alert("Error: " + String(errorThrown) + String(textStatus) + String(XMLHttpRequest.responseText)); + } + }); + } + + } + }); + $('#move_yse_field').on('submit', function(event){ event.preventDefault(); move_yse_field(); diff --git a/YSE_App/templates/YSE_App/yse_observing_calendar.html b/YSE_App/templates/YSE_App/yse_observing_calendar.html index a2972a45..a79de96b 100644 --- a/YSE_App/templates/YSE_App/yse_observing_calendar.html +++ b/YSE_App/templates/YSE_App/yse_observing_calendar.html @@ -145,11 +145,11 @@

Observing Calendar (UT)

{% for obs in all_obs %} { {% if obs.0 and obs.4 %} - title : 'Obs. ZTF Fields:\n{{obs.0}}\nSched. ZTF Fields:\n{{obs.4}}\nMoon: {{obs.2}}', + title : 'Obs. PS1 Fields:\n{{obs.0}}\nObs. PS2 Fields:\n{{obs.5}}\nSched. PS1 Fields:\n{{obs.4}}\nSched. PS2 Fields:\n{{obs.6}}\nMoon: {{obs.2}}', {% elif obs.0 %} - title : 'Obs. ZTF Fields:\n{{obs.0}}\nMoon: {{obs.2}}', + title : 'Obs. PS1 Fields:\n{{obs.0}}\nObs. PS2 Fields:\n{{obs.5}}\nMoon: {{obs.2}}', {% else %} - title : 'Sched. ZTF Fields:\n{{obs.4}}\nMoon: {{obs.2}}', + title : 'Sched. PS1 Fields:\n{{obs.4}}\nSched. PS2 Fields:\n{{obs.6}}\nMoon: {{obs.2}}', {% endif %} start : new Date({{ obs.1.year }}, {{ obs.1.month|add:"-1" }}, {{ obs.1.day }}), allDay : true, diff --git a/YSE_App/views.py b/YSE_App/views.py index ddf9ea66..d3b61368 100755 --- a/YSE_App/views.py +++ b/YSE_App/views.py @@ -652,38 +652,63 @@ def yse_observing_calendar(request): colors = ['#dd4b39', '#f39c12', '#00c0ef'] + for i,date in enumerate(date_list): time = Time(date_to_mjd(date.strftime('%Y-%m-%d 00:00:00')),format='mjd') sunset_forobs = tel.sun_set_time(time,which="next") sunrise_forobs = tel.sun_rise_time(time,which="next") - survey_obs = SurveyObservation.objects.filter( + survey_obs_ps1 = SurveyObservation.objects.filter( Q(mjd_requested__gte = date_to_mjd(sunset_forobs)-0.1) | Q(obs_mjd__gte = date_to_mjd(sunset_forobs)-0.1)).\ - filter(Q(mjd_requested__lte = date_to_mjd(sunrise_forobs)+0.1) | Q(obs_mjd__lte = date_to_mjd(sunrise_forobs)+0.1)) - if not len(survey_obs): continue - ztf_obs_ids = survey_obs.filter(obs_mjd__isnull=False).values_list('survey_field__ztf_field_id',flat=True).distinct() - ztf_sched_ids = survey_obs.filter(obs_mjd__isnull=True).values_list('survey_field__ztf_field_id',flat=True).distinct() + filter(Q(mjd_requested__lte = date_to_mjd(sunrise_forobs)+0.1) | Q(obs_mjd__lte = date_to_mjd(sunrise_forobs)+0.1)).\ + filter(survey_field__instrument__name='GPC1') + survey_obs_ps2 = SurveyObservation.objects.filter( + Q(mjd_requested__gte = date_to_mjd(sunset_forobs)-0.1) | Q(obs_mjd__gte = date_to_mjd(sunset_forobs)-0.1)).\ + filter(Q(mjd_requested__lte = date_to_mjd(sunrise_forobs)+0.1) | Q(obs_mjd__lte = date_to_mjd(sunrise_forobs)+0.1)).\ + filter(survey_field__instrument__name='GPC2') + + if not len(survey_obs_ps1) and not len(survey_obs_ps2): continue + ztf_obs_ps1_ids = survey_obs_ps1.filter(obs_mjd__isnull=False).values_list('survey_field__ztf_field_id',flat=True).distinct() + ztf_sched_ps1_ids = survey_obs_ps1.filter(obs_mjd__isnull=True).values_list('survey_field__ztf_field_id',flat=True).distinct() + ztf_obs_ps2_ids = survey_obs_ps2.filter(obs_mjd__isnull=False).values_list('survey_field__ztf_field_id',flat=True).distinct() + ztf_sched_ps2_ids = survey_obs_ps2.filter(obs_mjd__isnull=True).values_list('survey_field__ztf_field_id',flat=True).distinct() - ztf_obs_str = '' - for z in ztf_obs_ids: - filters = survey_obs.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() - ztf_obs_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) - ztf_sched_str = '' - for z in ztf_sched_ids: - if z in ztf_obs_ids: continue - filters = survey_obs.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() - ztf_sched_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) + ztf_obs_ps1_str = '' + for z in ztf_obs_ps1_ids: + filters = survey_obs_ps1.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() + ztf_obs_ps1_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) + ztf_sched_ps1_str = '' + for z in ztf_sched_ps1_ids: + if z in ztf_obs_ps1_ids: continue + filters = survey_obs_ps1.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() + ztf_sched_ps1_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) + ztf_obs_ps2_str = '' + for z in ztf_obs_ps2_ids: + filters = survey_obs_ps2.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() + ztf_obs_ps2_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) + ztf_sched_ps2_str = '' + for z in ztf_sched_ps2_ids: + if z in ztf_obs_ps2_ids: continue + filters = survey_obs_ps2.filter(survey_field__ztf_field_id=z).values_list('photometric_band__name',flat=True).distinct() + ztf_sched_ps2_str += '%s: %s; '%(z.__str__(),','.join([f.__str__() for f in filters])) - if len(survey_obs): - obstuple += ((ztf_obs_str[:-2],date, - '%i%%'%(moon_illumination(time)*100),colors[i%len(colors)],ztf_sched_str[:-2]),) + if len(survey_obs_ps1) and len(survey_obs_ps2): + obstuple += ((ztf_obs_ps1_str[:-2],date, + '%i%%'%(moon_illumination(time)*100),colors[i%len(colors)],ztf_sched_ps1_str[:-2],ztf_obs_ps2_str[:-2],ztf_sched_ps2_str[:-2]),) + elif len(survey_obs_ps1) and not len(survey_obs_ps2): + obstuple += ((ztf_obs_ps1_str[:-2],date, + '%i%%'%(moon_illumination(time)*100),colors[i%len(colors)],ztf_sched_ps1_str[:-2],'None','None'),) + elif len(survey_obs_ps2) and not len(survey_obs_ps1): + obstuple += (('None',date, + '%i%%'%(moon_illumination(time)*100),colors[i%len(colors)],'None',ztf_obs_ps2_str[:-2],ztf_sched_ps2_str[:-2]),) context = { 'all_obs': obstuple, 'utc_time': datetime.datetime.utcnow().isoformat().replace(' ','T'), } + return render(request, 'YSE_App/yse_observing_calendar.html', context) @login_required diff --git a/YSE_App/yse_utils/add_yse_fields.py b/YSE_App/yse_utils/add_yse_fields.py new file mode 100644 index 00000000..1b96f0f1 --- /dev/null +++ b/YSE_App/yse_utils/add_yse_fields.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# D. Jones - 8/9/22 +"""script for adding new YSE fields via the YSE-PZ API. +Unlike existing utilities, this takes exact pointings +for each field (one at a time) and assigns those to an +MSB""" + +# python YSE_App/yse_utils/add_yse_fields.py -s YSE_PZ/settings.ini --name=298.A --ra=01:59:49.157 --dec=-17:03:00 --instrument=GPC2 + +import argparse +import configparser +import requests +from requests.auth import HTTPBasicAuth +from astropy.coordinates import SkyCoord +import astropy.units as u + +class add_yse_fields: + def __init__(self): + pass + + def add_args(self, parser=None, usage=None, config=None): + + if parser == None: + parser = argparse.ArgumentParser(usage=usage, conflict_handler="resolve") + + parser.add_argument('-s','--settingsfile', default=None, type=str, + help='settings file (login/password info)') + parser.add_argument('-n','--name', default=None, type=str, + help='field name, format should be .') + parser.add_argument('-r','--ra', default=None, type=str, + help='field RA (decimal or sexigesimal)') + parser.add_argument('-d','--dec', default=None, type=str, + help='field Dec (decimal or sexigesimal)') + parser.add_argument('-i','--instrument', default=None, type=str, + help='instrument (GPC1 or GPC2)') + + if config: + parser.add_argument('--dblogin', default=config.get('main','dblogin'), type=str, + help='gmail login (default=%default)') + parser.add_argument('--dbpassword', default=config.get('main','dbpassword'), type=str, + help='gmail password (default=%default)') + parser.add_argument('--dbemailpassword', default=config.get('main','dbemailpassword'), type=str, + help='gmail password (default=%default)') + parser.add_argument('--dburl', default=config.get('main','dburl'), type=str, + help='base URL to POST/GET,PUT to/from a database (default=%default)') + + return parser + + def main(self): + + # check name format + if '.' not in self.options.name and len(self.options.name.split('.')[-1]) > 1: + raise RuntimeError('invalid field name format') + if 'P2.' not in self.options.name and self.options.instrument == 'GPC2': + raise RuntimeError(f"if instrument is GPC2, field must have 'P2.' at the end of numeric field ID") + + # see if MSB exists; if it doesn't, create a new MSB + msb_name = self.options.name.split('.')[0] + rmsb = requests.get( + url=f'{self.options.dburl}surveyfieldmsbs/?name={msb_name}', + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)) + if not rmsb.status_code == 200: + raise RuntimeError('MSB query failed') + rmsb = rmsb.json()['results'] + + # which group is the YSE group? There must be a better way to do this.... + ryse = requests.get( + url=f'{self.options.dburl}observationgroups/?name=YSE', + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)).json() + yse_group = ryse['results'][0]['url'] + + rinst = requests.get( + url=f'{self.options.dburl}instruments/?name={self.options.instrument}', + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)).json() + instrument = rinst['results'][0]['url'] + + + if not len(rmsb): + + msb_dict = {'obs_group':yse_group, + 'name':self.options.name.split('.')[0], + 'active':0} + rmsb = requests.post( + url='%ssurveyfieldmsbs/'%self.options.dburl,json=msb_dict, + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)) + if not rmsb.status_code == 200 and not rmsb.status_code == 201: + raise RuntimeError('MSB was not added successfully') + rmsb = rmsb.json() + else: + rmsb = rmsb[0] + + # we'll use this URL to patch the MSB with new filters + msb_id = rmsb['id'] + + # see if the survey field exists in the database already + try: + rfield = requests.get( + url=f'%ssurveyfields/?field_id={self.options.name}'%self.options.dburl, + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)).json() + except: + import pdb; pdb.set_trace() + + if len(rfield['results']): + # if it exists, make sure it's associated with the MSB + field_in_msb = False + for field in rmsb['survey_fields']: + if field['field_id'] == self.options.name: + field_in_msb = True + if field_in_msb: + print(f'field {self.options.name} exists and is already associated with MSB {msb_name}') + return + + # if field is not in the MSB, we need to add it + print(f'field {self.options.name} exists but is not associated with MSB {msb_name}') + print('adding it now...') + survey_field_list = [{'id':rfield['results'][0]['url'].split('/')[-2]}] + if len(rmsb['survey_fields']): + survey_field_list += [{'id':sf['id']} for sf in rmsb['survey_fields'] \ + if sf['id'] != rfield['results'][0]['url'].split('/')[-2]] + rmsb_add = requests.put(url=f'{self.options.dburl}surveyfieldmsbs/{msb_id}/', + json={'obs_group':yse_group,'name':msb_name, + 'survey_fields':survey_field_list}, + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)) + if not rmsb_add.status_code == 200: + raise RuntimeError('field was not associated with MSB successfully') + + return + + # now parse the coordinates of the new field + try: + ra,dec = float(self.options.ra),float(self.options.dec) + sc = SkyCoord(ra,dec,unit=u.deg) + except: + sc = SkyCoord(self.options.ra,self.options.dec,unit=(u.hour,u.deg)) + + # if field does not exist, we need to create it and add it to the MSB + field_dict = {'obs_group':yse_group, + 'instrument':instrument, + 'field_id':self.options.name, + 'cadence':3.0, + 'ztf_field_id':msb_name.replace('P2',''), + 'ra_cen':sc.ra.deg, + 'dec_cen':sc.dec.deg, + 'width_deg':3.1, + 'height_deg':3.1} + + rfield = requests.post( + url=f'{self.options.dburl}surveyfields/',json=field_dict, + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)) + if not rfield.status_code == 201: + raise RuntimeError('field was not added successfully') + rfield = rfield.json() + + # add to the MSB + survey_field_list = [{'id':rfield['url'].split('/')[-2]}] + if len(rmsb['survey_fields']): + survey_field_list += [{'id':sf['id']} for sf in rmsb['survey_fields'] \ + if sf['id'] != rfield['url'].split('/')[-2]] + #survey_field_list = [{'id':sf['url'].split('/')[-2]} for sf in rmsb.json()['results'][0]['survey_fields']] + + rmsb_add = requests.put(url=f'{self.options.dburl}surveyfieldmsbs/{msb_id}/', + json={'obs_group':yse_group,'name':msb_name, + 'survey_fields':survey_field_list}, + auth=HTTPBasicAuth(self.options.dblogin,self.options.dbpassword)) + if not rmsb_add.status_code == 200: + raise RuntimeError('field was not associated with MSB successfully') + + + print(f'successfully added field {self.options.name} at coords {sc.ra.deg,sc.dec.deg}') + + +if __name__ == "__main__": + ayf = add_yse_fields() + + # read args + parser = ayf.add_args(usage='') + args = parser.parse_args() + if args.settingsfile: + config = configparser.ConfigParser() + config.read(args.settingsfile) + else: config=None + parser = ayf.add_args(usage='',config=config) + args = parser.parse_args() + ayf.options = args + + ayf.main() + print('success!') diff --git a/YSE_App/yse_utils/get_YSE_PAs.py b/YSE_App/yse_utils/get_YSE_PAs.py new file mode 100644 index 00000000..61eaf3da --- /dev/null +++ b/YSE_App/yse_utils/get_YSE_PAs.py @@ -0,0 +1,521 @@ +#!/export/home/lowe/anaconda3/bin/python3 + + +# PA GENERATION FOR PS2 +# Version 4.5 --- added ID info to header +# Version 4.4 --- advance one day if being run before UT midnight +# Version 4.3 --- option to use NO randomized offset, for debugging purposes +# Version 4.2 --- output numbers of transients picked up by each PA +# output format slightly different, won't work with +# ysched.py version earlier than 4.0 +# Version 4.1 --- add an random offset to the list of PAs +# to address persistence problems +# Version 4.0 --- calculates multiple PAs +# Formerly known as get_YSE_PAs.newdj_041321.v2.py +# Version 2.0 --- prints out filters as well as PAs +############### + +import astropy.coordinates as cd +import astropy.units as u +import numpy as np +from matplotlib.patches import Rectangle +import matplotlib +import matplotlib.pyplot as plt +import matplotlib.cm as cm +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +from matplotlib.figure import Figure +from matplotlib.dates import DateFormatter +from matplotlib import rcParams +import subprocess +from random import sample, shuffle +import argparse +import configparser +import datetime +import requests +from requests.auth import HTTPBasicAuth +import json +from astropy.coordinates import SkyCoord + +from astropy.time import Time, TimeDelta +from astroplan import Observer +tel = Observer.at_site('keck', timezone='US/Hawaii') + +# For local stuff +import sys +import os.path +import getpass +# sys.path.append("/otis/ops/src/python") +# import ps1util +import socket +import pprint + + +def date_to_mjd(date): + time = Time(date,scale='utc') + return time.mjd + +def mjd_to_date(mjd): + time = Time(mjd,format='mjd',scale='utc') + return time.isot + +def GetSexigesimalString(ra_decimal, dec_decimal): + c = SkyCoord(ra_decimal,dec_decimal,unit=(u.deg, u.deg)) + ra = c.ra.hms + #dec = c.dec.dms + dec = np.array(c.dec.to_string(precision=2).replace('d',':').replace('m',':').replace('s','').split(':')).astype(float) + ra_string = "%02d:%02d:%05.2f" % (ra[0],ra[1],ra[2]) + if dec[0] >= 0: + dec_string = "+%02d:%02d:%05.2f" % (dec[0],np.abs(dec[1]),np.abs(dec[2])) + else: + dec_string = "%03d:%02d:%05.2f" % (dec[0],np.abs(dec[1]),np.abs(dec[2])) + + # Python has a -0.0 object. If the deg is this (because object lies < 60 min south), the string formatter will drop the negative sign + if c.dec < 0.0 and dec[0] == 0.0: + dec_string = "-00:%02d:%05.2f" % (np.abs(dec[1]),np.abs(dec[2])) + return (ra_string, dec_string) + +class YSE_PA: + + def __init__(self): + pass + + def add_arguments(self, parser=None, usage=None, config=None): + if parser == None: + parser = argparse.ArgumentParser(usage=usage, conflict_handler="resolve") + + # The basics + parser.add_argument('-s','--settingsfile', default=None, type=str, + help='settings file (login/password info)') + parser.add_argument('-v', '--verbose', action="count", dest="verbose", + default=0,help='verbosity level') + parser.add_argument('--telescope',type=str,default='PS1',help='either PS1 or PS2') + parser.add_argument('-noo', '--noo', action="store_true", help="do not add random offset to PA") + parser.add_argument('-c', '--cron', action="store_true", help="use if calling from cron (e.g.)") + parser.add_argument('--fieldlist',type=str,default=None,help='optional comma-separated list giving fields that need PAs') + parser.add_argument('--mjds_to_schedule',type=str,default=None,help='optional comma-separated list giving the times that each field should be scheduled. Length must match length of --fieldlist argument') + parser.add_argument('--list_transients', action="store_true", help="list transients for each PA if set (lot of output but potentially useful)") + + if config: + parser.add_argument('--yseurl', type=str, default=config.get('main','yseurl'), + help='YSE URL') + parser.add_argument('-u','--yseuser', type=str, default=config.get('main','yseuser'), + help='YSE user name') + parser.add_argument('-p','--ysepass', type=str, default=config.get('main','ysepass'), + help='YSE password') + parser.add_argument('--goodcellsfile_ps1', type=str, default=config.get('main','goodcellsfile_ps1'), + help='file with the good PS1 cells') + parser.add_argument('--goodcellsfile_ps2', type=str, default=config.get('main','goodcellsfile_ps2'), + help='file with the good PS2 cells') + parser.add_argument('--pscoords',type=str,default=config.get('main','pscoords'), + help='path to pscoords binary') + + + return parser + + # OLD VERSION NO LONGER USED ! + def yse_pa(self,msb_fields,msb_ras,msb_decs,transients_all,transients_goodcell,status_all,pa=None): + + transients_best,transients_2best,transients_3best,transients_4best = [],[],[],[] + transients_best_ra,transients_2best_ra,transients_3best_ra,transients_4best_ra = [],[],[],[] + transients_best_dec,transients_2best_dec,transients_3best_dec,transients_4best_dec = [],[],[],[] + for f,ra,ddec in zip(msb_fields,msb_ras,msb_decs): + # find the transients in the field + r = requests.get(f'{self.options.yseurl}/box_search/{ra}/{ddec}/1.65/', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + data = json.loads(r.text)['transients'] + for d in data: + if d['transient_name'] in transients_goodcell: + transients_best += [d['transient_name']] + transients_ra += [d['transient_ra']] + transients_dec += [d['transient_dec']] + elif d['transient_name'] in transients_all: + iTr = transients_all == d['transient_name'] + if status_all[iTr][0] == 'Interesting': + transients_2best += [d['transient_name']] + transients_2best_ra += [d['transient_ra']] + transients_2best_dec += [d['transient_dec']] + elif status_all[iTr][0] == 'FollowupRequested': + transients_3best += [d['transient_name']] + transients_3best_ra += [d['transient_ra']] + transients_3best_dec += [d['transient_dec']] + elif status_all[iTr][0] == 'Following': + transients_4best += [d['transient_name']] + transients_4best_ra += [d['transient_ra']] + transients_4best_dec += [d['transient_dec']] + + if not len(np.concatenate((transients_best,transients_2best,transients_3best,transients_4best))): + return None,None + + scf = SkyCoord(msb_ras[0],msb_decs[0],unit=u.deg) + + # figure out the PA for today, best airmass + if self.options.mjds_to_schedule is None or msb_fields[0].split('.')[0] not in self.options.fieldlist: + print('no preferred MJD given for field %s'%msb_fields[0].split('.')[0]) + + + + # If we're running this before UT midnight, advance one day + + t = Time.now() + + # We're not using this sub now, but I'll add this code anyway, + # just in case we ever do + # how can I define this globally?? + UTnow = datetime.datetime.utcnow() + UThour = UTnow.hour + if UThour > 16: + adday = TimeDelta(86400.0, format='sec') + t += adday + + time_start='05:00:00'; time_end='15:00:00' + night_start = tel.twilight_evening_astronomical(t,which="previous") + night_end = tel.twilight_morning_astronomical(t,which="previous") + hourmin,hourmax = int(night_start.iso.split()[-1].split(':')[0]),int(night_end.iso.split()[-1].split(':')[0]) + airmass,times = np.array([]),np.array([]) + for hour in range(hourmin,hourmax+1): + time_obs = '%s %02i:%s:00'%(t.iso.split()[0],hour,time_start.split(':')[1]) + time = Time(time_obs) + altaz = tel.altaz(time,scf) + if altaz.alt.value < 0: continue + airmass = np.append(airmass,1/np.cos((90.-altaz.alt.value)*np.pi/180.)) + times = np.append(times,time) + + time = times[airmass == np.min(airmass)] + else: + time = [mjd_to_date(self.options.mjds_to_schedule[self.options.fieldlist == msb_fields[0].split('.')[0]][0])] + + parallactic_angle = tel.parallactic_angle(time[0],scf) + + if pa is not None: + rotator_angles = np.array([180 - pa + parallactic_angle.deg]) + else: + rotator_angles = np.linspace(20,160,30) + len_good,list_full = [],[] + for rotator_angle in rotator_angles: + good_list = [] + pa = 180 - (-parallactic_angle.deg + rotator_angle) + for i,transient_list,transient_ra,transient_dec in zip( + range(len([transients_4best,transients_3best,transients_2best,transients_best])), + [transients_4best,transients_3best,transients_2best,transients_best], + [transients_4best_ra,transients_3best_ra,transients_2best_ra,transients_best_ra], + [transients_4best_dec,transients_3best_dec,transients_2best_dec,transients_best_dec]): + for transient,tra,tdec in zip(transient_list,transient_ra,transient_dec): + cmd = "echo %.7f %.7f | %s in=sky out=cell ra=%.7f dec=%.7f pa=%.1f dx=0 dy=0 dpa=0 sc=38.856"%( + tra,tdec,self.options.pscoords,msb_ras[0],msb_decs[0],pa) + output = subprocess.check_output(cmd, shell=True) + ota,cell,centerx,centery = output.split() + if 'OTA'+ota.decode('utf-8') in self.goodcells.keys() and cell.decode('utf-8') in self.goodcells['OTA'+ota.decode('utf-8')]: + if i < 3: good_list += [transient] + else: good_list += [transient]*4 + len_good += [len(good_list)] + list_full += [[t for t in np.unique(good_list)],] + + iGood = np.argsort(len_good)[::-1][0:5] + best_idx = sample(iGood.tolist(),1) + best_rotator = rotator_angles[best_idx] + list_good = np.array(list_full)[best_idx][0] + best_pa = 180 - (-parallactic_angle.deg + best_rotator[0]) + + return best_pa,list_good + + def yse_pa_new(self,msb_fields,msb_ras,msb_decs,transients_all,transients_goodcell,status_all,poffset,pa=None): + + transients_best,transients_2best,transients_3best,transients_4best = [],[],[],[] + transients_best_ra,transients_2best_ra,transients_3best_ra,transients_4best_ra = [],[],[],[] + transients_best_dec,transients_2best_dec,transients_3best_dec,transients_4best_dec = [],[],[],[] + transients_best_field,transients_2best_field,transients_3best_field,transients_4best_field = [],[],[],[] + for f,ra,ddec in zip(msb_fields,msb_ras,msb_decs): + # find the transients in the field + r = requests.get(f'{self.options.yseurl}/box_search/{ra}/{ddec}/1.65/', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + data = json.loads(r.text)['transients'] + for d in data: + # verify the transient actually is in the field + sc = SkyCoord(d['transient_ra'],d['transient_dec'],unit=u.deg) + scf = SkyCoord(ra,ddec,unit=u.deg) + if scf.separation(sc).deg > 1.65: continue + #if '575' in f and d['transient_name'] == '2022hss': + # import pdb; pdb.set_trace() + if d['transient_name'] in transients_goodcell: + transients_best += [d['transient_name']] + transients_best_ra += [d['transient_ra']] + transients_best_dec += [d['transient_dec']] + transients_best_field += [f] + elif d['transient_name'] in transients_all: + iTr = transients_all == d['transient_name'] + if status_all[iTr][0] == 'Interesting': + transients_2best += [d['transient_name']] + transients_2best_ra += [d['transient_ra']] + transients_2best_dec += [d['transient_dec']] + transients_2best_field += [f] + elif status_all[iTr][0] == 'FollowupRequested': + transients_3best += [d['transient_name']] + transients_3best_ra += [d['transient_ra']] + transients_3best_dec += [d['transient_dec']] + transients_3best_field += [f] + elif status_all[iTr][0] == 'Following': + transients_4best += [d['transient_name']] + transients_4best_ra += [d['transient_ra']] + transients_4best_dec += [d['transient_dec']] + transients_4best_field += [f] + + if not len(np.concatenate((transients_best,transients_2best,transients_3best,transients_4best))): + return None,None + + scf = SkyCoord(msb_ras[0],msb_decs[0],unit=u.deg) + + len_good,list_full = [],[] + origpalist = np.arange(0,359,10) + + # add random offset to PA + def addpoff(x): + return(x + poffset) % 360 + palist = addpoff(origpalist) + + # DIAG + currfield = msb_fields[0].split('.')[0] + # palist = np.arange(0,180,5) # ORIG + for pa in palist: + + # DIAG + # sys.stderr.write("field: %s trying PA: %s\n" % (currfield, pa)) + + good_list = [] + for i,transient_list,transient_ra,transient_dec,transient_field in zip( + range(len([transients_4best,transients_3best,transients_2best,transients_best])), + [transients_4best,transients_3best,transients_2best,transients_best], + [transients_4best_ra,transients_3best_ra,transients_2best_ra,transients_best_ra], + [transients_4best_dec,transients_3best_dec,transients_2best_dec,transients_best_dec], + [transients_4best_field,transients_3best_field,transients_2best_field,transients_best_field]): + for transient,tra,tdec,tfield in zip(transient_list,transient_ra,transient_dec,transient_field): + + msbr,msbd = msb_ras[msb_fields == tfield][0],msb_decs[msb_fields == tfield][0] + cmd = "echo %.7f %.7f | %s in=sky out=cell ra=%.7f dec=%.7f pa=%.1f dx=0 dy=0 dpa=0 sc=38.856"%( + tra,tdec,self.options.pscoords,msbr,msbd,pa) + output = subprocess.check_output(cmd, shell=True) + ota,cell,centerx,centery = output.split() + if 'OTA'+ota.decode('utf-8') in self.goodcells.keys() and cell.decode('utf-8') in self.goodcells['OTA'+ota.decode('utf-8')]: + if i < 3: good_list += [transient] + else: good_list += [transient]*4 + #import pdb; pdb.set_trace() + len_good += [len(good_list)] + list_full += [[t for t in np.unique(good_list)],] + + iGood = np.argsort(len_good)[::-1][0:5] + best_pa = palist[iGood] + list_good = np.array(list_full)[iGood] + # DIAG + # sys.stderr.write("list_good: %s best_pa: %s\n" % (list_good, best_pa)) + + return best_pa,list_good + + + def get_requested_fields(self): + + # If we're running this before UT midnight, add a day + UTnow = datetime.datetime.utcnow() + UThour = UTnow.hour + mjddate = UTnow + if UThour > 16: + mjddate = mjddate + datetime.timedelta(days=1) + + # get tonight's observation requests + startmjd = date_to_mjd(mjddate.date().isoformat()) + r = requests.get(f'{self.options.yseurl}/api/surveyobservations/?mjd_requested_gte={startmjd}&mjd_requested_lte={startmjd+1}&limit=1000&instrument={self.options.instrument}', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + data_results = json.loads(r.text)['results'] + + # match to survey field names + # here he's getting ALL the survey fields, and will later compare them + # with the surveyobservations fields + r = requests.get(f'{self.options.yseurl}/api/surveyfields/?limit=3000', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + surveyfielddata = json.loads(r.text)['results'] + + + filtdict = {} + fieldfilts = {} + # get all the photometric bands + r = requests.get(f'{self.options.yseurl}/api/photometricbands/?limit=1000', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + pbdata = json.loads(r.text)['results'] + for pb in pbdata: + filtdict[pb['url']] = pb['name'] + + field_msbs,fields,obs_mjds,ras,decs,obs_dates = np.array([]),np.array([]),np.array([]),np.array([]),np.array([]),np.array([]) + for d in data_results: # data_results is the requested fields + survey_field_url = d['survey_field'] + obs_mjd = d['obs_mjd'] + pb_url = d['photometric_band'] + if d['obs_mjd'] is None: obs_mjd = d['mjd_requested'] + obs_mjds = np.append(obs_mjds,obs_mjd) + obs_dates = np.append(obs_dates,mjd_to_date(obs_mjd)) + for s in surveyfielddata: # surveyfielddata is the defined fields + if s['url'] == survey_field_url: + # "fields" is full position e.g. 666.F + fields = np.append(fields,s['field_id']) + # "field_msbs" is the overall field name e.g. 666 + field_msbs = np.append(field_msbs,s['field_id'].split('.')[0]) + ras = np.append(ras,s['ra_cen']) + decs = np.append(decs,s['dec_cen']) + + # create a dict associating filters with the + # overall field names + thisfield = s['field_id'].split('.')[0] + thisfilt = filtdict[pb_url] + fieldfilts.setdefault(thisfield, set()).add(thisfilt) + # Because there are multiple filters per field name, + # I can't just np.append them as is done above + # the filters have twice as many list elements + # as the fields + + + fielddict = {} + fields_unique,idx = np.unique(fields,return_index=True) + fields,ras,decs,field_msbs = fields[idx],ras[idx],decs[idx],field_msbs[idx] + for f in np.unique(field_msbs): + fielddict[f] = ((fields[field_msbs == f]),(ras[field_msbs == f]),(decs[field_msbs == f])) + + return fielddict,fieldfilts + + def main(self): + + + fielddict,fieldfilts = self.get_requested_fields() + + + transients_all,transients_goodcell,status_all = np.array([]),np.array([]),np.array([]) + r = requests.get(f'{self.options.yseurl}/query_api/all_yse_transients/', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + data_all = json.loads(r.text)['transients'] + r = requests.get(f'{self.options.yseurl}/query_api/yse_transients_goodcell/', + auth=HTTPBasicAuth(self.options.yseuser,self.options.ysepass)) + data_goodcell = json.loads(r.text)['transients'] + for dg in data_goodcell: + transients_goodcell = np.append(transients_goodcell,dg['name']) + for da in data_all: + transients_all = np.append(transients_all,da['name']) + status_all = np.append(status_all,da['status']) + + + best_pa_list = [] + trans_list = [] + final_transients = {} + + origPAoffsets = list(range(10)) + usePAoffsets = [] + + output = "" + for f in fielddict.keys(): + # apply a random single digit offset to the PA + if len(usePAoffsets) == 0: + # this takes care of the unlikely case in which we have more + # than 10 YSE fields: the offset array will be replenished as + # often as needed + # randomize the offsets here + usePAoffsets = origPAoffsets[:] + shuffle(usePAoffsets) + if args.noo is True: + PAoffset = 0 + else: + PAoffset = usePAoffsets.pop() + best_pa,list_good = self.yse_pa_new(fielddict[f][0],fielddict[f][1],fielddict[f][2], + transients_all,transients_goodcell,status_all,PAoffset) + # DIAG + # sys.stderr.write("field: %s list_good: %s best_pa: %s\n" % (f, list_good, best_pa)) + best_pa_list += [best_pa] + trans_list += [list_good] + final_transients[f] = list_good + # DIAG + # sys.stderr.write("field: %s best_pa_list: %s list_good: %s\n" % (f,best_pa_list,list_good)) + + + if args.cron is True: + user = getpass.getuser() + fullhostname = socket.gethostname() + hostname = fullhostname.split('.')[0] + thisScript = os.path.realpath(sys.argv[0]) + # header = "# run from cron on %s@%s\n#" % (user, hostname) + header1 = "# generated for PS2 by %s\n" % (thisScript) + header2 = "# run from cron on %s@%s\n#" % (user, hostname) + header = header1 + header2 + else: + header = "#\n#\n#" + + + #print('field best_pa_m90 best_pa_merid best_pa_p90 filters') + for k,best_pa,tlist in zip(fielddict.keys(),best_pa_list,trans_list): + # sys.stderr.write("k: %s, best_pa_list: %s, trans_list: %s\n" % (k, best_pa, tlist)) + if best_pa is None: + outpa = "None" + outtrans = "None" + else: + # are these *already* numpy arrays? Can't tell! + bparray = np.array(best_pa) + trarray = np.array(tlist) + # these are the indices which sort the best_pa list + idx = np.argsort(bparray) + # sorted arrays + bplist = np.array(bparray)[idx] + trlist = np.array(trarray)[idx] + # number of transients for each PA, in order of increasing PA + numtrans = list(map(lambda x: len(x), trlist)) + outpa = ','.join(map(str, bplist)) + outtrans = ','.join(map(str, numtrans)) + # print(f"{k} {','.join(fieldfilts[k])} {outpa} {outtrans}") + if self.options.list_transients: + if outpa != "None": + outtr = '['+','.join(np.concatenate(trlist))+']' + else: + outtr = '' + output += f"\n{k} {','.join(fieldfilts[k])} {outpa} {outtrans} {outtr}" + else: + output += f"\n{k} {','.join(fieldfilts[k])} {outpa} {outtrans}" + # OK WE'RE OUTPUTTING AN EXTRA CARRIAGE RETURN GOTTA FIX THAT + + if len(output) == 0: + sys.exit() + else: + print(header + output) + + + +if __name__ == "__main__": + ys = YSE_PA() + # read args + parser = ys.add_arguments(usage='') + args = parser.parse_args() + if args.settingsfile: + config = configparser.ConfigParser() + config.read(args.settingsfile) + else: config=None + parser = ys.add_arguments(usage='',config=config) + args = parser.parse_args() + ys.options = args + + + + if ys.options.fieldlist is not None: + ys.options.fieldlist = np.array(ys.options.fieldlist.split(',')) + if ys.options.mjds_to_schedule is not None: + ys.options.mjds_to_schedule = np.array(ys.options.mjds_to_schedule.split(',')).astype(float) + if ys.options.fieldlist is None: raise RuntimeError('if --mjds_to_schedule is given, fieldlist must be as well') + if len(ys.options.fieldlist) != len(ys.options.mjds_to_schedule): + raise RuntimeError('--fieldlist and --mjds_to_schedule must be the same length') + + ys.goodcells = {} + if ys.options.telescope == 'PS1': + goodcellsfile = ys.options.goodcellsfile_ps1 + ys.options.instrument = 'GPC1' + elif ys.options.telescope == 'PS2': + goodcellsfile = ys.options.goodcellsfile_ps2 + ys.options.instrument = 'GPC2' + else: + raise RuntimeError('telescope must be either PS1 or PS2') + + with open(goodcellsfile) as fin: + for line in fin: + ys.goodcells[line.split()[0][:-1]] = line.split()[1:] + + + ys.main() diff --git a/YSE_App/yse_views.py b/YSE_App/yse_views.py index 14647ba9..05fbcf57 100644 --- a/YSE_App/yse_views.py +++ b/YSE_App/yse_views.py @@ -20,15 +20,21 @@ @login_required def select_yse_fields(request): - all_yse_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').distinct().order_by('name') - active_yse_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').filter(active=True).distinct().order_by('name') - active_names = active_yse_fields.values_list('name',flat=True) + all_yse_gpc1_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').filter(survey_fields__instrument__name='GPC1').distinct().order_by('name') + active_yse_gpc1_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').filter(survey_fields__instrument__name='GPC1').filter(active=True).distinct().order_by('name') + all_yse_gpc2_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').filter(survey_fields__instrument__name='GPC2').distinct().order_by('name') + active_yse_gpc2_fields = SurveyFieldMSB.objects.filter(survey_fields__obs_group__name='YSE').filter(survey_fields__instrument__name='GPC2').filter(active=True).distinct().order_by('name') + active_gpc1_names = active_yse_gpc1_fields.values_list('name',flat=True) + active_gpc2_names = active_yse_gpc2_fields.values_list('name',flat=True) + current_mjd = Time.now().mjd - yse_field_data = () + + # GPC1 fields + yse_gpc1_field_data = () last_obs_list = [] - for a in all_yse_fields: - if a.name in active_names: continue + for a in all_yse_gpc1_fields: + if a.name in active_gpc1_names: continue obs = SurveyObservation.objects.filter(survey_field=a.survey_fields.all()[0]).filter(obs_mjd__isnull=False).order_by('-obs_mjd') if len(obs): last_obs_date = obs[0].obs_mjd @@ -38,17 +44,38 @@ def select_yse_fields(request): days_since_obs = None airmass = 0 last_obs_list += [days_since_obs if days_since_obs is not None else 1000] - yse_field_data += ((a,last_obs_date,days_since_obs,airmass),) + yse_gpc1_field_data += ((a,last_obs_date,days_since_obs,airmass),) idx = np.argsort(last_obs_list) yse_field_data_new = () for i in idx: - yse_field_data_new += (yse_field_data[i],) - yse_field_data = yse_field_data_new + yse_field_data_new += (yse_gpc1_field_data[i],) + yse_gpc1_field_data = yse_field_data_new - - active_yse_field_data = () + # GPC2 fields + yse_gpc2_field_data = () + last_obs_list = [] + for a in all_yse_gpc2_fields: + if a.name in active_gpc2_names: continue + obs = SurveyObservation.objects.filter(survey_field=a.survey_fields.all()[0]).filter(obs_mjd__isnull=False).order_by('-obs_mjd') + if len(obs): + last_obs_date = obs[0].obs_mjd + days_since_obs = current_mjd - last_obs_date + else: + last_obs_date = None + days_since_obs = None + airmass = 0 + last_obs_list += [days_since_obs if days_since_obs is not None else 1000] + yse_gpc2_field_data += ((a,last_obs_date,days_since_obs,airmass),) + idx = np.argsort(last_obs_list) + yse_field_data_new = () + for i in idx: + yse_field_data_new += (yse_gpc2_field_data[i],) + yse_gpc2_field_data = yse_field_data_new + + # active GPC1 fields + active_yse_gpc1_field_data = () first_obs_list = [] - for a in active_yse_fields: + for a in active_yse_gpc1_fields: obs = SurveyObservation.objects.filter(survey_field=a.survey_fields.all()[0]).filter(obs_mjd__isnull=False).order_by('-obs_mjd') obs_mjd = np.sort(np.array([om for om in obs.values_list('obs_mjd',flat=True)])) if len(obs_mjd): @@ -70,26 +97,59 @@ def select_yse_fields(request): days_since_obs = None airmass = 0 first_obs_list += [days_since_obs if days_since_obs is not None else 10000] - active_yse_field_data += ((a,first_obs,days_since_obs,airmass),) + active_yse_gpc1_field_data += ((a,first_obs,days_since_obs,airmass),) idx = np.argsort(first_obs_list)[::-1] active_yse_field_data_new = () for i in idx: - active_yse_field_data_new += (active_yse_field_data[i],) - active_yse_field_data = active_yse_field_data_new + active_yse_field_data_new += (active_yse_gpc1_field_data[i],) + active_yse_gpc1_field_data = active_yse_field_data_new - + # active GPC2 fields + active_yse_gpc2_field_data = () + first_obs_list = [] + for a in active_yse_gpc2_fields: + obs = SurveyObservation.objects.filter(survey_field=a.survey_fields.all()[0]).filter(obs_mjd__isnull=False).order_by('-obs_mjd') + obs_mjd = np.sort(np.array([om for om in obs.values_list('obs_mjd',flat=True)])) + if len(obs_mjd): + + if len(obs_mjd[:-1][obs_mjd[1:]-obs_mjd[:-1] > 60]): + first_obs = obs_mjd[1:][obs_mjd[1:]-obs_mjd[:-1] > 60][0] + else: + first_obs = obs_mjd[0] + else: + first_obs = None + + obs_mjd = obs.values_list('obs_mjd',flat=True) + if len(obs): + + last_obs_date = obs[0].obs_mjd + days_since_obs = current_mjd - first_obs + else: + last_obs_date = None + days_since_obs = None + airmass = 0 + first_obs_list += [days_since_obs if days_since_obs is not None else 10000] + active_yse_gpc2_field_data += ((a,first_obs,days_since_obs,airmass),) + idx = np.argsort(first_obs_list)[::-1] + active_yse_field_data_new = () + for i in idx: + active_yse_field_data_new += (active_yse_gpc2_field_data[i],) + active_yse_gpc2_field_data = active_yse_field_data_new + + # moving fields form yse_move_field_form = yse_forms.YSEMoveFieldsForm() yse_group = ObservationGroup.objects.get(name='YSE') GPC1 = Instrument.objects.get(name='GPC1') all_yse_fields = SurveyField.objects.filter(obs_group__name='YSE').order_by('field_id') -# import pdb; pdb.set_trace() - context = {'yse_field_data':yse_field_data, - 'active_yse_field_data':active_yse_field_data, + #import pdb; pdb.set_trace() + context = {'yse_gpc1_field_data':yse_gpc1_field_data, + 'active_yse_gpc1_field_data':active_yse_gpc1_field_data, + 'yse_gpc2_field_data':yse_gpc2_field_data, + 'active_yse_gpc2_field_data':active_yse_gpc2_field_data, 'yse_move_field_form':yse_move_field_form, 'yse_group':yse_group, - 'GPC1':GPC1, 'all_yse_fields':all_yse_fields} return render(request, 'YSE_App/select_yse_fields.html', context) diff --git a/YSE_PZ/settings.py b/YSE_PZ/settings.py index 875aedc0..26084b44 100755 --- a/YSE_PZ/settings.py +++ b/YSE_PZ/settings.py @@ -53,7 +53,8 @@ 'django_filters', 'django_cron', 'el_pagination', - 'auditlog', + 'auditlog' + #'django_bootstrap3_multidatepicker.django_bootstrap3_multidatepicker' #'silk' ] @@ -140,7 +141,7 @@ # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases -#import pymysql +# import pymysql DATABASES = { 'explorer': { 'ENGINE': 'django.db.backends.mysql', @@ -160,8 +161,8 @@ 'OPTIONS': {'ssl': {'ssl_disabled': True}} } } -#pymysql.version_info = (1, 4, 2, "final", 0) -#pymysql.install_as_MySQLdb() +# pymysql.version_info = (1, 4, 2, "final", 0) +# pymysql.install_as_MySQLdb() EXPLORER_CONNECTIONS = { 'Explorer': 'explorer' } EXPLORER_DEFAULT_CONNECTION = 'explorer' @@ -209,7 +210,7 @@ SMTP_PORT = config.get('SMTP_provider', 'SMTP_PORT') LCOGTUSER = config.get('main', 'lcogtuser') LCOGTPASS = config.get('main', 'lcogtpass') -ZTFPASS = config.get('yse_forcedphot','ztfforcedphotpass') +ZTFPASS = config.get('ztf','ztfforcedphotpass') KEPLER_API_ENDPOINT = "http://api.keplerscience.org/is-k2-observing" TNSUSER = config.get('main','tns_bot_name') TNSID = config.get('main','tns_bot_id') @@ -217,6 +218,7 @@ TNSDECAMUSER = config.get('main','tns_decam_bot_name') TNSDECAMID = config.get('main','tns_decam_bot_id') TNSDECAMAPIKEY = config.get('main','tnsdecamapikey') +REDYSEFILTER = config.get('yse','red_yse_filter') # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ @@ -240,7 +242,7 @@ MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' -ZTFTMPDIR = config.get('yse_forcedphot','ztfforcedtmpdir') +ZTFTMPDIR = config.get('ztf','ztfforcedtmpdir') SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') USE_X_FORWARDED_HOST = True diff --git a/docker/requirements.web.dev b/docker/requirements.web.dev index e69de29b..018e1f5e 100644 --- a/docker/requirements.web.dev +++ b/docker/requirements.web.dev @@ -0,0 +1 @@ +astro-ghost==0.1.33

NameRADecDays Since First ObsAirmass
{{ a.0.name }}
{{a.0.CoordString.0}}