p2api 1.0.6__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- p2api/__about__.py +1 -0
- p2api/__init__.py +5 -0
- p2api/p2api.py +1808 -0
- p2api/utils/__init__.py +1 -0
- p2api/utils/add_absolute_time_intervals.py +399 -0
- p2api/utils/generate_finding_charts.py +260 -0
- p2api/utils/p2api_utils.py +304 -0
- p2api-1.0.6.dist-info/METADATA +61 -0
- p2api-1.0.6.dist-info/RECORD +12 -0
- p2api-1.0.6.dist-info/WHEEL +5 -0
- p2api-1.0.6.dist-info/entry_points.txt +3 -0
- p2api-1.0.6.dist-info/licenses/LICENSE +21 -0
p2api/utils/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# $Id: __init__.py 244843 2019-09-12 07:31:09Z jpritcha $
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
|
|
3
|
+
# $Id: generate_finding_charts.py 267033 2021-09-16 11:08:57Z jpritcha $
|
|
4
|
+
from __future__ import print_function
|
|
5
|
+
|
|
6
|
+
_VERSION_ = "$Revision: 267033 $"
|
|
7
|
+
|
|
8
|
+
import sys # interaction with Python interpreter
|
|
9
|
+
from optparse import OptionParser # for parsing command line arguments
|
|
10
|
+
from optparse import OptionGroup
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
import keyring
|
|
15
|
+
import datetime
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
import p2api
|
|
19
|
+
import p2api.utils.p2api_utils as p2api_utils
|
|
20
|
+
|
|
21
|
+
from astropy.time import Time
|
|
22
|
+
import numpy as np
|
|
23
|
+
from astroplan import Observer
|
|
24
|
+
import astropy.units as u
|
|
25
|
+
|
|
26
|
+
################################################################################
|
|
27
|
+
default_eso_period=p2api_utils.current_ESO_period()+1
|
|
28
|
+
min_ATI_length=1.*u.hr
|
|
29
|
+
################################################################################
|
|
30
|
+
class get_options:
|
|
31
|
+
"get command line options"
|
|
32
|
+
|
|
33
|
+
def __init__(self, vers="0.0"):
|
|
34
|
+
# define options and arguments
|
|
35
|
+
parser = OptionParser(version="%prog "+vers, formatter=p2api_utils.IndentedHelpFormatterWithNL())
|
|
36
|
+
|
|
37
|
+
group = OptionGroup(parser, "Input OB(s)")
|
|
38
|
+
group.add_option(
|
|
39
|
+
"-i", "--ids",
|
|
40
|
+
dest="ids",
|
|
41
|
+
help="""\
|
|
42
|
+
List of run, container, folder, and/or OB IDs. \
|
|
43
|
+
Note that the ATCs will be applied to all OBs recursively when a \
|
|
44
|
+
run, container or folder is specified.
|
|
45
|
+
[required]\
|
|
46
|
+
""",
|
|
47
|
+
default=None
|
|
48
|
+
)
|
|
49
|
+
parser.add_option_group(group)
|
|
50
|
+
|
|
51
|
+
group = OptionGroup(parser, "Specify the Absolute Time Intervals explicity.")
|
|
52
|
+
group.add_option(
|
|
53
|
+
"--ATCs", dest="ATCs",
|
|
54
|
+
help="""\
|
|
55
|
+
Underscore separated list of comma separated Absolute Time Constraints \
|
|
56
|
+
e.g. yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm_yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm{_...}
|
|
57
|
+
[optional]\
|
|
58
|
+
""",
|
|
59
|
+
default=None
|
|
60
|
+
)
|
|
61
|
+
group.add_option("-f", "--file", dest="file", help="A file with one ATC per line [optional]", default=None)
|
|
62
|
+
parser.add_option_group(group)
|
|
63
|
+
|
|
64
|
+
group = OptionGroup(parser, "Specify the Absolute Time Intervals using an orbital ephemeris. This functionality is EXPERIMENTAL, please check carefully!!!")
|
|
65
|
+
group.add_option("-E", "--ephem", dest="ephem", metavar="T0,PERIOD", help="Comma separated list of orbital T0[JD] and period[days] [optional]", default=None)
|
|
66
|
+
group.add_option("--phase_intervals", dest="phase_intervals", help="Comma separated list of phase intervals e.g. 0.1-0.2,0.305-0.375 [optional]", default=None)
|
|
67
|
+
group.add_option("--phase_target", dest="phase_target", help="Comma separated list of target phase, start_before [mins], min_start_before [mins] e.g. 0.01,120,30 [optional]", default=None)
|
|
68
|
+
group.add_option("--periods", dest="periods", help=f"Comma separated list of periods, default={default_eso_period} [optional]", default=str(default_eso_period))
|
|
69
|
+
parser.add_option_group(group)
|
|
70
|
+
|
|
71
|
+
group = OptionGroup(parser, "p2 server selection, options and password management")
|
|
72
|
+
group.add_option("--env", dest="env", help="Use the %s environment [optional], default = production" %("|".join(p2api.API_URL.keys())), default='production')
|
|
73
|
+
group.add_option("-u", "--user", dest="user", metavar="USER", help="the User Portal account of the user to use, e.g. ASMITHSONIAN [required for production (not required for demo)]", default=None)
|
|
74
|
+
group.add_option("-S", "--PWstore", dest="pwstore", metavar="PWSTORE", help="Store the password in the keyring, default=False", action="store_true", default=False)
|
|
75
|
+
group.add_option("-R", "--PWreenter", dest="pwreenter", metavar="PWREENTER", help="Reenter the password, thus overriding any PW in the keyring, default=False", action="store_true", default=False)
|
|
76
|
+
group.add_option("-Z", "--PWremove", dest="pwremove", metavar="PWREMOVE", help="Remove any password from the keyring, default=False", action="store_true", default=False)
|
|
77
|
+
parser.add_option_group(group)
|
|
78
|
+
|
|
79
|
+
group = OptionGroup(parser, "Verbosity...",
|
|
80
|
+
"All optional")
|
|
81
|
+
group.add_option("-n", "--dryRun", dest="dryrun", help="Do everything but make any changes to tickets [optional]", action="store_true", default=False)
|
|
82
|
+
group.add_option("-D", "--debug", dest="debug", help="Write out debugging info [optional]", action="store_true", default=False)
|
|
83
|
+
#group.add_option("-v", "--verbose", dest="vbose", help="Write out verbose info [optional]", action="store_true", default=False)
|
|
84
|
+
group.add_option("-q", "--quiet", dest="quiet", help="Write out minimal info [optional]", action="store_true", default=False)
|
|
85
|
+
parser.add_option_group(group)
|
|
86
|
+
|
|
87
|
+
# parse arguments
|
|
88
|
+
(options, args) = parser.parse_args()
|
|
89
|
+
|
|
90
|
+
if options.ids is None or (
|
|
91
|
+
(
|
|
92
|
+
options.ATCs is None
|
|
93
|
+
and
|
|
94
|
+
options.file is None
|
|
95
|
+
and
|
|
96
|
+
(
|
|
97
|
+
options.ephem is None
|
|
98
|
+
or
|
|
99
|
+
options.periods is None
|
|
100
|
+
or
|
|
101
|
+
options.phase_intervals is None
|
|
102
|
+
)
|
|
103
|
+
and
|
|
104
|
+
(
|
|
105
|
+
options.ephem is None
|
|
106
|
+
or
|
|
107
|
+
options.periods is None
|
|
108
|
+
or
|
|
109
|
+
options.phase_target is None
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
) :
|
|
113
|
+
parser.print_help()
|
|
114
|
+
sys.exit(2)
|
|
115
|
+
|
|
116
|
+
self.ids = options.ids
|
|
117
|
+
self.periods = options.periods
|
|
118
|
+
self.ATCs = options.ATCs
|
|
119
|
+
self.file = options.file
|
|
120
|
+
self.ephem = options.ephem
|
|
121
|
+
self.phase_intervals = options.phase_intervals
|
|
122
|
+
self.phase_target = options.phase_target
|
|
123
|
+
|
|
124
|
+
self.user = options.user
|
|
125
|
+
self.env = options.env
|
|
126
|
+
self.pwstore = options.pwstore
|
|
127
|
+
self.pwreenter = options.pwreenter
|
|
128
|
+
self.pwremove = options.pwremove
|
|
129
|
+
|
|
130
|
+
self.debug = options.debug
|
|
131
|
+
self.dryrun = options.dryrun
|
|
132
|
+
self.quiet = options.quiet
|
|
133
|
+
|
|
134
|
+
logFMT = "%(asctime)s %(module)15s[%(process)5d] [%(levelname)s] %(message)s"
|
|
135
|
+
logLVL=logging.INFO
|
|
136
|
+
if options.debug:
|
|
137
|
+
logLVL=logging.DEBUG
|
|
138
|
+
if options.quiet:
|
|
139
|
+
logLVL=logging.WARN
|
|
140
|
+
logging.basicConfig(level=logLVL, format=logFMT)
|
|
141
|
+
|
|
142
|
+
options = get_options(_VERSION_)
|
|
143
|
+
|
|
144
|
+
# ------------------------------------------------------------------------------
|
|
145
|
+
def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
146
|
+
ob_ATCs=[]
|
|
147
|
+
ATCs=None
|
|
148
|
+
check_ATCs=False
|
|
149
|
+
if options.ATCs is not None :
|
|
150
|
+
ATCs=[
|
|
151
|
+
[p2api_utils.decode_datetime(x.split(',')[0]),p2api_utils.decode_datetime(x.split(',')[1])]
|
|
152
|
+
for x in options.ATCs.splt('_')
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
elif options.file is not None :
|
|
156
|
+
with open(options.file) as file:
|
|
157
|
+
lines = file.readlines()
|
|
158
|
+
lines = [line.rstrip().lstrip().split(',') for line in lines]
|
|
159
|
+
ATCs=[
|
|
160
|
+
[
|
|
161
|
+
p2api_utils.decode_datetime(x[0])+datetime.timedelta(seconds=30), # rounding to 1min
|
|
162
|
+
p2api_utils.decode_datetime(x[1])+datetime.timedelta(seconds=30), # rounding to 1min
|
|
163
|
+
] for x in lines
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
elif options.ephem is not None :
|
|
167
|
+
ob_exec_time=ob_info['executionTime']
|
|
168
|
+
T0,P=(float(x) for x in options.ephem.split(','))
|
|
169
|
+
periods=[
|
|
170
|
+
item for sublist in
|
|
171
|
+
[[y for y in range(int(x.split('-')[0]),int(x.split('-')[-1])+1)] for x in options.periods.split(',')]
|
|
172
|
+
for item in sublist
|
|
173
|
+
]
|
|
174
|
+
periods.sort()
|
|
175
|
+
period_range=[periods[0],]
|
|
176
|
+
period_ranges=[]
|
|
177
|
+
_pp=periods[0]
|
|
178
|
+
sf_jds=[]
|
|
179
|
+
for _p in periods[1:] :
|
|
180
|
+
if _p > _pp+1 :
|
|
181
|
+
period_range+=[_pp,]
|
|
182
|
+
sf_jd=Time([p2api_utils.ESO_period_start_end_datetimes(ESO_P) for ESO_P in period_range]).jd
|
|
183
|
+
sf_jds+=[[sf_jd[0][0],sf_jd[1][1]],]
|
|
184
|
+
period_ranges+=[period_range,]
|
|
185
|
+
period_range=[_p,]
|
|
186
|
+
_pp=_p
|
|
187
|
+
period_range+=[_pp,]
|
|
188
|
+
sf_jd=Time([p2api_utils.ESO_period_start_end_datetimes(ESO_P) for ESO_P in period_range]).jd
|
|
189
|
+
sf_jds+=[[sf_jd[0][0],sf_jd[1][1]],]
|
|
190
|
+
period_ranges+=[period_range,]
|
|
191
|
+
|
|
192
|
+
post_ob_exec_time=0.
|
|
193
|
+
if options.phase_intervals is not None :
|
|
194
|
+
phase_intervals=[[float(y) for y in x.split('-')] for x in options.phase_intervals.split(',')]
|
|
195
|
+
min_start_before=0.
|
|
196
|
+
elif options.phase_target is not None :
|
|
197
|
+
phase_target,start_before,min_start_before=(float(x) for x in options.phase_target.split(','))
|
|
198
|
+
phase_intervals=[[phase_target-start_before/P/24./60.,phase_target],]
|
|
199
|
+
post_ob_exec_time=ob_exec_time
|
|
200
|
+
ob_exec_time=0.
|
|
201
|
+
else :
|
|
202
|
+
logging.error('No means to calculate phase intervals specified.')
|
|
203
|
+
|
|
204
|
+
checked_phase_intervals=[]
|
|
205
|
+
for p_int in phase_intervals :
|
|
206
|
+
if p_int[1] < p_int[0] :
|
|
207
|
+
p_int[0]=p_int[0]-1.
|
|
208
|
+
p_int_in_sec=(p_int[1]-p_int[0])*P*24.*60.*60.
|
|
209
|
+
if (
|
|
210
|
+
ob_exec_time < p_int_in_sec
|
|
211
|
+
and
|
|
212
|
+
p_int_in_sec > min_ATI_length.to_value(u.second)
|
|
213
|
+
) :
|
|
214
|
+
checked_phase_intervals+=[p_int,]
|
|
215
|
+
else :
|
|
216
|
+
if ob_exec_time < p_int_in_sec :
|
|
217
|
+
logging.warning(f'Phase interval {p_int[0]}--{p_int[1]} == {p_int_in_sec:3.1f}sec is too short to start and finish this OB with execution time of {ob_exec_time}secs.')
|
|
218
|
+
if p_int_in_sec > min_ATI_length.to_value(u.second) :
|
|
219
|
+
logging.warning(f'Phase interval {p_int[0]}--{p_int[1]} == {p_int_in_sec:3.1f}sec is shorter than the minimum ATI length time of {min_ATI_length.to_value(u.second)}secs.')
|
|
220
|
+
|
|
221
|
+
sf_ints=[]
|
|
222
|
+
for sf_jd in sf_jds :
|
|
223
|
+
orbits=(np.array(sf_jd)-T0)//P
|
|
224
|
+
for o in range(int(orbits[0])-1,int(orbits[1])+1) :
|
|
225
|
+
for p_int in checked_phase_intervals :
|
|
226
|
+
sf_int=[
|
|
227
|
+
T0+(o+p_int[0])*P,
|
|
228
|
+
T0+(o+p_int[1])*P-ob_exec_time/24./60./60.,
|
|
229
|
+
]
|
|
230
|
+
if (
|
|
231
|
+
( sf_int[0] > sf_jd[0] and sf_int[0] < sf_jd[1] )
|
|
232
|
+
or
|
|
233
|
+
( sf_int[1] > sf_jd[0] and sf_int[1] < sf_jd[1] )
|
|
234
|
+
) :
|
|
235
|
+
# Interval is within the time range of the specified period(s)...
|
|
236
|
+
original_sf_int=sf_int
|
|
237
|
+
int_spans_nighttime=True
|
|
238
|
+
if sf_int[1] - sf_int[0] < 1. :
|
|
239
|
+
sssr=[]
|
|
240
|
+
# Check that some part of the interval occurs during nighttime...
|
|
241
|
+
int_spans_nighttime=False
|
|
242
|
+
for which in ['previous','next',] :
|
|
243
|
+
sun_set_time=telescope.sun_set_time(Time(sf_int[0], format='jd'), which=which)
|
|
244
|
+
sun_rise_time=telescope.sun_rise_time(sun_set_time, which='next')
|
|
245
|
+
sssr+=[[sun_set_time,sun_rise_time],]
|
|
246
|
+
if (
|
|
247
|
+
(sf_int[0] > sun_set_time.jd and sf_int[0] < sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
248
|
+
or
|
|
249
|
+
(sf_int[1] > sun_set_time.jd and sf_int[1] < sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
250
|
+
or
|
|
251
|
+
(sf_int[0] < sun_set_time.jd and sf_int[1] > sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
252
|
+
) :
|
|
253
|
+
sf_int=[
|
|
254
|
+
np.max([sf_int[0],sun_set_time.jd]),
|
|
255
|
+
np.min([sf_int[1],sun_rise_time.jd-ob_exec_time/24./60./60.,sun_rise_time.jd-post_ob_exec_time/24./60./60.]),
|
|
256
|
+
]
|
|
257
|
+
if sf_int[1] > sf_int[0]+min_start_before/24./60. :
|
|
258
|
+
int_spans_nighttime=True
|
|
259
|
+
break
|
|
260
|
+
if (
|
|
261
|
+
int_spans_nighttime
|
|
262
|
+
and
|
|
263
|
+
((sf_int[1]-sf_int[0])*24*60.*60. > ob_exec_time)
|
|
264
|
+
and
|
|
265
|
+
(sf_int[1]-sf_int[0])*24*60.*60. > min_ATI_length.to_value(u.second)
|
|
266
|
+
) :
|
|
267
|
+
sf_ints+=[sf_int,]
|
|
268
|
+
else :
|
|
269
|
+
if not int_spans_nighttime :
|
|
270
|
+
logging.debug(f'Interval does not span any part of the night, original interval = {original_sf_int}, SSSR of previous and next nights {sssr[0][0].jd}--{sssr[0][1].jd} and {sssr[1][0].jd}--{sssr[1][1].jd}')
|
|
271
|
+
if ((sf_int[1]-sf_int[0])*24*60.*60. < ob_exec_time) :
|
|
272
|
+
logging.debug(f'Checked Interval shorter [{(sf_int[1]-sf_int[0])*24*60.*60.:3.1f}sec] than OB execution time [{ob_exec_time:3.1f}sec], original interval = {original_sf_int}, checked interval = {sf_int}')
|
|
273
|
+
if ((sf_int[1]-sf_int[0])*24*60.*60. < min_ATI_length.to_value(u.second)) :
|
|
274
|
+
logging.debug(f'Checked Interval shorter [{(sf_int[1]-sf_int[0])*24*60.*60.:3.1f}sec] than minimum ATI length time [{min_ATI_length.to_value(u.second):3.1f}sec], original interval = {original_sf_int}, checked interval = {sf_int}')
|
|
275
|
+
pass
|
|
276
|
+
ATCs=[Time(sf_int, format='jd') for sf_int in sf_ints]
|
|
277
|
+
check_ATCs=True
|
|
278
|
+
else :
|
|
279
|
+
raise "Don't know how to compute Absolute Time Constraints."
|
|
280
|
+
|
|
281
|
+
ob_ATCs=[]
|
|
282
|
+
for i,ATC in enumerate(ATCs) :
|
|
283
|
+
t=Time(ATC)
|
|
284
|
+
t.format = 'isot'
|
|
285
|
+
t.out_subfmt = 'date_hm'
|
|
286
|
+
ob_ATCs+=[{
|
|
287
|
+
'from': t[0].isot,
|
|
288
|
+
'to': t[1].isot,
|
|
289
|
+
},]
|
|
290
|
+
if check_ATCs :
|
|
291
|
+
phase_range=''
|
|
292
|
+
if options.ephem is not None :
|
|
293
|
+
phase_range=f" [Phases: {(((t[0]-Time(T0,format='jd'))/P).to_value(u.day)%1):5.3f} -- {(((t[1]-Time(T0,format='jd'))/P).to_value(u.day)%1):5.3f}]"
|
|
294
|
+
print(f"{i+1:3d} {ob_ATCs[-1]['from']} -- {ob_ATCs[-1]['to']} [duration={((t[1]-t[0]).to_datetime())}]{phase_range}")
|
|
295
|
+
if check_ATCs :
|
|
296
|
+
'''
|
|
297
|
+
logging.warning("****************************************************************************************")
|
|
298
|
+
logging.warning("****************************************************************************************")
|
|
299
|
+
logging.warning("****************************************************************************************")
|
|
300
|
+
logging.warning("Intervals via Orbital Ephemeris functionality is EXPERIMENTAL")
|
|
301
|
+
logging.warning("Please check the above intervals carefully and only continue if you are sure they are what YOU require.")
|
|
302
|
+
logging.warning("YOU, and YOU ALONE are responsible for the accuracy of these inetervals.")
|
|
303
|
+
'''
|
|
304
|
+
print("****************************************************************************************")
|
|
305
|
+
print("****************************************************************************************")
|
|
306
|
+
print("****************************************************************************************")
|
|
307
|
+
print("Intervals via Orbital Ephemeris functionality is EXPERIMENTAL")
|
|
308
|
+
print("Please check the above intervals carefully and only continue if you are sure they are what YOU require.")
|
|
309
|
+
print("YOU, and YOU ALONE are responsible for the accuracy of these intervals.")
|
|
310
|
+
yorn = input("Continue [y/N] ")
|
|
311
|
+
if yorn.lower() not in ['y',] :
|
|
312
|
+
print("Please contact ESO User Support via a ticket at https://support.eso.org/tickets")
|
|
313
|
+
print("to report/discuss the errors/problems in the above calculations.")
|
|
314
|
+
print("Please include in the description the EXACT command line used to run the script.")
|
|
315
|
+
sys.exit(0)
|
|
316
|
+
#raise Exception(f"Aborted.")
|
|
317
|
+
return ob_ATCs
|
|
318
|
+
# ------------------------------------------------------------------------------
|
|
319
|
+
def oneOB( api, obId ) :
|
|
320
|
+
try :
|
|
321
|
+
OB, _ = api.getOB(obId)
|
|
322
|
+
except p2api.P2Error as e :
|
|
323
|
+
## Looks like this ID is not an OB...
|
|
324
|
+
logging.error('OB %d could not be found...' %(obId))
|
|
325
|
+
return
|
|
326
|
+
except:
|
|
327
|
+
raise
|
|
328
|
+
ob_info = api.executionTime(obId)
|
|
329
|
+
run_info,_=api.getRun(OB['runId'])
|
|
330
|
+
|
|
331
|
+
telescope = Observer(location=p2api_utils.telescope_locations[run_info['telescope']])
|
|
332
|
+
|
|
333
|
+
if OB['itemType'] not in ['OB',] :
|
|
334
|
+
logging.warning('OB %d is not a science OB' %(obId))
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
if OB['obStatus'] not in ['P','-'] :
|
|
338
|
+
logging.warning('OB status is %s, OB not modifiable' %(OB['obstatus']))
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
runId, _ = api.getRun(OB['runId'])
|
|
342
|
+
ob_url=api.apiUrl+'/obsBlocks/'+str(obId)
|
|
343
|
+
oneOB_sdt=datetime.datetime.now()
|
|
344
|
+
## For the moment only setting is supported,
|
|
345
|
+
## ToDo: implement support for adding to...
|
|
346
|
+
logging.info("Setting Absolute Time Intervals for OBid = %d, OBname = '%s' @ %s..." % (OB['obId'],OB['name'],OB['instrument']))
|
|
347
|
+
absTCs, atcVersion = api.getAbsoluteTimeConstraints(obId)
|
|
348
|
+
|
|
349
|
+
ob_ATCs=get_ob_ATCs(
|
|
350
|
+
telescope=telescope,
|
|
351
|
+
ob_info=ob_info,
|
|
352
|
+
run_info=run_info,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if not options.dryrun :
|
|
356
|
+
api.saveAbsoluteTimeConstraints(
|
|
357
|
+
obId,
|
|
358
|
+
ob_ATCs,
|
|
359
|
+
atcVersion,
|
|
360
|
+
)
|
|
361
|
+
oneOB_edt=datetime.datetime.now()
|
|
362
|
+
logging.info(
|
|
363
|
+
"Added %d Absolute Time Intervals for OBid = %d, OBname = '%s' @ %s done in %s."
|
|
364
|
+
%(
|
|
365
|
+
len(ob_ATCs), obId, OB['name'], OB['instrument'], str(oneOB_edt-oneOB_sdt)
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
# ------------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
# ------------------------------------------------------------------------------
|
|
371
|
+
# ------------------------------------------------------------------------------
|
|
372
|
+
# ------------------------------------------------------------------------------
|
|
373
|
+
|
|
374
|
+
def main():
|
|
375
|
+
|
|
376
|
+
################################################################################
|
|
377
|
+
# remove password from keyring...
|
|
378
|
+
if options.pwremove and options.user is not None :
|
|
379
|
+
keyring.delete_password('usd_p2api_interactive:www.eso.org', options.user)
|
|
380
|
+
sys.exit(0)
|
|
381
|
+
|
|
382
|
+
api=p2api_utils.get_api(options)
|
|
383
|
+
obIds=p2api_utils.r_get_all_OBIds( api, options.ids.split(',') )
|
|
384
|
+
|
|
385
|
+
if len(obIds) > 0 :
|
|
386
|
+
if len(obIds) > 1 :
|
|
387
|
+
sdt=datetime.datetime.now()
|
|
388
|
+
logging.warning('Adding Absolute Time Constraints to %d OBs...' %( len(obIds) ))
|
|
389
|
+
for obId in obIds :
|
|
390
|
+
oneOB(api, obId, )
|
|
391
|
+
if len(obIds) > 1 :
|
|
392
|
+
edt=datetime.datetime.now()
|
|
393
|
+
logging.info('Total elapsed time to process %d finding charts %s...' %(len(obIds),str(edt-sdt)))
|
|
394
|
+
else :
|
|
395
|
+
logging.error('No OBs found.')
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
if __name__ == '__main__' :
|
|
399
|
+
main()
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
|
|
3
|
+
# $Id: generate_finding_charts.py 267033 2021-09-16 11:08:57Z jpritcha $
|
|
4
|
+
from __future__ import print_function
|
|
5
|
+
|
|
6
|
+
_VERSION_ = "$Revision: 267033 $"
|
|
7
|
+
|
|
8
|
+
import sys # interaction with Python interpreter
|
|
9
|
+
from optparse import OptionParser # for parsing command line arguments
|
|
10
|
+
from optparse import OptionGroup
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
import keyring
|
|
15
|
+
import datetime
|
|
16
|
+
import json
|
|
17
|
+
import requests
|
|
18
|
+
|
|
19
|
+
import p2api
|
|
20
|
+
import p2api.utils.p2api_utils as p2api_utils
|
|
21
|
+
################################################################################
|
|
22
|
+
|
|
23
|
+
################################################################################
|
|
24
|
+
class get_options:
|
|
25
|
+
"get command line options"
|
|
26
|
+
|
|
27
|
+
def __init__(self, vers="0.0"):
|
|
28
|
+
# define options and arguments
|
|
29
|
+
parser = OptionParser(version="%prog "+vers, formatter=p2api_utils.IndentedHelpFormatterWithNL())
|
|
30
|
+
|
|
31
|
+
group = OptionGroup(parser, "Input OB(s)")
|
|
32
|
+
group.add_option("-i", "--ids", dest="ids", metavar="Ids", help="List of OB IDs [required]", default=None)
|
|
33
|
+
group.add_option("--obsdate", dest="obsdate", metavar="OBS_DATE", help="Set the obsdate [optional]", default=None)
|
|
34
|
+
parser.add_option_group(group)
|
|
35
|
+
|
|
36
|
+
group = OptionGroup(parser, "Image display parameters",
|
|
37
|
+
"""\
|
|
38
|
+
The following parameters affect the way the 'default' images are displayed in the FCs.
|
|
39
|
+
They correspond directly to the corresponding parameters of the APLPY FITSFigure.show_grayscale method, see:
|
|
40
|
+
https://aplpy.readthedocs.io/en/stable/api/aplpy.FITSFigure.html#aplpy.FITSFigure.show_grayscale
|
|
41
|
+
for details.
|
|
42
|
+
"""
|
|
43
|
+
)
|
|
44
|
+
group.add_option("--pmax", dest="pmax", metavar="PMAX", help="pmax to apply to the display of first FC [optional]", type='float', default=None)
|
|
45
|
+
group.add_option("--pmin", dest="pmin", metavar="PMIN", help="pmin to apply to the display of first FC [optional]", type='float', default=None)
|
|
46
|
+
group.add_option("--stretch", dest="stretch", metavar="STRETCH", help="Stretch to apply to the display of first FC [optional]\n", default=None)
|
|
47
|
+
group.add_option("--exponent", dest="exponent", metavar="EXPONENT", help="Exponent if stretch='power' [optional]\n", default=None)
|
|
48
|
+
parser.add_option_group(group)
|
|
49
|
+
|
|
50
|
+
group = OptionGroup(parser, "Custom Image/Survey",
|
|
51
|
+
"""\
|
|
52
|
+
The following parameters affect the way the 'default' images are displayed in the FCs.
|
|
53
|
+
They correspond directly to the corresponding parameters without 'c_' prefixes of the APLPY FITSFigure.show_grayscale method, see:
|
|
54
|
+
https://aplpy.readthedocs.io/en/stable/api/aplpy.FITSFigure.html#aplpy.FITSFigure.show_grayscale
|
|
55
|
+
for details.
|
|
56
|
+
"""
|
|
57
|
+
)
|
|
58
|
+
group.add_option("--survey", dest="survey", metavar="SURVEY", help="An alternative SkyView survey to use. Use --supported_surveys to see which surveys are supported. [optional]", default=None)
|
|
59
|
+
group.add_option("--bkg_image", dest="bkg_image", metavar="BK_IMAGE", help="A custom background image to use [optional]", default=None)
|
|
60
|
+
group.add_option("--bkg_lam", dest="bkg_lam", metavar="BK_LAM", help="Description of the WL coverage of the custom background image/survey [optional]", default=None)
|
|
61
|
+
group.add_option("--c_pmax", dest="c_pmax", metavar="PMAX", help="pmax to apply to the display of first FC [optional]", type='float', default=None)
|
|
62
|
+
group.add_option("--c_pmin", dest="c_pmin", metavar="PMIN", help="pmin to apply to the display of first FC [optional]", type='float', default=None)
|
|
63
|
+
group.add_option("--c_stretch", dest="c_stretch", metavar="STRETCH", help="Stretch to apply to the display of first FC [optional]\n", default=None)
|
|
64
|
+
group.add_option("--c_exponent", dest="c_exponent", metavar="EXPONENT", help="Exponent if stretch='power' [optional]\n", default=None)
|
|
65
|
+
parser.add_option_group(group)
|
|
66
|
+
|
|
67
|
+
group = OptionGroup(parser, "Gaia pseudo images parameters",
|
|
68
|
+
"The following parameters affect the way the Gaia pseudo images (if any) are constructed."
|
|
69
|
+
)
|
|
70
|
+
group.add_option("--GAIA_im_IQ", dest="GAIA_im_IQ", metavar="FWHM",
|
|
71
|
+
help="FWHM to use for any Gaia images that will be generated [optional]",
|
|
72
|
+
type='float',
|
|
73
|
+
default=None
|
|
74
|
+
)
|
|
75
|
+
group.add_option("--GAIA_im_noise", dest="GAIA_im_noise", metavar="NOISE",
|
|
76
|
+
help=
|
|
77
|
+
"""\
|
|
78
|
+
GAIA_im_noise is a dimensionless factor, with the noise computed via the numpy method random.normal(loc,scale) with loc=0.0 and:
|
|
79
|
+
scale=GAIA_im_noise*<brightest_flux_value>
|
|
80
|
+
with <brightest_flux_value> being the maximum pixel value in the noiseless pseudo image.
|
|
81
|
+
The default value is (as at 2020-01): 1e-6
|
|
82
|
+
Together with pmin and pmax this parameter gives (some) control over the relative appearance of stars of different brightness, and can thus be helpful to (for example) highlight faint, but not insignificant, field star(s).
|
|
83
|
+
[optional] default=1e-6
|
|
84
|
+
""",
|
|
85
|
+
type='float', default=None
|
|
86
|
+
)
|
|
87
|
+
group.add_option("--c_GAIA_im_IQ", dest="c_GAIA_im_IQ", metavar="FWHM",
|
|
88
|
+
help="Same as --GAIA_im_IQ but for any Gaia pseudo images associated with the custom FC.",
|
|
89
|
+
type='float',
|
|
90
|
+
default=None
|
|
91
|
+
)
|
|
92
|
+
group.add_option("--c_GAIA_im_noise", dest="c_GAIA_im_noise", metavar="NOISE",
|
|
93
|
+
help="Same as --GAIA_im_noise but for any Gaia pseudo images associated with the custom FC.",
|
|
94
|
+
type='float',
|
|
95
|
+
default=None
|
|
96
|
+
)
|
|
97
|
+
parser.add_option_group(group)
|
|
98
|
+
|
|
99
|
+
group = OptionGroup(parser, "p2 server selection, options and password management")
|
|
100
|
+
group.add_option("--env", dest="env", help="Use the %s environment [optional], default = production" %("|".join(p2api.API_URL.keys())), default='production')
|
|
101
|
+
group.add_option("-u", "--user", dest="user", metavar="USER", help="the User Portal account of the user to use, e.g. ASMITHSONIAN [required for production (not required for demo)]", default=None)
|
|
102
|
+
group.add_option("-S", "--PWstore", dest="pwstore", metavar="PWSTORE", help="Store the password in the keyring, default=False", action="store_true", default=False)
|
|
103
|
+
group.add_option("-R", "--PWreenter", dest="pwreenter", metavar="PWREENTER", help="Reenter the password, thus overriding any PW in the keyring, default=False", action="store_true", default=False)
|
|
104
|
+
group.add_option("-Z", "--PWremove", dest="pwremove", metavar="PWREMOVE", help="Remove any password from the keyring, default=False", action="store_true", default=False)
|
|
105
|
+
parser.add_option_group(group)
|
|
106
|
+
|
|
107
|
+
group = OptionGroup(parser, "help...")
|
|
108
|
+
group.add_option("--supported_surveys", dest="supSurs", metavar="Ids", help="Report the list of supported surveys", action="store_true", default=False)
|
|
109
|
+
parser.add_option_group(group)
|
|
110
|
+
|
|
111
|
+
group = OptionGroup(parser, "Verbosity...",
|
|
112
|
+
"All optional")
|
|
113
|
+
group.add_option("-D", "--debug", dest="debug", help="Write out debugging info [optional]", action="store_true", default=False)
|
|
114
|
+
#group.add_option("-v", "--verbose", dest="vbose", help="Write out verbose info [optional]", action="store_true", default=False)
|
|
115
|
+
group.add_option("-q", "--quiet", dest="quiet", help="Write out minimal info [optional]", action="store_true", default=False)
|
|
116
|
+
parser.add_option_group(group)
|
|
117
|
+
|
|
118
|
+
# parse arguments
|
|
119
|
+
(options, args) = parser.parse_args()
|
|
120
|
+
|
|
121
|
+
if not options.ids and not options.supSurs :
|
|
122
|
+
parser.print_help()
|
|
123
|
+
sys.exit(2)
|
|
124
|
+
|
|
125
|
+
self.ids = options.ids
|
|
126
|
+
self.obsdate = options.obsdate
|
|
127
|
+
|
|
128
|
+
self.pmin = options.pmin
|
|
129
|
+
self.pmax = options.pmax
|
|
130
|
+
self.stretch = options.stretch
|
|
131
|
+
self.exponent = options.exponent
|
|
132
|
+
self.GAIA_im_IQ = options.GAIA_im_IQ
|
|
133
|
+
self.GAIA_im_noise = options.GAIA_im_noise
|
|
134
|
+
|
|
135
|
+
self.survey = options.survey
|
|
136
|
+
self.bkg_image = options.bkg_image
|
|
137
|
+
self.bkg_lam = options.bkg_lam
|
|
138
|
+
self.c_pmin = options.c_pmin
|
|
139
|
+
self.c_pmax = options.c_pmax
|
|
140
|
+
self.c_stretch = options.c_stretch
|
|
141
|
+
self.c_exponent = options.c_exponent
|
|
142
|
+
self.c_GAIA_im_IQ = options.c_GAIA_im_IQ
|
|
143
|
+
self.c_GAIA_im_noise = options.c_GAIA_im_noise
|
|
144
|
+
|
|
145
|
+
self.user = options.user
|
|
146
|
+
self.env = options.env
|
|
147
|
+
self.pwstore = options.pwstore
|
|
148
|
+
self.pwreenter = options.pwreenter
|
|
149
|
+
self.pwremove = options.pwremove
|
|
150
|
+
|
|
151
|
+
self.supSurs = options.supSurs
|
|
152
|
+
|
|
153
|
+
self.debug = options.debug
|
|
154
|
+
#self.vbose = options.vbose
|
|
155
|
+
self.quiet = options.quiet
|
|
156
|
+
|
|
157
|
+
logFMT = "%(asctime)s %(module)15s[%(process)5d] [%(levelname)s] %(message)s"
|
|
158
|
+
logLVL=logging.INFO
|
|
159
|
+
#if options.vbose:
|
|
160
|
+
# logLVL=logging.INFO
|
|
161
|
+
if options.debug:
|
|
162
|
+
logLVL=logging.DEBUG
|
|
163
|
+
if options.quiet:
|
|
164
|
+
logLVL=logging.WARN
|
|
165
|
+
logging.basicConfig(level=logLVL, format=logFMT)
|
|
166
|
+
|
|
167
|
+
options = get_options(_VERSION_)
|
|
168
|
+
# ------------------------------------------------------------------------------
|
|
169
|
+
def oneOB( api, obId ) :
|
|
170
|
+
try :
|
|
171
|
+
OB, _ = api.getOB(obId)
|
|
172
|
+
except p2api.P2Error as e :
|
|
173
|
+
## Looks like this ID is not an OB...
|
|
174
|
+
logging.error('OB %d could not be found...' %(obId))
|
|
175
|
+
return
|
|
176
|
+
except:
|
|
177
|
+
raise
|
|
178
|
+
|
|
179
|
+
if OB['itemType'] not in ['OB',] :
|
|
180
|
+
logging.warning('OB %d is not a science OB' %(obId))
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
if OB['obStatus'] not in ['P','-'] :
|
|
184
|
+
logging.warning('OB status is %s, OB not modifiable' %(OB['obstatus']))
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
runId, _ = api.getRun(OB['runId'])
|
|
188
|
+
ob_url=api.apiUrl+'/obsBlocks/'+str(obId)
|
|
189
|
+
oneOB_sdt=datetime.datetime.now()
|
|
190
|
+
logging.info("Creating finding charts for OBid = %d, OBname = '%s' @ %s..." % (OB['obId'],OB['name'],OB['instrument']))
|
|
191
|
+
data = api.generateFindingChart(
|
|
192
|
+
obId,
|
|
193
|
+
obs_date=options.obsdate,
|
|
194
|
+
stretch=options.stretch,
|
|
195
|
+
exponent=options.exponent,
|
|
196
|
+
pmin=options.pmin,
|
|
197
|
+
pmax=options.pmax,
|
|
198
|
+
GAIA_im_IQ=options.GAIA_im_IQ,
|
|
199
|
+
GAIA_im_noise=options.GAIA_im_noise,
|
|
200
|
+
survey=options.survey,
|
|
201
|
+
bkg_image=options.bkg_image,
|
|
202
|
+
bkg_lam=options.bkg_lam,
|
|
203
|
+
c_stretch=options.c_stretch,
|
|
204
|
+
c_exponent=options.c_exponent,
|
|
205
|
+
c_pmin=options.c_pmin,
|
|
206
|
+
c_pmax=options.c_pmax,
|
|
207
|
+
c_GAIA_im_IQ=options.c_GAIA_im_IQ,
|
|
208
|
+
c_GAIA_im_noise=options.c_GAIA_im_noise,
|
|
209
|
+
)
|
|
210
|
+
oneOB_edt=datetime.datetime.now()
|
|
211
|
+
logging.info("Finding chart for OBid = %d, OBname = '%s' @ %s done in %s." % (obId, OB['name'], OB['instrument'], str(oneOB_edt-oneOB_sdt)))
|
|
212
|
+
if data is not None :
|
|
213
|
+
try :
|
|
214
|
+
jwarn=json.loads(r.content.decode('utf-8'))
|
|
215
|
+
if 'warnings' in jwarn.keys() :
|
|
216
|
+
logging.warning(jwarn['warnings'])
|
|
217
|
+
except :
|
|
218
|
+
pass
|
|
219
|
+
# ------------------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# ------------------------------------------------------------------------------
|
|
223
|
+
# ------------------------------------------------------------------------------
|
|
224
|
+
# ------------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
def main():
|
|
227
|
+
|
|
228
|
+
################################################################################
|
|
229
|
+
# remove passowrd from keyring...
|
|
230
|
+
if options.pwremove and options.user is not None :
|
|
231
|
+
keyring.delete_password('usd_p2api_interactive:www.eso.org', options.user)
|
|
232
|
+
sys.exit(0)
|
|
233
|
+
|
|
234
|
+
################################################################################
|
|
235
|
+
if options.supSurs :
|
|
236
|
+
r = requests.get('%s/supported_surveys' %(p2api.P2FC_URL[options.env]))
|
|
237
|
+
if r.status_code in [200,201,204] :
|
|
238
|
+
print(r.text)
|
|
239
|
+
else:
|
|
240
|
+
raise(r.text)
|
|
241
|
+
sys.exit(0)
|
|
242
|
+
|
|
243
|
+
#login to the API
|
|
244
|
+
api=p2api_utils.get_api(options)
|
|
245
|
+
obIds=p2api_utils.r_get_all_OBIds( api, options.ids.split(',') )
|
|
246
|
+
|
|
247
|
+
if len(obIds) > 0 :
|
|
248
|
+
if len(obIds) > 1 :
|
|
249
|
+
sdt=datetime.datetime.now()
|
|
250
|
+
logging.warning('Submitting %d OBs for FC generation...' %( len(obIds) ))
|
|
251
|
+
for obId in obIds :
|
|
252
|
+
oneOB(api, obId)
|
|
253
|
+
if len(obIds) > 1 :
|
|
254
|
+
edt=datetime.datetime.now()
|
|
255
|
+
logging.info('Total elapsed time to process %d finding charts %s...' %(len(obIds),str(edt-sdt)))
|
|
256
|
+
else :
|
|
257
|
+
logging.error('No OBs found.')
|
|
258
|
+
|
|
259
|
+
if __name__ == '__main__' :
|
|
260
|
+
main()
|