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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name |
+ RA |
+ Dec |
+ Days Since Last Obs |
+ Airmass |
+
+
+
+ {% for a in yse_gpc2_field_data %}
+
+ {{ a.0.name }} |
+ {{a.0.CoordString.0}} |
+ {{a.0.CoordString.1}} |
+ {{ a.2|floatformat:0 }} |
+ {{a.3}} |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+
+ Name |
+ RA |
+ Dec |
+ Days Since First Obs |
+ Airmass |
+
+
+
+ {% for a in active_yse_gpc2_field_data %}
{{ a.0.name }} |
{{a.0.CoordString.0}} |
@@ -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