diff --git a/README.md b/README.md index b2ff8c560566bb5c86bbd9903f9121b4bf706026..13743c85b3869178cbb3d8d66a38d9d084cacfeb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ These are scripts for interfacing with the TMSS API. - `script/run_script_fe.sh` runs the `tmss_fe_test_observation.py` using the `config_fe.yaml` - `script/run_script_im.sh` runs the `tmss_im_test_observation.py` using the `config_im.yaml` -Install the LOFAR TMSS client from https://git.astron.nl/ro/lofar_tmss_client +Install the LOFAR TMSS client from https://git.astron.nl/tmss/lofar_tmss_client The scripts use a `login.yaml` file which should contain diff --git a/tmss_cal_observation.py b/tmss_cal_observation.py new file mode 100755 index 0000000000000000000000000000000000000000..3fad5b6f8e523e119a8c60378b94b633809fd7f6 --- /dev/null +++ b/tmss_cal_observation.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +import os +import sys +import yaml +import json +import argparse +from datetime import datetime, timedelta, UTC +from math import ceil + +import astropy.units as u +from astropy.coordinates import SkyCoord, get_icrs_coordinates + +from lofar_tmss_client.tmss_http_rest_client import TMSSsession + +from print_dict import print_dict + +if __name__ == "__main__": + # Read command line arguments + parser = argparse.ArgumentParser(description="Schedule station calibration observations in TMSS") + parser.add_argument("-s", "--source", help="Source to observe [str, default: Cas A]", + default="Cas A", type=str) + parser.add_argument("-a", "--antennafield", help="Antenna field to select [str, default: HBA_DUAL]", + default="HBA_DUAL", type=str) + parser.add_argument("-f", "--filter", help="Filter to select [str, default: HBA_110_190]", + default="HBA_110_190", type=str) + parser.add_argument("-t", "--tstart", help="Time between start (isot) [str, default: now]", + default=None, type=str) + parser.add_argument("-w", "--window", help="Time between window length (d) [float, default: 1]", + default=1.0, type=float) + parser.add_argument("-L", "--stationlist", help="Station to use [str, default: CS001, can be multiple, e.g. \"CS001,CS002,CS003\"]", + default="CS001", type=str) + parser.add_argument("-i", "--scheduling_set_id", help="Scheduling set ID [int, default: 395]", + default=395, type=int) + parser.add_argument("-M", "--description", help="Observation description [str, example \"HBA station calibration\", default: \"HBA station calibration\"]", + default="HBA station calibration", type=str) + parser.add_argument("-v", "--verbose", help="Provide detailed output", + action="store_true") + parser.add_argument("-F", "--fixed_time", help="Fix observation start time (no dynamic scheduling)", + action="store_true") + parser.add_argument("-u", "--upload", help="Upload specification document and create scheduling unit draft", + action="store_true") + parser.add_argument("-b", "--blueprint", help="Blueprint uploaded scheduling unit draft", + action="store_true") + parser.add_argument("-S", "--subbands", help="Inital subband configuration", + default=[0], nargs='+', type=int) + parser.add_argument("-p", "--subband_step", help="Subband step size per integration", + default=1, type=int) + parser.add_argument("-T", "--integration_time", help="Integration time per subband captured", + default=1.0, type=float) + parser.add_argument("-N", "--num_cycles", help="Number of full subband cycles", + default=1.0, type=float) + args = parser.parse_args() + + # Settings + run_spec = {"strategy_name": "FE Stokes I - raw", + "description": args.description} + if args.fixed_time: + src_spec = {"name": args.source, + "elev_min_deg": 00, + "lst_min_s": -43200, + "lst_max_s": 43200, + "priority_queue": "A", + "rank": 1.00} + else: + src_spec = {"name": args.source, + "elev_min_deg": 30, + "lst_min_s": -7200, + "lst_max_s": 7200, + "priority_queue": "A", + "rank": 1.00} + + # Get pointing + p = get_icrs_coordinates(args.source) + pointing = {"target": args.source, + "angle1": p.ra.rad, + "angle2": p.dec.rad, + "direction_type": "J2000"} + + # Start time + if args.tstart is None: + # Round to start of minute + tstart = datetime.now(UTC) + else: + tstart = datetime.strptime(args.tstart, "%Y-%m-%dT%H:%M:%S") + tend = tstart + timedelta(days=args.window) + tstart = tstart.strftime("%Y-%m-%dT%H:%M:%S") + tend = tend.strftime("%Y-%m-%dT%H:%M:%S") + + # Station groups for Fly's Eye observations + stationlist = [item for item in args.stationlist.split(",")] + station_groups = [{"stations": [item], + "max_nr_missing": 1} for item in stationlist] + + # Check antenna field against LOFAR2.0 stations + if args.antennafield == "LBA_ALL": + if not set(stationlist) <= set(["CS001", "CS032", "RS307"]): + print("Can not use LBA_ALL on LOFAR stations. Exiting.") + sys.exit() + + # Check if filter is compatible with antenna set + if ("LBA" in args.filter and "HBA" in args.antennafield) or ("HBA" in args.filter and "LBA" in args.antennafield): + print("Wrong combination of antennafield and filter selection. Exiting.") + sys.exit() + + observation_time = int(ceil(args.integration_time * 512 * args.num_cycles / args.subband_step)) + # Specify observing mode + mode = {"stokes": "I", + "quantisation": { + "bits": 8, + "enabled": False, + "scale_max": 5, + "scale_min": -5, + }, + "subbands_per_file": 488, + "channels_per_subband": 16, + "time_integration_factor": 512 + } + + # Read credentials + with open("login.yaml", "r") as fp: + settings = yaml.full_load(fp) + + # Open session + with TMSSsession(host=settings['host'], + port=settings['port'], + username=settings['username'], + password=settings['password']) as client: + print("Opened TMSS connection") + + # Get the latest satellite monitoring template + template = client.get_scheduling_unit_observing_strategy_template(run_spec['strategy_name']) + print(f"Using strategy template {template['url']}") + + # Get the specifications document + original_spec_doc = client.get_scheduling_unit_observing_strategy_template_specification_with_just_the_parameters(template['name'], template['version']) + + # Copy original specification document + spec_doc = original_spec_doc.copy() + + if args.fixed_time: + spec_doc['scheduling_constraints_doc']['time']['at'] = f'{tstart}' + spec_doc['scheduling_constraints_doc']['scheduler'] = 'fixed_time' + else: + spec_doc['scheduling_constraints_doc']['time']['between'] = [{"from": tstart, "to": tend}] + spec_doc['scheduling_constraints_doc']['scheduler'] = 'dynamic' + spec_doc['scheduling_constraints_doc']['sky']['transit_offset']['from'] = src_spec['lst_min_s'] + spec_doc['scheduling_constraints_doc']['sky']['transit_offset']['to'] = src_spec['lst_max_s'] + + spec_doc['tasks']['Observation']['specifications_doc']['duration'] = observation_time + spec_doc['tasks']['Observation']['short_description'] = src_spec["name"] + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['SAPs'] = [{"subbands": [200], + "digital_pointing": pointing}] + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['tile_beam'] = pointing + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['antenna_set'] = args.antennafield + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['filter'] = args.filter + + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['station_groups'] = station_groups + spec_doc['tasks']['Observation']['specifications_doc']['beamformer']['pipelines'][0]['station_groups'] = station_groups + spec_doc['tasks']['Observation']['specifications_doc']['beamformer']['pipelines'][0]['flys eye']['settings'] = mode + + spec_doc['tasks']['Observation']['specifications_doc']['QA']['XST'] = {"enabled": True, + "integration_interval": args.integration_time, + "subbands": args.subbands, + "subbands_step": args.subband_step} + + # Show spec doc + if args.verbose: + print_dict(spec_doc, prefix="spec_doc") + + # Skip if not uploaded + if not args.upload: + print("No scheduling units uploaded to TMSS.") + print() + sys.exit() + + # Create scheduling unit + scheduling_unit_draft = client.create_scheduling_unit_draft_from_strategy_template(template['id'], args.scheduling_set_id, spec_doc, src_spec["name"], run_spec['description'], src_spec['priority_queue'], src_spec['rank']) + + # Patch scheduling unit with keys that are not included in the strategy + print(f"Created SU draft {scheduling_unit_draft['id']} for {src_spec['name']} at {scheduling_unit_draft['url']}") + + # Skip if not blueprinted + if not args.blueprint: + print("No scheduling units blueprinted.") + print() + sys.exit() + + # Blueprint SU + scheduling_unit_blueprint = client.create_scheduling_unit_blueprint_and_tasks_and_subtasks_tree(scheduling_unit_draft['id']) + print(f"Created SU blueprint {scheduling_unit_blueprint['id']} for {src_spec['name']} at {scheduling_unit_blueprint['url']}") + diff --git a/tmss_fe_observation.py b/tmss_fe_observation.py index fa74441fca1fc2aaa4614ca4ae60bbbecc4c483b..18a17ad9d402cd3fe006154dee711ecb723da240 100755 --- a/tmss_fe_observation.py +++ b/tmss_fe_observation.py @@ -33,8 +33,8 @@ if __name__ == "__main__": default="CS001", type=str) parser.add_argument("-i", "--scheduling_set_id", help="Scheduling set ID [int, default: 305]", default=305, type=int) - parser.add_argument("-p", "--pointing", help="Override pointing [str, example: \"Zenith,0.0,1.5707963,AZELGEO\", default: None]", - default=None, type=str) + parser.add_argument("-p", "--pointings", help="Override pointing (can be multiple) [str, example: \"Zenith,0.0,1.5707963,AZELGEO\", default: None]", + default=None, type=str, action="append") parser.add_argument("-m", "--mode", help="Observing mode (I, IQUV or XXYY) [str, default: I]", default="I", type=str) parser.add_argument("-D", "--downsamp", help="Downsampling factor for Stokes I observing [int, default: 16]", @@ -45,6 +45,12 @@ if __name__ == "__main__": default=1, type=int) parser.add_argument("-N", "--subbands_per_file", help="Number of subbands per file [int, default: 488 for mode I, 20 for mode XX]", default=None, type=int) + parser.add_argument("-M", "--description", help="Observation description [str, example \"Test observation\", default: None, will use source name]", + default=None, type=str) + parser.add_argument("-X", "--xst", help="XST settings (subband start, subband step, integration time) [str, example: \"194,0,1.0\", default: None]", + default=None, type=str) + parser.add_argument("-v", "--verbose", help="Provide detailed output", + action="store_true") parser.add_argument("-u", "--upload", help="Upload specification document and create scheduling unit draft", action="store_true") parser.add_argument("-b", "--blueprint", help="Blueprint uploaded scheduling unit draft", @@ -62,19 +68,40 @@ if __name__ == "__main__": "rank": 1.00} # Get pointing - if args.pointing is None: + if args.pointings is None: p = get_icrs_coordinates(args.source) - pointing = {"target": args.source, - "angle1": p.ra.rad, - "angle2": p.dec.rad, - "direction_type": "J2000"} + pointings = [{"target": args.source, + "angle1": p.ra.rad, + "angle2": p.dec.rad, + "direction_type": "J2000"}] + tile_pointing = pointings[0] else: - parts = args.pointing.split(",") - pointing = {"target": parts[0], - "angle1": float(parts[1]), - "angle2": float(parts[2]), - "direction_type": parts[3]} - src_spec["name"] = parts[0] + pointings = [] + first = True + for point in args.pointings: + parts = point.split(",") + pointing = {"target": parts[0], + "angle1": float(parts[1]), + "angle2": float(parts[2]), + "direction_type": parts[3]} + if first: + src_spec["name"] = parts[0] + tile_pointing = pointing + first = False + pointings.append(pointing) + + # Get XST settings + if args.xst is not None: + parts = args.xst.split(",") + xst_spec = {"enabled": True, + "subbands": [int(parts[0])], + "subbands_step": int(parts[1]), + "integration_interval": float(parts[2])} + else: + xst_spec = {"enabled": False, + "subbands": [300], + "subbands_step": 0, + "integration_interval": 1.0} # Decode subbands if "," in args.subband: @@ -89,7 +116,7 @@ if __name__ == "__main__": subband_list = [subband] * nsubband else: subband_list = [int(args.subband)] - + # Start time if args.tstart is None: # Round to start of minute @@ -115,6 +142,11 @@ if __name__ == "__main__": print("Wrong combination of antennafield and filter selection. Exiting.") sys.exit() + # Check if total number of subbands fits + if len(subband_list) * len(pointings) * args.saps > 488: + print("Too many subbands per pointing specified. Exiting.") + sys.exit() + # Subbands per file if args.subbands_per_file is not None: subbands_per_file = args.subbands_per_file @@ -190,18 +222,25 @@ if __name__ == "__main__": spec_doc['scheduling_constraints_doc']['scheduler'] = 'fixed_time' spec_doc['scheduling_constraints_doc']['sky']['transit_offset']['from'] = src_spec['lst_min_s'] spec_doc['scheduling_constraints_doc']['sky']['transit_offset']['to'] = src_spec['lst_max_s'] + for source_constraint in ['sun', 'moon', 'jupiter']: + spec_doc['scheduling_constraints_doc']['sky']['min_distance']['target'][source_constraint] = 0 + spec_doc['scheduling_constraints_doc']['sky']['min_distance']['calibrator'][source_constraint] = 0 spec_doc['tasks']['Observation']['specifications_doc']['duration'] = args.length spec_doc['tasks']['Observation']['short_description'] = src_spec["name"] saps = [] - for isap in range(args.saps): - sap = { - "subbands": subband_list, - "digital_pointing": pointing - } - saps.append(sap) + idx = 0 + for pointing in pointings: + for isap in range(args.saps): + sap = { + "name": f"SAP{idx:03d}", + "subbands": subband_list, + "digital_pointing": pointing + } + saps.append(sap) + idx += 1 spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['SAPs'] = saps - spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['tile_beam'] = pointing + spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['tile_beam'] = tile_pointing spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['antenna_set'] = args.antennafield spec_doc['tasks']['Observation']['specifications_doc']['station_configuration']['filter'] = args.filter @@ -209,9 +248,13 @@ if __name__ == "__main__": spec_doc['tasks']['Observation']['specifications_doc']['beamformer']['pipelines'][0]['station_groups'] = station_groups spec_doc['tasks']['Observation']['specifications_doc']['beamformer']['pipelines'][0]['flys eye']['settings'] = mode - # Show spec doc - print_dict(spec_doc, prefix="spec_doc") + if xst_spec["enabled"]: + spec_doc['tasks']['Observation']['specifications_doc']['QA']['XST'] = xst_spec + # Show spec doc + if args.verbose: + print_dict(spec_doc, prefix="spec_doc") + # Skip if not uploaded if not args.upload: print("No scheduling units uploaded to TMSS.") diff --git a/tmss_format_l2json_commands.py b/tmss_format_l2json_commands.py new file mode 100755 index 0000000000000000000000000000000000000000..478a6b79027720a79abd10a6475c331e4e313604 --- /dev/null +++ b/tmss_format_l2json_commands.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +import sys +import json +import yaml +import argparse + +from datetime import datetime, timedelta, UTC + +from lofar_tmss_client.tmss_http_rest_client import TMSSsession + +from print_dict import print_dict + +if __name__ == "__main__": + # Read command line arguments + parser = argparse.ArgumentParser(description="List tasks") + parser.add_argument("-p", "--project", help="Project to which tasks belong [str, default: COM_LOFAR2]", + default="Calibration", type=str) + parser.add_argument("-s", "--tstart", help="Start time (isot) [str, default: now - 1 day]", + default=None, type=str) + parser.add_argument("-e", "--tend", help="Start time (isot) [str, default: now]", + default=None, type=str) + args = parser.parse_args() + + task_type = "observation" + + # Start time + if args.tstart is None and args.tend is None: + tstart = (datetime.now(UTC) + timedelta(days=-1)).strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + tend = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + else: + tstart = datetime.strptime(args.tstart, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + tend = datetime.strptime(args.tend, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + + # Read credentials + with open("login.yaml", "r") as fp: + settings = yaml.load(fp, Loader=yaml.FullLoader) + + with TMSSsession(host=settings['host'], + port=settings['port'], + username=settings['username'], + password=settings['password']) as client: + + # Format URL + url = f"https://tmss.lofar.eu/api/task_blueprint?tags=&created_at_after=&created_at_before=&updated_at_after=&updated_at_before=&name=&description=&scheduled_start_time_after={tstart}&scheduled_start_time_before={tend}&scheduled_stop_time_after=&scheduled_stop_time_before=&actual_process_start_time_after=&actual_process_start_time_before=&actual_process_stop_time_after=&actual_process_stop_time_before=&actual_on_sky_start_time_after=&actual_on_sky_start_time_before=&actual_on_sky_stop_time_after=&actual_on_sky_stop_time_before=&process_start_time_after=&process_start_time_before=&process_stop_time_after=&process_stop_time_before=&on_sky_start_time_after=&on_sky_start_time_before=&on_sky_stop_time_after=&on_sky_stop_time_before=&on_sky_duration=&duration=&specified_on_sky_duration=&obsolete_since=&short_description=&specifications_doc=&specifications_template=&draft=&scheduling_unit_blueprint=&output_pinned=unknown&id=&id_min=&id_max=&scheduling_unit_blueprint_min=&scheduling_unit_blueprint_max=&scheduling_unit_blueprint_name=&scheduling_set_name=&project={args.project}&draft_min=&draft_max=&duration_min=&duration_max=&on_sky_duration_min=&on_sky_duration_max=&relative_start_time_min=&relative_start_time_max=&relative_stop_time_min=&relative_stop_time_max=&subtasks_min=&subtasks_max=&obsolete=&task_type={task_type}" + + # Query results + spec_doc = client.do_request_and_get_result_as_json_object(method="GET", full_url=url) + + # Print results + for o in spec_doc["results"]: + blueprint_id = o['scheduling_unit_blueprint_id'] + description = o['short_description'] + duration = o['specifications_doc']['duration'] + task_type = o['task_type'] + obsid = o['subtasks_ids'][0] + tstart = o['scheduled_start_time'] + band = o['specifications_doc']['station_configuration']['filter'] + antennaset = o['specifications_doc']['station_configuration']['antenna_set'] + station_groups = o['specifications_doc']['station_configuration']['station_groups'] + stations = [s for sg in station_groups for s in sg['stations']] + #print(f"| {obsid} | {blueprint_id} | {task_type} | {tstart} | {duration:6d} | {antennaset:8s} | {band:11s} | {description} | {stations}") + + # Create station string + station_string = "" + for station in stations: + station_string += f"{station} " + station_string = station_string.rstrip() + + if "LBA" in antennaset: + cmd = f"python l2json/quick_impl.py --tstart {tstart} --duration {duration} --output_pattern \"/home/bassa/calibration/{{start}}_L{obsid}_{{station}}{{field}}_{{datatype}}.h5\" --station {station_string} --type XST --field LBA" + elif "HBA_DUAL" in antennaset: + cmd = f"python l2json/quick_impl.py --tstart {tstart} --duration {duration} --output_pattern \"/home/bassa/calibration/{{start}}_L{obsid}_{{station}}{{field}}_{{datatype}}.h5\" --station {station_string} --type XST --field HBA0 HBA1 HBA" + print(cmd) diff --git a/tmss_list_observations.py b/tmss_list_observations.py new file mode 100755 index 0000000000000000000000000000000000000000..618a26972b144ce351477853c0d02b38287828f5 --- /dev/null +++ b/tmss_list_observations.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +import sys +import json +import yaml +import argparse + +from datetime import datetime, timedelta, UTC + +from lofar_tmss_client.tmss_http_rest_client import TMSSsession + +from print_dict import print_dict + +if __name__ == "__main__": + # Read command line arguments + parser = argparse.ArgumentParser(description="List tasks") + parser.add_argument("-p", "--project", help="Project to which tasks belong [str, default: COM_LOFAR2]", + default="COM_LOFAR2", type=str) + parser.add_argument("-s", "--tstart", help="Start time (isot) [str, default: now - 1 day]", + default=None, type=str) + parser.add_argument("-e", "--tend", help="Start time (isot) [str, default: now]", + default=None, type=str) + args = parser.parse_args() + + task_type = "observation" + + # Start time + if args.tstart is None and args.tend is None: + tstart = (datetime.now(UTC) + timedelta(days=-1)).strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + tend = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + else: + tstart = datetime.strptime(args.tstart, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + tend = datetime.strptime(args.tend, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S").replace(":", "%3A") + + # Read credentials + with open("login.yaml", "r") as fp: + settings = yaml.load(fp, Loader=yaml.FullLoader) + + with TMSSsession(host=settings['host'], + port=settings['port'], + username=settings['username'], + password=settings['password']) as client: + + # Format URL + url = f"https://tmss.lofar.eu/api/task_blueprint?tags=&created_at_after=&created_at_before=&updated_at_after=&updated_at_before=&name=&description=&scheduled_start_time_after={tstart}&scheduled_start_time_before={tend}&scheduled_stop_time_after=&scheduled_stop_time_before=&actual_process_start_time_after=&actual_process_start_time_before=&actual_process_stop_time_after=&actual_process_stop_time_before=&actual_on_sky_start_time_after=&actual_on_sky_start_time_before=&actual_on_sky_stop_time_after=&actual_on_sky_stop_time_before=&process_start_time_after=&process_start_time_before=&process_stop_time_after=&process_stop_time_before=&on_sky_start_time_after=&on_sky_start_time_before=&on_sky_stop_time_after=&on_sky_stop_time_before=&on_sky_duration=&duration=&specified_on_sky_duration=&obsolete_since=&short_description=&specifications_doc=&specifications_template=&draft=&scheduling_unit_blueprint=&output_pinned=unknown&id=&id_min=&id_max=&scheduling_unit_blueprint_min=&scheduling_unit_blueprint_max=&scheduling_unit_blueprint_name=&scheduling_set_name=&project={args.project}&draft_min=&draft_max=&duration_min=&duration_max=&on_sky_duration_min=&on_sky_duration_max=&relative_start_time_min=&relative_start_time_max=&relative_stop_time_min=&relative_stop_time_max=&subtasks_min=&subtasks_max=&obsolete=&task_type={task_type}" + + # Query results + spec_doc = client.do_request_and_get_result_as_json_object(method="GET", full_url=url) + + #print(f"|| OBSID || BP ID || Task || Start || Duration || Antenna Set || Band || Description | Stations |") + + #print_dict(spec_doc, prefix="spec_doc") + + # Print results + for o in spec_doc["results"]: +# print(o) + blueprint_id = o['scheduling_unit_blueprint_id'] + description = o['short_description'] + duration = o['specifications_doc']['duration'] + task_type = o['task_type'] + obsid = o['subtasks_ids'][0] + tstart = o['scheduled_start_time'] + band = o['specifications_doc']['station_configuration']['filter'] + antennaset = o['specifications_doc']['station_configuration']['antenna_set'] + station_groups = o['specifications_doc']['station_configuration']['station_groups'] + stations = [s for sg in station_groups for s in sg['stations']] + #print(f"| {obsid} | {blueprint_id} | {task_type} | {tstart} | {duration:6d} | {antennaset:8s} | {band:11s} | {description} | {stations}") + + # Create station string + station_string = "" + for station in stations: + station_string += f"{station} " + station_string = station_string.rstrip() + + if "LBA" in antennaset: + cmd = f"python l2json/quick_impl.py --tstart {tstart} --duration {duration} --output_pattern \"/home/bassa/calibration/{{start}}_L{obsid}_{{station}}{{field}}_{{datatype}}.h5\" --station {station_string} --type XST --field LBA" + elif "HBA_DUAL" in antennaset: + cmd = f"python l2json/quick_impl.py --tstart {tstart} --duration {duration} --output_pattern \"/home/bassa/calibration/{{start}}_L{obsid}_{{station}}{{field}}_{{datatype}}.h5\" --station {station_string} --type XST --field HBA0 HBA1 HBA" + print(cmd)