a2p2 0.2.14__py3-none-any.whl → 0.7.4__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.
- a2p2/__main__.py +40 -1
- a2p2/chara/facility.py +54 -4
- a2p2/chara/gui.py +31 -5
- a2p2/client.py +158 -31
- a2p2/facility.py +14 -1
- a2p2/gui.py +46 -12
- a2p2/instrument.py +3 -0
- a2p2/jmmc/__init__.py +7 -0
- a2p2/jmmc/catalogs.py +129 -0
- a2p2/jmmc/generated_models.py +191 -0
- a2p2/jmmc/models.py +104 -0
- a2p2/jmmc/services.py +16 -0
- a2p2/jmmc/utils.py +130 -0
- a2p2/jmmc/webservices.py +48 -0
- a2p2/ob.py +98 -9
- a2p2/samp.py +20 -0
- a2p2/version.py +210 -131
- a2p2/vlti/conf/GRAVITY_ditTable.json +21 -19
- a2p2/vlti/conf/GRAVITY_rangeTable.json +200 -28
- a2p2/vlti/conf/MATISSE_rangeTable.json +58 -22
- a2p2/vlti/conf/PIONIER_ditTable.json +1 -1
- a2p2/vlti/conf/PIONIER_rangeTable.json +16 -18
- a2p2/vlti/facility.py +160 -43
- a2p2/vlti/gravity.py +243 -311
- a2p2/vlti/gui.py +165 -39
- a2p2/vlti/instrument.py +266 -49
- a2p2/vlti/matisse.py +61 -147
- a2p2/vlti/pionier.py +34 -157
- {a2p2-0.2.14.dist-info → a2p2-0.7.4.dist-info}/METADATA +34 -20
- a2p2-0.7.4.dist-info/RECORD +39 -0
- {a2p2-0.2.14.dist-info → a2p2-0.7.4.dist-info}/WHEEL +1 -1
- {a2p2-0.2.14.dist-info → a2p2-0.7.4.dist-info}/entry_points.txt +0 -1
- a2p2/vlti/confP104/GRAVITY_ditTable.json +0 -122
- a2p2/vlti/confP104/GRAVITY_rangeTable.json +0 -202
- a2p2/vlti/confP104/MATISSE_ditTable.json +0 -2
- a2p2/vlti/confP104/MATISSE_rangeTable.json +0 -202
- a2p2/vlti/confP104/PIONIER_ditTable.json +0 -77
- a2p2/vlti/confP104/PIONIER_rangeTable.json +0 -118
- a2p2/vlti/confP105/GRAVITY_ditTable.json +0 -37
- a2p2/vlti/confP105/GRAVITY_rangeTable.json +0 -42
- a2p2/vlti/confP105/MATISSE_ditTable.json +0 -2
- a2p2/vlti/confP105/MATISSE_rangeTable.json +0 -44
- a2p2/vlti/confP105/PIONIER_ditTable.json +0 -25
- a2p2/vlti/confP105/PIONIER_rangeTable.json +0 -38
- a2p2-0.2.14.dist-info/RECORD +0 -44
- {a2p2-0.2.14.dist-info → a2p2-0.7.4.dist-info}/LICENSE +0 -0
- {a2p2-0.2.14.dist-info → a2p2-0.7.4.dist-info}/top_level.txt +0 -0
a2p2/vlti/instrument.py
CHANGED
@@ -8,12 +8,16 @@ import json
|
|
8
8
|
import os
|
9
9
|
# import ast
|
10
10
|
import re
|
11
|
+
import logging
|
11
12
|
|
12
13
|
import numpy as np
|
13
14
|
from astropy.coordinates import SkyCoord
|
15
|
+
import astropy.units as u
|
14
16
|
|
15
17
|
from a2p2.instrument import Instrument
|
16
18
|
|
19
|
+
logger = logging.getLogger(__name__)
|
20
|
+
|
17
21
|
|
18
22
|
class VltiInstrument(Instrument):
|
19
23
|
|
@@ -26,13 +30,41 @@ class VltiInstrument(Instrument):
|
|
26
30
|
self.rangeTable = None
|
27
31
|
self.ditTable = None
|
28
32
|
|
33
|
+
# warnings
|
34
|
+
self.warnings = []
|
35
|
+
self.errors = []
|
36
|
+
|
37
|
+
def isScience(self, objtype):
|
38
|
+
return "SCI" in objtype
|
39
|
+
|
40
|
+
def isCalibrator(self, objtype):
|
41
|
+
return "SCI" not in objtype
|
42
|
+
|
29
43
|
def get(self, obj, fieldname, defaultvalue):
|
30
44
|
if fieldname in obj._fields:
|
31
45
|
return getattr(obj, fieldname)
|
32
46
|
else:
|
33
47
|
return defaultvalue
|
34
48
|
|
35
|
-
|
49
|
+
def getSequence(self, ob):
|
50
|
+
# We may look at ob.observationSchedule but at present tuime schedule still is computed on a2p2 side
|
51
|
+
sci = []
|
52
|
+
cal = []
|
53
|
+
for observationConfiguration in ob.observationConfiguration:
|
54
|
+
if 'SCIENCE' in observationConfiguration.type:
|
55
|
+
sci.append(observationConfiguration)
|
56
|
+
else:
|
57
|
+
cal.append(observationConfiguration)
|
58
|
+
if len(sci)+len(cal) <= 2: # return [CAL] [SCI]
|
59
|
+
return cal+sci
|
60
|
+
# else return CAL1 SCI CAL2 [SCI CAL3] [SCI CAL4]
|
61
|
+
seq = []
|
62
|
+
for c in cal:
|
63
|
+
seq.append(c)
|
64
|
+
seq += sci
|
65
|
+
return seq[0:-1]
|
66
|
+
|
67
|
+
# checkOB() must be defined by each instruments
|
36
68
|
# def checkOB(self, ob, p2container=None):
|
37
69
|
# consider dryMode if p2container is None else check again and submit on p2 side
|
38
70
|
|
@@ -42,30 +74,49 @@ class VltiInstrument(Instrument):
|
|
42
74
|
|
43
75
|
# create new container
|
44
76
|
obsconflist = ob.observationConfiguration
|
77
|
+
|
78
|
+
# Aspro2 always send SCI at first position (or CAL if no SCI)
|
45
79
|
folderName = obsconflist[0].SCTarget.name
|
46
80
|
folderName = re.sub('[^A-Za-z0-9]+', '_', folderName.strip())
|
47
|
-
|
48
|
-
# force a top folder in demo.
|
81
|
+
# prefix with username to make test folder clearer
|
49
82
|
if p2container.isRoot() and self.facility.isTutorialAccount():
|
50
|
-
|
51
|
-
|
52
|
-
|
83
|
+
folderName += "_" + self.facility.a2p2client.preferences.getP2UserCommentName()
|
84
|
+
|
85
|
+
# do create a folder or concatenation only for SM or tutorial account
|
86
|
+
# should we create a concatenation only if we have multiple objects
|
87
|
+
if p2container.isRoot():
|
88
|
+
# create a concatenation if service mode (even if we do not have any cal at this stage)
|
89
|
+
if p2container.isServiceModeRun():
|
90
|
+
# TODO fix bug when we keep the last selection that is a Concatenation. Concatenation can't be nested.
|
91
|
+
# use parent container or ask user to choose another container location ?
|
92
|
+
folder, _ = api.createConcatenation(
|
93
|
+
p2container.containerId, folderName)
|
94
|
+
ui.addToLog(f"concatenation '{folderName}' created")
|
95
|
+
else:
|
96
|
+
folder, _ = api.createFolder(
|
97
|
+
p2container.containerId, folderName)
|
98
|
+
ui.addToLog(f"folder '{folderName}' created")
|
99
|
+
|
100
|
+
# update parent tree since we created a new subfolder
|
101
|
+
ui.updateTree(p2container.run, p2container.containerId)
|
102
|
+
|
53
103
|
p2container.containerId = folder['containerId']
|
54
104
|
|
55
|
-
# create a concatenation if service mode
|
56
|
-
if p2container.isServiceModeRun():
|
57
|
-
folder, _ = api.createConcatenation(
|
58
|
-
p2container.containerId, folderName)
|
59
105
|
else:
|
60
|
-
|
61
|
-
p2container.containerId = folder['containerId']
|
106
|
+
ui.addToLog("concatenation or folder not created")
|
62
107
|
|
63
108
|
ui.addToLog("OB checked / preparing submission...")
|
64
109
|
self.checkOB(ob, p2container)
|
65
110
|
|
111
|
+
# refresh and select last created element tree
|
112
|
+
ui.updateTree(p2container.run, p2container.containerId)
|
113
|
+
ui.selectTreeItem(p2container.containerId)
|
114
|
+
ui.addToLog(
|
115
|
+
"OB submitted! Please check logs and fix last details on P2 web.")
|
116
|
+
|
66
117
|
def getCoords(self, target, requirePrecision=True):
|
67
118
|
"""
|
68
|
-
Format coordinates from given target to be VLTI compliant.
|
119
|
+
Format HMS DMS coordinates from given target to be VLTI compliant.
|
69
120
|
Throws an exception if requirePrecision is true and given inputs have less than 3 (RA) or 2 (DEC) digits.
|
70
121
|
"""
|
71
122
|
|
@@ -93,36 +144,63 @@ class VltiInstrument(Instrument):
|
|
93
144
|
|
94
145
|
def getPMCoords(self, target, defaultPMRA=0.0, defaultPMDEC=0.0):
|
95
146
|
"""
|
96
|
-
Returns PMRA, PMDEC as float values rounded to 4 decimal digits. 0.0 is used as default if not present.
|
147
|
+
Returns PMRA, PMDEC in arcsec/year as float values rounded to 4 decimal digits. 0.0 is used as default if not present.
|
97
148
|
"""
|
98
149
|
PMRA = self.get(target, "PMRA", defaultPMRA)
|
99
150
|
PMDEC = self.get(target, "PMDEC", defaultPMDEC)
|
100
151
|
return round(float(PMRA) / 1000.0, 4), round(float(PMDEC) / 1000.0, 4)
|
101
152
|
|
153
|
+
def getPARALLAX(self, target, defaultPARALLAX=0.0):
|
154
|
+
"""
|
155
|
+
Returns PARALLAX in arcsec as float value rounded to 4 decimal digits. 0.0 is used as default if not present.
|
156
|
+
"""
|
157
|
+
PARALLAX = self.get(target, "PARALLAX", defaultPARALLAX)
|
158
|
+
return round(float(PARALLAX) / 1000.0, 4)
|
159
|
+
|
160
|
+
|
102
161
|
def getFlux(self, target, flux):
|
103
162
|
"""
|
104
163
|
Returns Flux as float values rounded to 3 decimal digits.
|
105
164
|
|
106
165
|
flux in 'V', 'J', 'H'...
|
107
166
|
"""
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
return
|
119
|
-
elif "K0" in baseline:
|
120
|
-
return "astrometric"
|
121
|
-
elif "U" in baseline:
|
122
|
-
return "UTs"
|
167
|
+
try:
|
168
|
+
return round(float(getattr(target, "FLUX_" + flux)), 3)
|
169
|
+
except:
|
170
|
+
raise ValueError(
|
171
|
+
f"Missing {flux} flux for target { getattr(target,'name') }") from None
|
172
|
+
|
173
|
+
def getBaselineCode(self, ob):
|
174
|
+
confAltName = ob.get(ob.interferometerConfiguration, "confAltName")
|
175
|
+
stations = ob.get(ob.interferometerConfiguration, "stations")
|
176
|
+
if confAltName:
|
177
|
+
return confAltName
|
123
178
|
else:
|
124
179
|
raise ValueError(
|
125
|
-
"Can't detect Interferometric Array type from given baseline : %s)" % (
|
180
|
+
"Can't detect alt name of Interferometric Array type from given baseline : %s)" % (stations))
|
181
|
+
|
182
|
+
def getAcquisitionType(self):
|
183
|
+
return self.facility.ui.getAcquisitionType()
|
184
|
+
return "onaxis"
|
185
|
+
return "offaxis"
|
186
|
+
return "wide"
|
187
|
+
|
188
|
+
def checkIssVltiType(self, acqTSF):
|
189
|
+
# TODO improve handling of this keyword using input from Aspro2's OB
|
190
|
+
|
191
|
+
# use GUI live checkboxes instead of preferences
|
192
|
+
vltitypesVars = self.facility.ui.getIssVltitypeVars()
|
193
|
+
vltitypes = [v for v in vltitypesVars
|
194
|
+
if vltitypesVars[v].get() and self.isInRange(acqTSF.tpl, "ISS.VLTITYPE", v)]
|
195
|
+
if vltitypes:
|
196
|
+
self.ui.addToLog(
|
197
|
+
f"Set template's ISS_VLTITYPE to {vltitypes}")
|
198
|
+
acqTSF.ISS_VLTITYPE = vltitypes
|
199
|
+
else:
|
200
|
+
# TODO throw an warning ?
|
201
|
+
self.ui.addToLog(
|
202
|
+
f"Warning: no compatible ISS_VLTITYPE selected in the GUI")
|
203
|
+
pass
|
126
204
|
|
127
205
|
def getA2p2Comments(self):
|
128
206
|
return 'Generated by ' + self.facility.a2p2client.preferences.getP2UserCommentName() + \
|
@@ -147,7 +225,7 @@ class VltiInstrument(Instrument):
|
|
147
225
|
self.ditTable = json.load(open(f))
|
148
226
|
return self.ditTable
|
149
227
|
|
150
|
-
def getDit(self, tel, spec, pol, K, dualFeed=False, showWarning=False):
|
228
|
+
def getDit(self, tel, spec, pol, K, dualFeed=False, targetName="", showWarning=False):
|
151
229
|
"""
|
152
230
|
finds DIT according to ditTable and K magnitude K
|
153
231
|
|
@@ -172,7 +250,7 @@ class VltiInstrument(Instrument):
|
|
172
250
|
if tel == "UT":
|
173
251
|
dK += ditTable["AT"]['Kut']
|
174
252
|
for i, d in enumerate(dits):
|
175
|
-
if mags[i]
|
253
|
+
if mags[i] <= (K - dK) and (K - dK) <= mags[i + 1]:
|
176
254
|
return d
|
177
255
|
|
178
256
|
# handle out of bounds
|
@@ -181,11 +259,19 @@ class VltiInstrument(Instrument):
|
|
181
259
|
for i, d in enumerate(dits):
|
182
260
|
kmin = min(kmin, mags[i] + dK)
|
183
261
|
kmax = max(kmax, mags[i + 1] + dK)
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
262
|
+
|
263
|
+
if showWarning:
|
264
|
+
self.warnings.append(
|
265
|
+
f"K mag ({K}) is out of range [{kmin},{kmax}]\n mode ( ∆K={dK} tel={tel}, spec={spec}, pol={pol}, dualFeed={dualFeed}) \n for target '{targetName}'")
|
266
|
+
|
267
|
+
# always return a value to avoid unsupported operations
|
268
|
+
if K < kmin:
|
269
|
+
return min(dits)
|
270
|
+
return max(dits)
|
271
|
+
|
272
|
+
# raise ValueError(
|
273
|
+
# "K mag (%f) of '%s' is out of ranges [%f,%f]\n for this mode (tel=%s, spec=%s, pol=%s, dualFeed=%s)" % (
|
274
|
+
# K, targetName, kmin, kmax, tel, spec, pol, dualFeed))
|
189
275
|
|
190
276
|
def getRangeTable(self):
|
191
277
|
if self.rangeTable:
|
@@ -220,6 +306,14 @@ class VltiInstrument(Instrument):
|
|
220
306
|
return value >= rangeTable[_tpl][key]['min'] and \
|
221
307
|
value <= rangeTable[_tpl][key]['max']
|
222
308
|
if 'list' in rangeTable[_tpl][key].keys():
|
309
|
+
#
|
310
|
+
# hack set to check for coordinates convention define by p2
|
311
|
+
# vlue will be checked by p2 later...
|
312
|
+
if "ra" in rangeTable[_tpl][key]['list']:
|
313
|
+
return True
|
314
|
+
if "dec" in rangeTable[_tpl][key]['list']:
|
315
|
+
return True
|
316
|
+
|
223
317
|
# return value in rangeTable[_tpl][key]['list']
|
224
318
|
if type(value) is list:
|
225
319
|
for v in value:
|
@@ -280,7 +374,7 @@ class VltiInstrument(Instrument):
|
|
280
374
|
if not key in rangeTable[_tpl].keys():
|
281
375
|
raise ValueError(
|
282
376
|
"unknown keyword '%s' in template '%s'" % (key, tpl))
|
283
|
-
if 'default' in rangeTable[_tpl][key].keys()
|
377
|
+
if 'default' in rangeTable[_tpl][key].keys():
|
284
378
|
return rangeTable[_tpl][key]['default']
|
285
379
|
return None
|
286
380
|
|
@@ -304,13 +398,15 @@ class VltiInstrument(Instrument):
|
|
304
398
|
res[key] = rangeTable[_tpl][key]["default"]
|
305
399
|
return res
|
306
400
|
|
401
|
+
def getSkySeparation(self, ra1, dec1, ra2, dec2):
|
402
|
+
target1 = SkyCoord(ra1, dec1, frame='icrs', unit=(u.hourangle, u.deg))
|
403
|
+
target2 = SkyCoord(ra2, dec2, frame='icrs', unit=(u.hourangle, u.deg))
|
404
|
+
return target1.separation(target2)
|
307
405
|
|
308
|
-
def
|
309
|
-
science = SkyCoord(ra, dec, frame='icrs', unit=
|
310
|
-
|
311
|
-
|
312
|
-
dec_offset = (science.dec - ft.dec)
|
313
|
-
return [ra_offset.deg * 3600 * 1000, dec_offset.deg * 3600 * 1000] # in mas
|
406
|
+
def getSkyOffset(self, ra, dec, originRa, originDec):
|
407
|
+
science = SkyCoord(ra, dec, frame='icrs', unit=(u.hourangle, u.deg))
|
408
|
+
origin = SkyCoord(originRa, originDec, frame='icrs', unit=(u.hourangle, u.deg))
|
409
|
+
return origin.spherical_offsets_to(science)
|
314
410
|
|
315
411
|
def getSiderealTimeConstraints(self, LSTINTERVAL):
|
316
412
|
# by default, above 40 degree. Will generate a WAIVERABLE ERROR if not.
|
@@ -330,9 +426,10 @@ class VltiInstrument(Instrument):
|
|
330
426
|
intervals.append({'from': lstStartSex, 'to': lstEndSex})
|
331
427
|
return intervals
|
332
428
|
|
333
|
-
def saveSiderealTimeConstraints(self, api,
|
429
|
+
def saveSiderealTimeConstraints(self, api, ob, LSTINTERVAL):
|
334
430
|
# wait for next Aspro release to only send constraints set by user
|
335
431
|
return
|
432
|
+
obId = ob['obId']
|
336
433
|
intervals = self.getSiderealTimeConstraints(LSTINTERVAL)
|
337
434
|
if intervals:
|
338
435
|
sidTCs, stcVersion = api.getSiderealTimeConstraints(obId)
|
@@ -362,7 +459,35 @@ class VltiInstrument(Instrument):
|
|
362
459
|
|
363
460
|
return s
|
364
461
|
|
365
|
-
def
|
462
|
+
def formatRangeTable(self):
|
463
|
+
rangeTable = self.getRangeTable()
|
464
|
+
buffer = ""
|
465
|
+
for l in rangeTable.keys():
|
466
|
+
buffer += l + "\n"
|
467
|
+
for k in rangeTable[l].keys():
|
468
|
+
constraint = rangeTable[l][k]
|
469
|
+
keys = constraint.keys()
|
470
|
+
buffer += ' %30s :' % (k)
|
471
|
+
if 'min' in keys and 'max' in keys:
|
472
|
+
buffer += ' %f ... %f ' % (
|
473
|
+
constraint['min'], constraint['max'])
|
474
|
+
elif 'list' in keys:
|
475
|
+
buffer += str(constraint['list'])
|
476
|
+
elif "spaceseparatedlist" in keys:
|
477
|
+
buffer += ' ' + " ".join(constraint['spaceseparatedlist'])
|
478
|
+
if 'default' in keys:
|
479
|
+
buffer += ' (' + str(constraint['default']) + ')'
|
480
|
+
else:
|
481
|
+
buffer += ' -no default-'
|
482
|
+
buffer += "\n"
|
483
|
+
return buffer
|
484
|
+
|
485
|
+
def showP2Response(self, response, ob,):
|
486
|
+
if not ob:
|
487
|
+
return
|
488
|
+
|
489
|
+
obId = ob['obId']
|
490
|
+
|
366
491
|
if response['observable']:
|
367
492
|
msg = 'OB ' + \
|
368
493
|
str(obId) + ' submitted successfully on P2\n' + \
|
@@ -371,9 +496,93 @@ class VltiInstrument(Instrument):
|
|
371
496
|
msg = 'OB ' + str(obId) + ' submitted successfully on P2\n' + ob[
|
372
497
|
'name'] + ' has WARNING.\n see LOG for details.'
|
373
498
|
self.ui.addToLog('\n')
|
374
|
-
self.ui.ShowInfoMessage(msg)
|
499
|
+
# self.ui.ShowInfoMessage(msg)
|
500
|
+
self.ui.addToLog(msg)
|
375
501
|
self.ui.addToLog('\n'.join(response['messages']) + '\n\n')
|
376
502
|
|
503
|
+
def createOB(self, p2container, obTarget, obConstraints, OBJTYPE, instrumentMode, LSTINTERVAL, tsfs):
|
504
|
+
""" Creates an OB on P2 and attach a template for every given tsf."""
|
505
|
+
|
506
|
+
ui = self.ui
|
507
|
+
ui.setProgress(0.1)
|
508
|
+
|
509
|
+
goodName = re.sub('[^A-Za-z0-9]+', '_', obTarget.name)
|
510
|
+
OBS_DESCR = '_'.join(
|
511
|
+
(OBJTYPE[0:3], goodName, self.getName(), instrumentMode))
|
512
|
+
# removed from template name acqTSF.ISS_BASELINE[0]
|
513
|
+
|
514
|
+
# dev code to debug without interracting with P2
|
515
|
+
if False:
|
516
|
+
self.ui.addToLog(f"Skip ob creation : {OBS_DESCR}")
|
517
|
+
for tsf in tsfs:
|
518
|
+
self.ui.addToLog(f"Skip {tsf.getP2Name()} template creation")
|
519
|
+
ui.setProgress(1.0)
|
520
|
+
return None
|
521
|
+
else:
|
522
|
+
self.ui.addToLog(f"Creating new ob from p2 : {OBS_DESCR}")
|
523
|
+
|
524
|
+
api = self.facility.getAPI()
|
525
|
+
|
526
|
+
ob, obVersion = api.createOB(p2container.containerId, OBS_DESCR)
|
527
|
+
|
528
|
+
# we use obId to populate OB
|
529
|
+
ob['obsDescription']['name'] = OBS_DESCR[0:min(len(OBS_DESCR), 31)]
|
530
|
+
ob['obsDescription']['userComments'] = self.getA2p2Comments()
|
531
|
+
|
532
|
+
# copy target info
|
533
|
+
targetInfo = obTarget.getDict()
|
534
|
+
for key in targetInfo:
|
535
|
+
ob['target'][key] = targetInfo[key]
|
536
|
+
|
537
|
+
# copy constraints info
|
538
|
+
constraints = obConstraints.getDict()
|
539
|
+
for k in constraints:
|
540
|
+
ob['constraints'][k] = constraints[k]
|
541
|
+
|
542
|
+
self.ui.addToLog("New OB saved to p2\n%s" % ob, False)
|
543
|
+
ob, obVersion = api.saveOB(ob, obVersion)
|
544
|
+
|
545
|
+
# set time constraints if present
|
546
|
+
self.saveSiderealTimeConstraints(api, ob, LSTINTERVAL)
|
547
|
+
ui.addProgress()
|
548
|
+
|
549
|
+
for tsf in tsfs:
|
550
|
+
ui.addProgress()
|
551
|
+
self.createTemplate(ob,tsf)
|
552
|
+
|
553
|
+
# verify OB online
|
554
|
+
response = self.verifyOB(ob)
|
555
|
+
ui.setProgress(1.0)
|
556
|
+
|
557
|
+
self.showP2Response(response, ob)
|
558
|
+
|
559
|
+
return ob
|
560
|
+
|
561
|
+
def createTemplate(self, ob, tsf, templateName=None):
|
562
|
+
if not templateName:
|
563
|
+
templateName = tsf.getP2Name()
|
564
|
+
|
565
|
+
if not ob:
|
566
|
+
self.ui.addToLog(f"Request for new template ignored '{templateName}'")
|
567
|
+
return
|
568
|
+
self.ui.addToLog(f"Creating new template '{templateName}'")
|
569
|
+
obId = ob['obId']
|
570
|
+
api = self.facility.getAPI()
|
571
|
+
tpl, tplVersion = api.createTemplate(obId, templateName)
|
572
|
+
values = tsf.getDict()
|
573
|
+
tpl, tplVersion = api.setTemplateParams(
|
574
|
+
obId, tpl, values, tplVersion)
|
575
|
+
|
576
|
+
def verifyOB(self, ob):
|
577
|
+
if not ob:
|
578
|
+
self.ui.addToLog(f"Request to verify OB ignored")
|
579
|
+
return
|
580
|
+
|
581
|
+
api = self.facility.getAPI()
|
582
|
+
response, _=api.verifyOB(ob['obId'], True)
|
583
|
+
return response
|
584
|
+
|
585
|
+
|
377
586
|
|
378
587
|
# TemplateSignatureFile
|
379
588
|
# use new style class to get __getattr__ advantage
|
@@ -410,6 +619,9 @@ class TSF(object):
|
|
410
619
|
def getDict(self):
|
411
620
|
return self.tsfParams
|
412
621
|
|
622
|
+
def getName(self):
|
623
|
+
return self.tpl
|
624
|
+
|
413
625
|
def getP2Name(self):
|
414
626
|
return self.tpl[0:-4]
|
415
627
|
|
@@ -488,9 +700,14 @@ class FixedDict(object):
|
|
488
700
|
|
489
701
|
class OBTarget(FixedDict):
|
490
702
|
|
491
|
-
def __init__(self):
|
703
|
+
def __init__(self, instrument, scienceTarget):
|
492
704
|
FixedDict.__init__(
|
493
705
|
self, ('name', 'ra', 'dec', 'properMotionRa', 'properMotionDec'))
|
706
|
+
# Target name can include any alphanumeric character, and space, dot, plus or minus signs [a-z][A-Z][0-9][.+- ]
|
707
|
+
# ( https://www.eso.org/sci/observing/phase2/p2intro/p2-tutorials/p2-ImportTargetList.html )
|
708
|
+
self.name = re.sub(r'[^a-zA-Z0-9.\+\- ]+','',scienceTarget.name.strip())
|
709
|
+
self.ra, self.dec = instrument.getCoords(scienceTarget)
|
710
|
+
self.properMotionRa, self.properMotionDec = instrument.getPMCoords(scienceTarget)
|
494
711
|
|
495
712
|
|
496
713
|
class OBConstraints(TSF):
|
@@ -498,4 +715,4 @@ class OBConstraints(TSF):
|
|
498
715
|
def __init__(self, instrument):
|
499
716
|
TSF.__init__(self, instrument, "instrumentConstraints.tsf")
|
500
717
|
# WORKARROUND missing param in p2 json but valid and used in our code
|
501
|
-
instrument.getRangeTable()[self.tpl]["name"]={}
|
718
|
+
instrument.getRangeTable()[self.tpl]["name"] = {}
|