-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding AZSS correction per subscan #1065
base: master
Are you sure you want to change the base?
Conversation
…pdated noise logic to incorporate wrap_name from config\n\- added handling for 'fknee' and 'min_noise' in noise process based on user-defined thresholds
71891d7
to
6d888d9
Compare
…stimation from get_azss with flag subscan, TODO: azss subtraction per subscan still problematic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some inline comments.
proc_aman.flags.wrap("left_scan", aman.flags.left_scan) | ||
proc_aman.flags.wrap("right_scan", aman.flags.right_scan) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These have to exist in the axis manager first which means that FlagTurnarounds must be run first with the argument merge_lr = True
which is the default but can be overwritten. Not sure what the right path is here, perhaps if those don't exist then look in proc_aman for them and if they're not in either place then run the the get_turnaround_flags fn w/ merge_lr = True.
def calc_and_save(self, aman, proc_aman): | ||
if 'flags' not in proc_aman._fields: | ||
from sotodlib.core import FlagManager | ||
proc_aman.wrap('flags', FlagManager.for_tod(proc_aman)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically we don't wrap into proc_aman
directly in calc_and_save
instead we make one new AxisManager here (say bss_aman
--bad sub scan aman), wrap everything into that, and then pass that to save
(in the field typically called calc_aman
) and the save method wraps that into proc_aman
so that everything for this one preprocess step is in a single field in proc_aman. Here you wrap into proc_aman directly and also wrap ss_aman, and det_aman all into separate fields of proc_aman. Let's put everything in one aman and send just that one to save
.
subscan_stats_T = proc_aman[self.stats_name+"_T"] | ||
subscan_stats_Q = proc_aman[self.stats_name+"_Q"] | ||
subscan_stats_U = proc_aman[self.stats_name+"_U"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this requires that you run GetStats
three times wrapping in the same name but appending _T
, _Q
, and _U
to the end? That's a pretty specific prerequisite. Plus I think 90% of the time we are running GetStats
it'll be to achieve what BadSubscanFlags
is achieving (probably the other 10% of the time is getting some stats on the full TOD or PSD I guess). So why don't we instead check if self.stats_name+"_T"
exists and if not call tod_ops.flags.get_stats to get the info you need.
@@ -998,3 +1021,73 @@ def noise_fit_flags(aman, low_wn, high_wn, high_fk): | |||
return flag_valid_fk | |||
else: | |||
return None | |||
|
|||
def get_noisy_subscan_flags(aman, subscan_stats_T, subscan_stats_Q, subscan_stats_U, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this require T, Q, and U simultaneously makes this a very restrictive function (i.e. can only be run for the SATs not LAT and only after demodulation). Maybe we can make this take just one signal (i.e. signal = subscan_stats_T) and produce one dets x subscan boolean mask/RangesMatrix per signal then the preprocess method could choose how to combine these i.e. if there's one use 1, if there's >1 use logical and or logical or, etc. Thoughts?
raise ValueError(f"Flag name {name} already exists in aman.flags") | ||
aman.flags.wrap(name, noisy_subscan_flags) | ||
|
||
return noisy_subscan_flags, noisy_detector_flags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix newline
def process(self, aman, proc_aman): | ||
subtract = self.process_cfgs.get('subtract', False) | ||
if self.proc_aman_turnaround_info: | ||
_f = attergetter(self.proc_aman_turnaround_info) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: attrgetter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
if 'flags' not in proc_aman._fields: | ||
from sotodlib.core import FlagManager | ||
proc_aman.wrap('flags', FlagManager.for_tod(proc_aman)) | ||
proc_aman.flags.wrap("left_scan", aman.flags.left_scan) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left_scan and right_scan are already in the proc_aman after FlagTurnarounds, just top-level not under "flags". We probably want to agree on one place for them and just look there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nominally we shouldn't be wrapping anything into aman unless it's explicitly intended to be done in a process
step and then merged into proc_aman
in the calc_and_save
step. However the wrapping into aman is happening in calc_and_save
for FlagTurnarounds which should not be allowed. Long story short we should have all of the merge options hard coded false in the call to get_turnaround_flags
in calc_and_save
and any functions that look for info from TurnaroundFlags should look for it in proc_aman.
right_mask = turnaround_info.right_scan | ||
else: | ||
print("") | ||
print("HEREEEEEEE") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover debug statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor comments/questions on formatting and organization.
tod_ops.azss.get_azss(aman, azss_stats_name=self.azss_stats_name, | ||
turnaround_info=turnaround_info, | ||
merge_stats = True, merge_model=False, | ||
subtract_in_place=subtract, **self.calc_cfgs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably has already been discussed so feel free to ignore this, but this is using calc_cfgs
within process
which seems a bit counter-intuitive. I think it might be unavoidable given the way this needs to be run, but maybe these would make more sense as process_cfgs
since process
is always going to be run and will run first.
@@ -313,15 +435,31 @@ def subtract_azss(aman, signal='signal', azss_template_name='azss_model', | |||
else: | |||
raise TypeError("Signal must be None, str, or ndarray") | |||
|
|||
azss_stats, model_left, model_right = get_model_sig_tod(aman, azss_stats, az=None) | |||
|
|||
if in_place: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional, but I think this logic can be simplified by assigning to a temporary variable, i.e.:
if in_place:
if signal_name is None:
sig = signal
else:
sig = aman[signal_name]
else:
if signal_name is None:
sig = signal.copy()
else:
sig = aman[signal_name].copy()
As long as you use sig -= mask
, the non-copy ones should stay as references.
if self.azss_stats_name in proc_aman: | ||
if subtract: | ||
tod_ops.azss.subtract_azss(aman, proc_aman[self.azss_stats_name], | ||
signal = self.calc_cfgs.get('signal'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor formatting on signal = self.calc_cfgs.get('signal')
(space not needed).
else: | ||
tod_ops.azss.get_azss(aman, azss_stats_name=self.azss_stats_name, | ||
turnaround_info=turnaround_info, | ||
merge_stats = True, merge_model=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want merge_model
hardcoded to False
here (or elsewhere)? Is there any case where we'd want to be able to look at the model after fitting or interpolation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes because it wraps in a n_dets x n_samps copy of the data, we can use get_model_sig_tod
to reconstruct it from the info in azss_stats
if we need to look at it later.
else: | ||
tod_ops.azss.get_azss(aman, azss_stats_name=self.azss_stats_name, | ||
turnaround_info=turnaround_info, | ||
merge_stats = True, merge_model=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor formatting with unneeded spaces on merge_stats
.
Addresses remaining part of issue #1009, i.e. adding AZSS correction per subscan, as a continuation of the PR in #1064.