From bc85b8e5eb216b2532e6d65df24d69fe39176df7 Mon Sep 17 00:00:00 2001 From: mmccrackan Date: Fri, 21 Aug 2026 11:43:45 -0400 Subject: [PATCH 1/2] add sine_el_nod --- src/sorunlib/seq.py | 46 +++++++++++++++++++++++++++++++++++++-------- tests/test_seq.py | 15 +++++++++++---- tests/util.py | 5 +++++ 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/sorunlib/seq.py b/src/sorunlib/seq.py index 7c04081..c344dd8 100644 --- a/src/sorunlib/seq.py +++ b/src/sorunlib/seq.py @@ -11,16 +11,17 @@ @protect_shutdown -def _stop_scan(): +def _stop_scan(scan): acu = run.CLIENTS['acu'] print("Stopping scan.") stop_smurfs() - # Stop motion - acu.generate_scan.stop() + scan.stop() + print("Waiting for telescope motion to stop.") - resp = acu.generate_scan.wait(timeout=OP_TIMEOUT) + resp = scan.wait(timeout=OP_TIMEOUT) + check_response(acu, resp) print("Scan finished.") @@ -100,11 +101,11 @@ def scan(description, stop_time, width, az_drift=0, scan_type=1, el_amp=None, # Wait until stop time monitor_process(acu, 'generate_scan', stop_time) finally: - _stop_scan() + _stop_scan(acu.generate_scan) -def el_nod(el1, el2, num=5, pause=5): - """Perform a set of elevation nods. +def step_el_nod(el1, el2, num=5, pause=5): + """Perform a set of step-wise elevation nods. Elevation nods will be peformed at the current azimuth, and will start from and return to the current elevation. The nod first moves to ``el1``, @@ -123,7 +124,7 @@ def el_nod(el1, el2, num=5, pause=5): try: # Enable SMuRF streams - run.smurf.stream('on', subtype='cal', tag='el_nods') + run.smurf.stream('on', subtype='cal', tag='step_el_nods') # Grab current telescope position resp = acu.monitor.status() @@ -141,3 +142,32 @@ def el_nod(el1, el2, num=5, pause=5): run.acu.move_to(az=init_az, el=init_el) finally: stop_smurfs() + + +def sine_el_nod(el_depth, num_nods=None, **kwargs): + """Perform a set of sinusoidal elevation nods. + + Elevation nods will be peformed at the current azimuth, and will start from + and return to the current elevation. The nod will move between the current + elevation and +/- el_depth depending on if el_depth is positive or negative. + + Args: + el_depth (float): The number of degrees from the current el to nod to. + Can be negative. + num_nods (int or None): Number of nods to perform. If not None, limits + the nods to the specified number of sinusoidal nods. The process will + exit without error once that has completed. + """ + acu = run.CLIENTS['acu'] + + try: + # Enable SMuRF streams + run.smurf.stream('on', subtype='cal', tag='sine_el_nods') + + # Start telescope motion + resp = acu.generate_el_nod.start(el_depth=el_depth, + num_nods=num_nods) + + check_started(acu, resp) + finally: + _stop_scan(acu.generate_el_nod) diff --git a/tests/test_seq.py b/tests/test_seq.py index d09bf05..25149e9 100644 --- a/tests/test_seq.py +++ b/tests/test_seq.py @@ -99,7 +99,7 @@ def test_scan_failed_smurfs_on_shutdown(patch_clients): seq.run.CLIENTS['smurf'][1].stream.wait.side_effect = [mocked_response] seq.run.CLIENTS['smurf'][2].stream.wait.side_effect = [mocked_response] - seq._stop_scan() + seq._stop_scan(seq.run.CLIENTS['acu'].generate_scan) seq.run.CLIENTS['acu'].generate_scan.wait.assert_called() @@ -125,15 +125,15 @@ def test_scan_timeout_on_wait_to_stop_streams(patch_clients): # other keys in .session: op_code, degraded, data print(mock_reply) - seq._stop_scan() + seq._stop_scan(seq.run.CLIENTS['acu'].generate_scan) # We dropped the one that timed out assert len(seq.run.CLIENTS['smurf']) == 2 @patch('sorunlib.seq.time.sleep', MagicMock()) -def test_el_nod(patch_clients): +def test_step_el_nod(patch_clients): sorunlib.acu.move_to(az=180, el=50) - seq.el_nod(el1=40, el2=60) + seq.step_el_nod(el1=40, el2=60) # Calls will be repeated, but these three are representative of the el nod calls = [call(az=180, el=50), @@ -143,3 +143,10 @@ def test_el_nod(patch_clients): # Move back to initial position seq.run.CLIENTS['acu'].go_to.start.assert_called_with(az=180, el=50) + + +@patch('sorunlib._internal.time.sleep', MagicMock()) +def test_sine_el_nod(patch_clients): + for el_depth, num_nods in [(-0.5, None), (0.5, 1)]: + print(el_depth, num_nods) + seq.sine_el_nod(el_depth=el_depth, num_nods=num_nods) diff --git a/tests/util.py b/tests/util.py index 917aaa3..334fdd1 100644 --- a/tests/util.py +++ b/tests/util.py @@ -64,9 +64,14 @@ def _mock_acu_client(platform_type, az=180, el=50, boresight=0): session = create_session('generate_scan', status='running') reply = OCSReply(ocs.OK, 'msg', session.encoded()) + # scan acu.generate_scan = MagicMock() acu.generate_scan.start = MagicMock(return_value=reply) acu.generate_scan.status = MagicMock(return_value=reply) + # el nod + acu.generate_el_nod = MagicMock() + acu.generate_el_nod.start = MagicMock(return_value=reply) + acu.generate_el_nod.status = MagicMock(return_value=reply) return acu From 0356f0b7c216e24603a5ee71c94eb347855cc66d Mon Sep 17 00:00:00 2001 From: mmccrackan Date: Fri, 21 Aug 2026 11:44:49 -0400 Subject: [PATCH 2/2] pass kwargs --- src/sorunlib/seq.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sorunlib/seq.py b/src/sorunlib/seq.py index c344dd8..3d547fb 100644 --- a/src/sorunlib/seq.py +++ b/src/sorunlib/seq.py @@ -166,7 +166,8 @@ def sine_el_nod(el_depth, num_nods=None, **kwargs): # Start telescope motion resp = acu.generate_el_nod.start(el_depth=el_depth, - num_nods=num_nods) + num_nods=num_nods, + **kwargs) check_started(acu, resp) finally: