-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnap_onoff_obs.py
executable file
·339 lines (276 loc) · 14.1 KB
/
snap_onoff_obs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/usr/bin/python3
'''
Name: snap_obs.py
Author: Jon Richards, SETI Institute
Date: August/Sept 2018
Note: This program was originally called snap_observation_run.py written by
Jack Hicish. It has been modified by Jon Richards to handle multiple RF
switches to work in unison.
As of August 25 the rfswitch and atten programs have been changed.
Here is the new syntax:
rfswitch <ant|antPol>
Swiched the appropriate rfswitch to the specified antenn pols or
pols. If you specify an ant pol, only that one switch will select the
antenna pol. For instance, "rfswitch 2a" will switch both the x an y
rfswitches to 2a's x and y pol inputs. "rfswitch 2ax" will only
switch the x pol. THis is useful when using x and y pols hooked to the
same 16x1 rf switch.
atten <db> <ant|antPol>
Sets the attenuation for and antenna (does pol pols) or just one
pol.
'''
import sys
import logging
from optparse import OptionParser
from SNAPobs import snap_defaults,snap_observations
from ATATools import ata_control,logger_defaults,ata_positions,snap_array_helpers
from ATAobs import obs_db
import ATAComm
import onoff_db
from six.moves import configparser
default_fpga_file = snap_defaults.spectra_snap_file
default_captures = 16
default_repetitions = 3
default_pointings = "0.0,10"
default_rms = snap_defaults.rms
def onoff_observations(ant_dict,obs_set_id,freq,fpga_file,source,repetitions,ncaptures,az_offset,el_offset):
"""
do a series of On Off observations for given set ID
"""
logger= logger_defaults.getModuleLogger(__name__)
if az_offset == 0.0 and el_offset == 0.0:
logger.error("both azimuth and elevation offset are 0. It is NOT how on-off observations should be made")
raise RuntimeError("az and el offset are both 0")
if not obs_set_id:
logger.error("no set id for On Off observations")
raise RuntimeError("no set id")
obsids = []
for rep in range(repetitions):
for on_or_off in ["on", "off"]:
ants = snap_array_helpers.dict_values_to_comma_string(ant_dict)
logger.info("pointing antennas {} to position {}".format(ants,on_or_off))
ata_control.point_ants(on_or_off, ants)
desc = "{} repetition {}".format(on_or_off.upper(),rep)
filefragment = "{0!s}_{1:03d}".format(on_or_off,rep)
if(on_or_off == "on" and rep == 0):
attendict = snap_observations.setRMS(ant_dict,fpga_file,default_rms)
if(on_or_off == "on"):
caz = 0.0
cel = 0.0
else:
caz = az_offset
cel = el_offset
cobsid = snap_observations.record_same(ant_dict,freq,source,ncaptures,
"ON-OFF","ataonoff",desc,filefragment,"SNAP",caz,cel,fpga_file,obs_set_id)
obs_db.updateAttenVals(cobsid,attendict)
obsids.append(cobsid)
#if we got to this point without raising an exception, we are marking all measurements as OK
logger.info("marking observations {} as OK".format(', '.join(map(str,obsids))))
obs_db.markRecordingsOK(obsids)
def remove_dups(duplicate):
final_list = list(set(duplicate))
return final_list
def main():
# Define the argumants
parser = OptionParser(usage= 'Usage %prog options',
description='Run an observation with multiple antennas and pointings')
#parser.add_argument('hosts', type=str, help = hostnamesHelpString)
parser.add_option('--fpga', dest='fpga_file', type=str, action="store", default=default_fpga_file,
help = '.fpgfile to program')
#parser.add_argument('-s', dest='srate', type=float, default=900.0,
# help ='Sample rate in MHz for non-interleaved band. Used for spectrum axis scales')
parser.add_option('-n', dest='ncaptures', type=int, action="store", default=default_captures,
help ='Number of data captures (for each correlation product)')
parser.add_option('-r', dest='repetitions', type=int, action="store", default=default_repetitions,
help ='Number of repetitions of on-off pairs')
parser.add_option('-i', dest='obs_set', type=int, action="store", default=None,
help ='Observation set ID. If present it will continue previous observations')
parser.add_option('-a', dest='ants', type=str, action="store", default=None,
help ='Comma separated array list of ATA antennas, eg: \"2j,2d,4k\"')
parser.add_option('-p', dest='pointings', type=str, action="store", default=None,
help ='Comma separated list of on off sources, eg: \"casa,vira,moon\"')
parser.add_option('-o', dest='off', type=str, action="store", default=default_pointings,
help ='Specify the off az,el in degrees, eg: 10,0')
parser.add_option('-f', dest='freqs', type=str, action="store", default=None,
help ='Comma separated list of sky tuning frequencies, in MHz. Only one set of frequencies, eg: \"2000,3000,4000\"')
parser.add_option('-c', '--config', dest='configfile', type=str, action="store", default=None,
help ="config file with measurement parameters")
parser.add_option('-v', '--verbose', dest='verbose', action="store_true", default=False,
help ="More on-screen information")
parser.add_option('--no-file', dest='nofile', action="store_true", default=False,
help ="log to screen, not to file")
parser.add_option('-m', '--mail', dest='mail', action="store", default=None,
help ="The recipient e-mail address (if different from default)")
(options,args) = parser.parse_args()
if(options.verbose):
loglevel=logging.INFO
else:
loglevel=logging.WARNING
if(options.nofile):
logger = logger_defaults.getProgramLogger("SNAP_ON_OFF_OBS",loglevel)
else:
logger = logger_defaults.getFileLogger("SNAP_ON_OFF_OBS",'/var/log/ata/onoff.log',loglevel)
if len(sys.argv) <= 1:
logger.warning("no options provided")
parser.print_help()
sys.exit(1)
try:
if options.configfile:
configParser = configparser.RawConfigParser()
configParser.read(options.configfile)
ant_str = configParser.get('measurement', 'antennas')
freq_str = configParser.get('measurement', 'freq')
pointings_str = configParser.get('measurement', 'sources')
except:
logger.exception("config file exception")
raise
if options.mail:
ATAComm.setRecipient(options.mail)
if options.ants:
ant_str = options.ants
else:
if not options.configfile:
logger.error("antennas were not provided and no config file")
raise RuntimeError("no antenna string")
if options.obs_set:
#todo: check if that ID exits
try:
obs_set_id = options.obs_set
obs_db.getSetData(obs_set_id)
except:
logger.error("Data set id {} does not exist".format(obs_set_id))
raise
else:
obs_set_id = obs_db.getNewObsSetID("OnOff observation")
if options.freqs:
freq_str = options.freqs
else:
if not options.configfile:
logger.error("frequencies were not provided and no config file")
raise RuntimeError("no freq string")
if options.pointings:
pointings_str = options.pointings
else:
if not options.configfile:
logger.error("pointings (sources) were not provided and no config file")
raise RuntimeError("no pointings string")
offs = snap_array_helpers.string_to_numeric_array(options.off)
az_offset = offs[0]
el_offset = offs[1]
repetitions = options.repetitions
ncaptures = options.ncaptures
#TODO: we may need to modify this to add a verbosity/send mail/slack flags
doOnOffObservations(ant_str,freq_str, pointings_str,az_offset,el_offset,repetitions,ncaptures,obs_set_id,options.fpga_file)
exit()
def doOnOffObservations(ant_str,freq_str, pointings_str,az_offset,el_offset,repetitions,ncaptures,obs_set_id,fpga_file):
logger = logger_defaults.getModuleLogger(__name__)
ant_list = snap_array_helpers.string_to_array(ant_str);
pointings = snap_array_helpers.string_to_array(pointings_str);
freq_list = snap_array_helpers.string_to_numeric_array(freq_str);
ant_list = remove_dups(ant_list)
full_ant_str = snap_array_helpers.array_to_string(ant_list)
info_string = ("OnOff Started\nDataset ID {7}\n\nAnts: {0!s}\nFreq: {1!s}\n"
"Pointings: {2!s}\nOff positions: Az={3:3.2f} El={4:3.2f}\n"
"Repetitions {5:d}\nCaptures {6:d}").format(full_ant_str, freq_str, pointings_str,az_offset,el_offset,repetitions,ncaptures,obs_set_id)
logger.info(info_string)
logger.warning("Communication disabled, edit code")
ATAComm.sendMail("SNAP Obs started",info_string)
ATAComm.postSlackMsg(info_string)
try:
ant_groups = ata_control.get_snap_dictionary(ant_list)
except:
logstr = "unable to match antennas with snaps"
logger.exception(logstr)
ATAComm.sendMail("SNAP Obs exception",logstr)
raise
#getting the antennas. From now on we can modify any antenna parameters
# Reserve the antennas
logger.info("Reserving antennas %s in bfa antgroup" % full_ant_str)
try:
ata_control.reserve_antennas(ant_list)
except:
logstr = "unable to reserve the antennas"
logger.exception(logstr)
ATAComm.sendMail("SNAP Obs exception",logstr)
raise
# For each SNAP. set the minicircuits attenuators to 12.0
# To do this, get a list of the first antenna in each snap group
try:
default_atten_db = 12 # Suggested by jack
antpols_list_list = []
atten_list_list = []
for a in ant_groups.keys():
antpols_list_list.append(["%sx"%ant_groups[a][0],"%sy"%ant_groups[a][0]])
atten_list_list.append([default_atten_db, default_atten_db])
ata_control.set_atten_thread(antpols_list_list,atten_list_list)
except:
logstr = "unable to set attenuators"
logger.exception(logstr)
ATAComm.sendMail("SNAP Obs exception",logstr)
ata_control.release_antennas(ant_list, True)
raise
current_source = None
new_antennas = True
logger.info("starting observations")
try:
ata_control.try_on_lnas(ant_list)
while(1):
new_antennas = True
#gets a antenna dictionary and
curr_ant_dict,curr_freq_list = onoff_db.get_obs_params(obs_set_id,pointings,ant_groups,freq_list)
#if None, it meast that all was measured
if not curr_ant_dict:
logger.info("all seems to be measured")
break
for curr_freq in curr_freq_list:
current_source,was_changed = ata_positions.ATAPositions.getPreferedSourceUp(current_source,pointings)
if not current_source:
errormsg = 'no source is up ({}). terminating observation set {}'.format(','.join(pointings),obs_set_id)
logger.error(errormsg)
raise RuntimeError(errormsg)
#we either changed antennas or changed source.
#need to generate the ephemeris and autotune PAMs
if was_changed:
#if we only switched the antennas, we don't need to regenerate
# the ephemeris
logger.info("source changed to {}".format(current_source))
ata_control.create_ephems(current_source, az_offset, el_offset);
if( was_changed or new_antennas):
logger.info("need to (re)run autotune")
curr_ant_list = snap_array_helpers.dict_to_list(curr_ant_dict)
curr_ant_string = snap_array_helpers.array_to_string(curr_ant_list)
logger.info("pointing the antennas")
ata_control.point_ants("on", curr_ant_string );
logger.info("autotuning")
ata_control.autotune(curr_ant_string)
ata_control.rf_switch_thread(curr_ant_list)
new_antennas = False
logger.info("changing to frequency {}".format(curr_freq))
ata_control.set_freq(curr_freq, curr_ant_string)
onoff_observations(curr_ant_dict,obs_set_id,curr_freq,fpga_file,current_source,repetitions,ncaptures,az_offset,el_offset)
#snap_control.do_onoff_obs(args.hosts, \
# "/home/sonata/dev/ata_snap/snap_adc5g_spec/outputs/snap_adc5g_spec_2018-06-23_1048.fpg", \
# source, args.ncaptures, args.repetitions, ants_to_observe, freq, obsid, 0.0, 10.0)
#now, we believe we have measured all frequencies for curr_ant_dict, so we may
#remove the content of it from our original ant_groups. Note that this function
#alters the ant_groups!
onoff_db.remove_antennas_from_dict(ant_groups,curr_ant_dict);
ATAComm.sendMail("SNAP Obs End","Finishing measurements - success")
ATAComm.postSlackMsg("Finishing measurements - success")
except KeyboardInterrupt:
logger.info("Keyboard interuption")
ATAComm.sendMail("SNAP Obs End","Finishing measurements - keyboard interrupt, obsid {}".format(obs_set_id))
ATAComm.postSlackMsg("Finishing measurements - keyboard interrupt")
except Exception as e:
logger.exception("something went wrong")
errmsg = "Finishing measurements - failed, obsid {}: {}".format(obs_set_id,e)
ATAComm.sendMail("SNAP Obs End",errmsg)
ATAComm.postSlackMsg(errmsg)
raise
finally:
logger.info("shutting down")
ata_control.release_antennas(ant_list, True)
#ata_control.release_antennas(ant_list, False)
#logger.warning("not parking the antennas!")
if __name__== "__main__":
main()