Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
507d6b6
First working attempt at implementing per-EB solints
psheehan Feb 5, 2024
9a32ff7
Name the solints p0,p1,p2,...,ap0,ap1,...
psheehan Feb 6, 2024
4316601
Catch cases where spw_baseband == '' in check_spw_widest_in_bb
psheehan Jan 29, 2024
5de7f7c
Fixes to get per-EB solints working when EBs have different #s of sol…
psheehan Feb 22, 2024
ad13212
Merge branch 'main' into refactor_code_spwcombine+per_EB_solints
psheehan Mar 25, 2025
94649ed
Merge branch 'make_pip_installable' into make_pip_installable+per_EB_…
psheehan Mar 25, 2025
7f47723
Show solution interval per-EB in the weblog.
psheehan Apr 1, 2025
b22339a
Add option to use uniform solution intervals across all EBs
psheehan Jul 8, 2025
bf072a6
Merge remote-tracking branch 'origin/make_pip_installable' into make_…
psheehan Jul 8, 2025
4d9b729
Use uniform_solints=True for tests for now to match what was previous…
psheehan Jul 8, 2025
001b8b4
Merge remote-tracking branch 'origin/make_pip_installable' into make_…
psheehan Sep 24, 2025
0bdaea3
Merge remote-tracking branch 'upstream/make_pip_installable' into mak…
psheehan Sep 25, 2025
1562607
Add code to enable testing across the major changes brought by per_EB…
psheehan Sep 25, 2025
15edeea
Make sure the SNR_self_EB array is only as long as the vislist passed…
psheehan Sep 30, 2025
98c293f
Merge branch 'make_pip_installable+per_EB_solints' into make_pip_inst…
psheehan Sep 30, 2025
3b50cb0
Add some keywords to exclude from comparison due to expected changes …
psheehan Sep 30, 2025
2f961af
Merge remote-tracking branch 'upstream/make_pip_installable' into mak…
psheehan Nov 10, 2025
f0870b1
Merge remote-tracking branch 'upstream/make_pip_installable' into mak…
psheehan Nov 10, 2025
84a16b5
Merge branch 'make_pip_installable+per_EB_solints' into make_pip_inst…
psheehan Nov 10, 2025
400b94e
Merge remote-tracking branch 'upstream/main' into make_pip_installabl…
psheehan Apr 8, 2026
d23ce03
Ensure inf_EB and *_ap solints are mapped correctly now that we recor…
psheehan Apr 8, 2026
b836a11
Merge remote-tracking branch 'upstream/main' into make_pip_installabl…
psheehan Apr 23, 2026
c28ed09
Properly handle the key_map so that keys whose names changed are look…
psheehan Apr 24, 2026
38f5711
Track the sub-fields to selfcal/gaincal per-EB. Also store the origin…
psheehan May 7, 2026
4392918
No need to add _ap or _EB for solint matching now that we are trackin…
psheehan May 11, 2026
e733a4a
Make sure the ap solints actually use solmode ap
psheehan May 12, 2026
0de423a
Merge branch 'main' into make_pip_installable+per_EB_solints
psheehan May 12, 2026
5fe98a6
sub-fields-to-selfcal was not being properly updated per-vis after ev…
psheehan May 12, 2026
7da3c3f
Track Stop_Reason per EB as well.
psheehan May 12, 2026
2643132
vis should be vislist
psheehan May 13, 2026
bd14292
Merge branch 'main' into make_pip_installable+per_EB_solints
jjtobin May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions auto_selfcal/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
parser.add_argument('--do_amp_selfcal', default=True)
parser.add_argument('--usermask', default={}, type=ast.literal_eval) # require that it is a CRTF region (CASA region format)
parser.add_argument('--usermodel', default={}, type=ast.literal_eval)
parser.add_argument('--uniform_solints', default=False)
parser.add_argument('--inf_EB_gaincal_combine', default='scan', type=str) # should we get rid of this option?
parser.add_argument('--inf_EB_gaintype', default='G', type=str)
parser.add_argument('--inf_EB_override', action='store_true')
Expand Down
3 changes: 2 additions & 1 deletion auto_selfcal/auto_selfcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def auto_selfcal(
inf_EB_gaintype='G',
inf_EB_override=False,
optimize_spw_combine=True, # if False, will not attempt per spw or per baseband solutions for any solint except inf_EB
uniform_solints=False,
gaincal_minsnr=2.0,
gaincal_unflag_minsnr=5.0,
minsnr_to_proceed=2.95,
Expand Down Expand Up @@ -449,7 +450,7 @@ def auto_selfcal(
vis_for_targets[target][band]['vislist'],
spectral_average=spectral_average, sort_targets_and_EBs=sort_targets_and_EBs, scale_fov=scale_fov, inf_EB_gaincal_combine=inf_EB_gaincal_combine,
inf_EB_gaintype=inf_EB_gaintype, apply_cal_mode_default=apply_cal_mode_default, do_amp_selfcal=do_amp_selfcal,
usermask=usermask, usermodel=usermodel,guess_scan_combine=guess_scan_combine,max_solint=max_solint,
uniform_solints=uniform_solints, usermask=usermask, usermodel=usermodel,guess_scan_combine=guess_scan_combine,max_solint=max_solint,
iscalibrator=iscalibrator, do_delay_cal=do_delay_cal, shorter_amp_solints=shorter_amp_solints,
imsize=imsize, cell=cell, refant=refant, debug=debug)

Expand Down
44 changes: 25 additions & 19 deletions auto_selfcal/gaincal_wrapper.py

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion auto_selfcal/image_analysis_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def get_image_stats(image, mask, backup_mask, selfcal_library, use_nfmask, solin
else:
SNR_NF, RMS_NF = SNR, RMS

for vis in selfcal_library['vislist']:
if suffix in ['dirty','orig','initial','final']:
vislist = selfcal_library['vislist']
else:
vislist = selfcal_library['vislist-to-gaincal']

for vis in vislist:
if suffix in ['dirty','orig','initial','final']:
if spw == 'all':
update_dict = selfcal_library
Expand Down
73 changes: 36 additions & 37 deletions auto_selfcal/mosaic_helpers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import numpy as np
from .selfcal_helpers import *

def evaluate_subfields_to_gaincal(selfcal_library, target, band, solint, iteration, solmode, solints, selfcal_plan,
def evaluate_subfields_to_gaincal(vis, selfcal_library, target, band, solint, iteration, solmode, solints, selfcal_plan,
minsnr_to_proceed, allow_gain_interpolation=False,):

sani_target=sanitize_string(target)

# Fields that don't have any mask in the primary beam should be removed from consideration, as their models are likely bad.
new_fields_to_selfcal = []
for fid in selfcal_library['sub-fields-to-selfcal']:
for fid in selfcal_library[vis]['sub-fields-to-selfcal']:
os.system('rm -rf test*.mask')
tmp_SNR_NF,tmp_RMS_NF=estimate_near_field_SNR(sani_target+'_field_'+str(fid)+'_'+band+'_'+solint+'_'+str(iteration)+'.image.tt0', \
las=selfcal_library['LAS'], mosaic_sub_field=True, save_near_field_mask=False)
Expand Down Expand Up @@ -41,8 +41,8 @@ def evaluate_subfields_to_gaincal(selfcal_library, target, band, solint, iterati
if not checkmask(sani_target+'_field_'+str(fid)+'_'+band+'_'+solint+'_'+str(iteration)+'.image.tt0'):
print("Removing field "+str(fid)+" from gaincal because there is no signal within the primary beam.")
skip_reason = "No signal"
elif selfcal_plan[fid]['solint_snr_per_field'][solints[iteration]] < minsnr_to_proceed and \
solint not in ['inf_EB','scan_inf']:
elif selfcal_plan[fid][vis]['solint_snr_per_field'][solints[iteration]] < minsnr_to_proceed and \
selfcal_plan[vis]['solint_settings'][solint]['sub-name'] not in ['inf_EB','scan_inf']:
print("Removing field "+str(fid)+" from gaincal because the estimated solint snr is too low.")
skip_reason = "Estimated SNR"
elif updated_intflux > selfcal_library['flux_threshold'] * original_intflux:
Expand All @@ -53,45 +53,44 @@ def evaluate_subfields_to_gaincal(selfcal_library, target, band, solint, iterati
new_fields_to_selfcal.append(fid)

if fid not in new_fields_to_selfcal and solint != "inf_EB" and not allow_gain_interpolation:
for vis in selfcal_library[fid]['vislist']:
#selfcal_library[fid][vis][solint]['interpolated_gains'] = True
#selfcal_library[fid]['Stop_Reason'] = "Gaincal solutions would be interpolated"
selfcal_library[fid]['Stop_Reason'] = skip_reason
selfcal_library[fid][vis][solint]['Pass'] = "None"
selfcal_library[fid][vis][solint]['Fail_Reason'] = skip_reason
#selfcal_library[fid][vis][solint]['interpolated_gains'] = True
#selfcal_library[fid]['Stop_Reason'] = "Gaincal solutions would be interpolated"
selfcal_library[fid][vis]['Stop_Reason'] = skip_reason
selfcal_library[fid][vis][solint]['Pass'] = "None"
selfcal_library[fid][vis][solint]['Fail_Reason'] = skip_reason

return new_fields_to_selfcal




def evaluate_subfields_after_gaincal(selfcal_library, target, band, solint, iteration, solmode, allow_gain_interpolation=False):
def evaluate_subfields_after_gaincal(vis, selfcal_library, selfcal_plan, target, band, solint, iteration, solmode, allow_gain_interpolation=False):

new_fields_to_selfcal = selfcal_library['sub-fields-to-selfcal'].copy()
new_fields_to_selfcal = selfcal_library[vis]['sub-fields-to-selfcal'].copy()

sani_target=sanitize_string(target)

if selfcal_library['obstype'] == 'mosaic' and ((solint != "inf_EB" and not allow_gain_interpolation) or \
(allow_gain_interpolation and "inf" not in solint)):
# With gaincal done and bad fields removed from gain tables if necessary, check whether any fields should no longer be selfcal'd
# because they have too much interpolation.
for vis in selfcal_library['vislist']:
#for vis in selfcal_library['vislist']:
if True:
## If an EB had no fields to gaincal on, remove all fields in that EB from being selfcal'd as there is no calibration available
## in this EB.
if np.intersect1d(selfcal_library['sub-fields-to-gaincal'],\
if np.intersect1d(selfcal_library[vis]['sub-fields-to-gaincal'],\
list(selfcal_library['sub-fields-fid_map'][vis].keys())).size == 0:
for fid in np.intersect1d(new_fields_to_selfcal,list(selfcal_library['sub-fields-fid_map'][vis].keys())):
new_fields_to_selfcal.remove(fid)

selfcal_library[fid]['Stop_Reason'] = 'No viable calibrator fields in at least 1 EB'
for v in selfcal_library[fid]['vislist']:
selfcal_library[fid][v][solint]['Pass'] = 'None'
if 'Fail_Reason' in selfcal_library[fid][v][solint]:
selfcal_library[fid][v][solint]['Fail_Reason'] += '; '
else:
selfcal_library[fid][v][solint]['Fail_Reason'] = ''
selfcal_library[fid][v][solint]['Fail_Reason'] += 'No viable fields'
continue
selfcal_library[fid][vis]['Stop_Reason'] = 'No viable calibrator fields in at least 1 EB'
selfcal_library[fid][vis][solint]['Pass'] = 'None'
if 'Fail_Reason' in selfcal_library[fid][vis][solint]:
selfcal_library[fid][vis][solint]['Fail_Reason'] += '; '
else:
selfcal_library[fid][vis][solint]['Fail_Reason'] = ''
selfcal_library[fid][vis][solint]['Fail_Reason'] += 'No viable fields'
return new_fields_to_selfcal
## NEXT TO DO: check % of flagged solutions - DONE, see above
## After that enable option for interpolation through inf - DONE
tb.open(sani_target+'_'+vis+'_'+band+'_'+solint+'_'+str(iteration)+'_'+solmode[iteration]+'_'+
Expand All @@ -100,7 +99,7 @@ def evaluate_subfields_after_gaincal(selfcal_library, target, band, solint, iter
scans = tb.getcol("SCAN_NUMBER")

for fid in np.intersect1d(new_fields_to_selfcal,list(selfcal_library['sub-fields-fid_map'][vis].keys())):
if solint == "scan_inf":
if selfcal_plan[vis]['solint_settings'][solint]['sub-name'] == "scan_inf":
msmd.open(vis)
cals_for_scan = []
total_cals_for_scan = []
Expand All @@ -125,29 +124,29 @@ def evaluate_subfields_after_gaincal(selfcal_library, target, band, solint, iter
new_fields_to_selfcal.remove(fid)

if fid not in new_fields_to_selfcal:
# We need to update all the EBs, not just the one that failed.
for v in selfcal_library[fid]['vislist']:
selfcal_library[fid][v][solint]['Pass'] = 'None'
if allow_gain_interpolation:
selfcal_library[fid][v][solint]['Fail_Reason'] = 'Interpolation beyond inf'
else:
selfcal_library[fid][v][solint]['Fail_Reason'] = 'Bad gaincal solutions'
selfcal_library[fid][vis][solint]['Pass'] = 'None'
if allow_gain_interpolation:
selfcal_library[fid][vis][solint]['Fail_Reason'] = 'Interpolation beyond inf'
else:
selfcal_library[fid][vis][solint]['Fail_Reason'] = 'Bad gaincal solutions'


tb.close()
elif selfcal_library['obstype'] == 'mosaic' and solint == "inf_EB":
## If an EB had no fields to gaincal on, remove all fields in that EB from being selfcal'd as there is no calibration available
## in this EB.
for vis in selfcal_library['vislist']:
if np.intersect1d(selfcal_library['sub-fields-to-gaincal'],\
#for vis in selfcal_library['vislist']:
if True:
if np.intersect1d(selfcal_library[vis]['sub-fields-to-gaincal'],\
list(selfcal_library['sub-fields-fid_map'][vis].keys())).size == 0:
for fid in np.intersect1d(new_fields_to_selfcal,list(selfcal_library['sub-fields-fid_map'][vis].keys())):
new_fields_to_selfcal.remove(fid)

selfcal_library[fid]['Stop_Reason'] = 'No viable calibrator fields for inf_EB in at least 1 EB'
for v in selfcal_library[fid]['vislist']:
selfcal_library[fid][v][solint]['Pass'] = 'None'
selfcal_library[fid][v][solint]['Fail_Reason'] = 'No viable inf_EB fields'
selfcal_library[fid][vis]['Stop_Reason'] = 'No viable calibrator fields for inf_EB in at least 1 EB'
selfcal_library[fid][vis][solint]['Pass'] = 'None'
selfcal_library[fid][vis][solint]['Fail_Reason'] = 'No viable inf_EB fields'

print("new_fields_to_selfcal", new_fields_to_selfcal)

return new_fields_to_selfcal

2 changes: 1 addition & 1 deletion auto_selfcal/original_ms_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def applycal_to_orig_MSes(selfcal_library='selfcal_library.pickle', write_only=T
for band in selfcal_library[target].keys():
if selfcal_library[target][band]['SC_success']:
for vis in selfcal_library[target][band]['vislist']:
solint=selfcal_library[target][band]['final_solint']
solint=selfcal_library[target][band][vis]['final_solint']
iteration=selfcal_library[target][band][vis][solint]['iteration']

# Write the line to the command log
Expand Down
Loading
Loading