-
Notifications
You must be signed in to change notification settings - Fork 1
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
add time_constant function #179
base: main
Are you sure you want to change the base?
Conversation
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.
I comment in terms of hwp controls for this type of measurements that spins up and down hwp.
-
I suggest streaming separately for forward spin and backward spin. This is because hwp solution pipeline assumes constant rotation direction within the data range. It requires more work to analyze it if both forward and reverse spin are included in the data range.
-
For the hwp rotation direction estimation, you can just use.
apply_hwp_angle_model(tod, on_sign_ambiguous='offcenter')
. It might be possible to simplify functions. The hwp rotation direction estimation has to be different from cmb observations bacausehwp_solution.pid_direction
is not reliable for spin down measurement. This is because commanded spin direction and actual spin direction is different when hwp is spinning down.hwp_solution.offcenter_direction
will be the robust rotation direction estimator for this hwp spin down up measurements.
if stepwise_before: | ||
rotate(False) | ||
# Stop the HWP | ||
_stop_hwp_with_wiregrid() |
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.
I suggest to add following here, to stream separately for forward and backward
run.smurf.stream('off')
run.smurf.stream('on')
Thanks Kyohei!
|
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.
I add comments around insert() and eject().
src/sorunlib/wiregrid.py
Outdated
run.smurf.bias_step(tag=bs_tag, concurrent=True) | ||
|
||
# Insert the wiregrid | ||
insert() |
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.
Could you add detector streams during the insert() and eject(), and add sleep (5 sec?) before and after the insert()/eject()?
Sleep times have two purposes. One is to see the detector response with/without the wiregrid right before and after the insertion/ejection. The second is to wait for the wiregrid to be stable before the bias-step measurement.
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.
I added detector streams and sleep. In these streams, I used new tags, wg_inserting
and wg_ejecting
. The commit for these modification is here: f1e1157
src/sorunlib/wiregrid.py
Outdated
run.smurf.bias_step(tag=bs_tag, concurrent=True) | ||
|
||
# Eject the wiregrid | ||
eject() |
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.
Here, I want to add also detector stream ON --> sleep --> eject --> sleep.
I'm concerned about future automation of gl calibration. I will let you decide, but I don't see any disadvantage of splitting stream. If you split, you don't need to re-calculate hwp solution. |
53df2c2
to
f1e1157
Compare
for more information, see https://pre-commit.ci
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #179 +/- ##
=======================================
Coverage ? 84.15%
=======================================
Files ? 10
Lines ? 631
Branches ? 0
=======================================
Hits ? 531
Misses ? 100
Partials ? 0 ☔ View full report in Codecov by Sentry. |
Thanks, Kyohei and Daiki. |
OK, I'm fine if you don't mind recalculating the hwp angle. |
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.
Here's a first pass at a review from me. A couple general comments/comments:
- Please wrap lines to ~80 characters. I'm not super strict on the exact length, but there are some pretty long lines (100+) characters here. Try to be consistent with the existing code here.
- How often will this be run? Daily? Monthly? Once? I was a bit surprised to see the PR, thinking we had implemented the regular calibration in
wiregrid.calibrate()
already. - We need tests. I've been pretty meticulous to keep 100% coverage from the get-go in this repo.
sorunlib
is tricky because I often can't just interrupt daily operations to test some new functionality. Check out thetests/
directory to see existing tests. New tests for this will go intests/test_wiregrid.py
. There are instructions for running tests in the main README. Also, please merge in the latestmain
, there will be a new code coverage check that runs.
ls_status = resp.session['data']['fields']['limitswitch'] | ||
if (ls_status['LSR1'] == 1 or ls_status['LSL1'] == 1) and not (ls_status['LSR2'] == 1 and ls_status['LSL2'] == 1): | ||
position = 'outside' | ||
elif (ls_status['LSR2'] == 1 or ls_status['LSL2'] == 1) and not (ls_status['LSR1'] == 1 or ls_status['LSL1'] == 1): | ||
position = 'inside' | ||
else: | ||
raise RuntimeError("The wiregrid position is unknown. The limitswitch response is like this:\n" + | ||
"LSR1: {}\n".format('ON' if ls_status['LSR1'] == 1 else 'OFF') | ||
+ "LSL1: {}\n".format('ON' if ls_status['LSL1'] == 1 else 'OFF') | ||
+ "LSR2: {}\n".format('ON' if ls_status['LSR2'] == 1 else 'OFF') | ||
+ "LSL2: {}\n".format('ON' if ls_status['LSL2'] == 1 else 'OFF') | ||
+ "Aborting...") |
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.
I've wondered if there was a method for determining whether the wiregrid was inserted or not for a while now. It would be better to put this logic into the Agent itself, within the acq
process' session.data
. Then here you would only need to check resp.session['data']['fields']['position']
. This also exposes the wiregrid state for other clients, such as ocs-web.
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.
I agree with you. I created the PR to implement the position data in session.data
.
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.
Great, I just reviewed that. Once it's merged we should drop the code here and use the session.data
.
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.
Alright, now that simonsobs/socs#794 is merged, let's drop this here and use the new session.data
(along with existing timestamp.)
raise RuntimeError("The wiregrid position is unknown. The limitswitch response is like this:\n" + | ||
"LSR1: {}\n".format('ON' if ls_status['LSR1'] == 1 else 'OFF') |
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.
If this stays here for the moment...pre-commit is complaining about this particular line. Move the +
down from line 211 to the start of line 212, like you have the rest of the lines starting with +
.
else: | ||
raise RuntimeError("Unknown wiregrid position. Aborting...") |
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.
_check_wiregrid_position()
only ever returns 'outside' or 'inside', so this code path will never execute.
# Check the initial HWP direction | ||
if initial_hwp_direction not in ['forward', 'backward']: | ||
raise RuntimeError("Initial HWP direction should be either 'forward' or 'backward'. Aborting...") | ||
current_hwp_direction = initial_hwp_direction |
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 must be able to be determined automatically, no? I would think from the monitor process' session.data
, from 'hwp_freq'.
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.
I asked the HWP team about how to know its current spin direction in a robust and fast way, but I was told there is no way. The scheduler can remember the last command to set the direction (the arugment in run.hwp.set_freq()
) and whether it was finished successful, so the scheduler can feed its information into the time_constant()
function. I thought this is safer than reading the session.data
. Does this seem overly verbose?
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.
'direction' in session.data of pid controller agent might be good for initial direction? This value is not reliable when we spin down hwp, or when hwp is stopped, but it is reliable when hwp is spinning stablly.
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.
For now, I assumed the scheduler knows the HWP spin direction but this is also under the condition which the HWP is already spinning. Using 'direction' would be more simple than now. I will modify. Thanks Kyohei!
_check_motor_on() | ||
_check_telescope_position(elevation_check=True, boresight_check=False) | ||
|
||
if _check_zenith: |
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.
_check_zenith()
is a function call, this is missing the parentheses.
rotate(continuous=True, duration=10) | ||
|
||
# Bias step (the wire grid is off the window) | ||
bs_tag = f'biasstep, wg_time_constant, wg_ejected, hwp_2hz_{current_hwp_direction}' + el_tag |
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.
A few comments on these tags:
- Do we need a 'biasstep' tag when taking a bias step? I'll admit I don't know how these tags are used downstream, but is the operation not implicit?
- The ideal state might be wiregrid ejected and HWP rotating at 2Hz, but that isn't actually checked until
_reverse_hwp_with_wiregrid()
is called later on. I would want to verify those before tagging a bias step with them. My recommendation is to add them to the checks above, at the start of the method.
# Check the wiregrid position | ||
position = _check_wiregrid_position() |
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.
The checks in both _stop_hwp_with_wiregrid()
and _spin_hwp_with_wiregrid()
seem like are duplicating the check, and as a result making the functions more complicated than they need to be. They're only used in _reverse_hwp_with_wiregrid()
, which is only called after insert()
. If insert()
fails to insert the wiregrid it raises and the schedule with exit.
If you still want to check the wiregrid is inserted, I'd say do the check in _reverse_hwp_with_wiregrid()
before doing anything else. You can then assume its inserted in these other two functions, and they simplify down to:
def _stop_hwp():
"""Stop the HWP."""
print("Starting to stop the HWP.")
run.hwp.stop(active=True)
print("The HWP stopped successfully.")
def _spin_hwp(target_hwp_direction):
"""Spin the HWP to the target direction at 2Hz.
Args:
target_hwp_direction (str): Target HWP direction, 'forward' or 'backward'.
"""
if target_hwp_direction == 'forward':
print("Starting to spin up the HWP in forward.")
run.hwp.set_freq(freq=2.0)
print("The HWP is spinning at 2Hz in forward successfully.")
elif target_hwp_direction == 'backward':
print("Starting to spin up the HWP in backward.")
run.hwp.set_freq(freq=-2.0)
print("The HWP is spinning at 2Hz in backward successfully.")
if current_hwp_direction == 'forward': | ||
target_hwp_direction = 'backward' | ||
elif current_hwp_direction == 'backward': | ||
target_hwp_direction = 'forward' |
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.
I want to make sure we get this convention correct. The HWP supervisor agent has an argument called --forward-dir
that defines 'forward' to be clockwise or counter-clockwise, which seems to imply to me this isn't really a fixed direction. Is there some document about what our convention should be?
(I tried to avoid this question myself when writing hwp.set_freq()
, but it seems I can't escape it.)
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.
I found the confluence page about the rotation direction definition: CHWP main page -- Rotation direction definition. The cw/ccw seems to correspond to the PID value depending on each satp and the PID corresponds to 'forward' or 'reverse' not depending on the satp. We should pay attention which physical direction the 'forward' and 'reverse' mean - cw or ccw. This document uses 'reverse' instead of 'backward'.
Also, I found the 'forwards' and 'backwards' (not 'reverse') in the observation plans on the confluence. I guess a lot of people may make the 'forwards' correspond to the plus frequency like run.hwp.set_freq(freq=+2)
and 'backwards' to the minus.
It may be good time to integrate the convention.
Thanks Brian! Sorry for the late reply and the lack of explanation. I'm replying about some discussion points.
|
I added some APIs for a time constant measurement with the wire grid and the HWP into the
wiregrid.py
.Here is the added functions and its explanation:
_check_wiregrid_position()
_stop_hwp_with_wiregrid()
_spin_hwp_with_wiregrid(target_hwp_direction)
target_hwp_direction
.target_hwp_direction
is bool argument,'forward'
or'backward'
._reverse_hwp_with_wiregrid(initial_hwp_direction, streaming=False, stepwise_before=False, stepwise_after=False)
initial_hwp_direction
using_stop_hwp_with_wiregrid()
and_spin_hwp_with_wiregrid(target_hwp_direction)
stepwise_before
andstepwise_after
are to identify whether performing them or not.time_constant(initial_hwp_direction, stepwise_first=True, stepwise_last=True, stepwise_mid=False, repeat=1)
repeat
, and ejects the wire grid.Any questions and comments are welcome.