From 3e76fd9ffd680e372f298fc1c4727d3c964b0ade Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 2 Apr 2026 14:15:42 -0300 Subject: [PATCH 1/5] WIP (ACORM): initial version of AC ORM measurement script - to abandon notebooks, standardize saving of ORMs for LOCO fittings --- bin/sirius-script-si-loco-measure-acorm.py | 293 +++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 bin/sirius-script-si-loco-measure-acorm.py diff --git a/bin/sirius-script-si-loco-measure-acorm.py b/bin/sirius-script-si-loco-measure-acorm.py new file mode 100644 index 0000000..e462e23 --- /dev/null +++ b/bin/sirius-script-si-loco-measure-acorm.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python-sirius +"""Script for running & analyzing AC ORM measurements for LOCO fittings.""" + +import signal +import sys +import time +from functools import partial +from threading import Lock + +import numpy as _np +from apsuite.commisslib.meas_ac_orm import ACORMParams, MeasACORM +from mathphys.functions import load + +MEAS_TIMEOUT = 6 * 60 # [s] +CONN_TIMEOUT = 15 # [s] + +lock_stop = Lock() + + +def _stop_now(meas_orm, signum, frame): + """.""" + _ = frame + if lock_stop.locked(): + print('There is another stop request running. Please wait a little.') + return + lock_stop.acquire() + + sname = signal.Signals(signum).name + tstamp = time.strftime('%Y-%m-%d %H:%M:%S') + print(f'{sname} received at {tstamp}') + sys.stdout.flush() + sys.stderr.flush() + meas_orm.stop() + print('Waiting measurement to stop smoothly') + if meas_orm.wait_measurement(60): + print('Measurement safely stopped.') + else: + print('Measurement did not stop within 60 seconds.') + lock_stop.release() + + +def configure(meas_orm, args): + """.""" + # only configuring parameters which differ from + # MeasACORM.params defaults or are changed by the flags of the script. + # TODO: review the class defaults. compare it to the last measrements. + meas_orm.params.ref_respmat_name = args.ref_respmat_name + meas_orm.params.correct_orbit_between_acqs = ( + args.correct_orbit_between_acqs + ) + + meas_orm.params.corrs_norm_kicks = True + meas_orm.params.corrs_ch_kick = 5.000 + meas_orm.params.corrs_cv_kick = 5.000 + meas_orm.params.corrs_dorb1ch = 40.000 + meas_orm.params.corrs_dorb1cv = 40.000 + + nrsecs = 1 + primes = meas_orm.params.find_primes(2 * 8 * nrsecs + 2, 3) + # TODO: do we still need to exclude frequencies close to 60 Hz even + # now without the PetraVII Cavity? + primes = _np.array(sorted(set(primes) - {59, 61})) + cv_freqs = primes[: 8 * nrsecs] + primes = _np.array(sorted(set(primes) - set(cv_freqs))) + ch_freqs = primes[: 6 * nrsecs] + + meas_orm.params.corrs_ch_freqs = ch_freqs + meas_orm.params.corrs_cv_freqs = cv_freqs + + meas_orm.params.rf_mode = 'Standard' + meas_orm.params.rf_step_kick = 75 / 2 + meas_orm.params.rf_step_delay = 0.2 + + +def check_configdb_entry(name, meas_orm, print_info=False): + """True if name is not a si_orbcorr_respm entry, False otherwise.""" + try: + info = meas_orm.configdb.get_config_info(name) + except Exception as e: + return True + if print_info: + print(f'An ORM with name "{name}" already exists in configDB ') + print('Info:') + for key, val in info.items(): + val = convert_timestamps(val) + print(f'\t{key}: {val}') + return False + + +def convert_timestamps(val): + """.""" + if isinstance(val, float): + return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(val)) + + elif isinstance(val, list): + return [convert_timestamps(v) for v in val] + return val + + +def check_previous_loco_input_data(name): + """.""" + try: + ln = name + '_loco_input_data.pickle' + _ = load(ln) + print( + f'There already is a LOCO input data file named {ln}. ' + ' Please, choose a different ORM name or delete/rename the ' + 'existing file. Exiting.' + ) + return True + except FileNotFoundError: + return False + + +def main(): + """Parse params, configure and run the AC ORM measurement.""" + import argparse as _argparse + + params = ACORMParams() + + parser = _argparse.ArgumentParser( + description='Measure AC ORM for LOCO fitting.' + ) + + parser.add_argument( + '-n', + '--name', + type=str, + default='acorm', + help='ORM nickname (without extension). Used for saving measurement ' + 'acquisitions data, LOCO input data and for saving the ORM to the ' + 'configDB (if --save2configdb is set). Defaults to "acorm".', + ) + + parser.add_argument( + '--print-setup', + action='store_true', + help='Print measurement setup (parameters) and try to connect to PVs.', + ) + + parser.add_argument( + '--run-meas', + action='store_true', + help='Run the measurement. If not set, the script will only attempt ' + 'to connect to PVs and print the measurement setup if ' + '--print-setup is set.', + ) + + parser.add_argument( + '--conn-timeout', + type=int, + default=CONN_TIMEOUT, + help='Time (in seconds) to wait for PVs to connect. Defaults to ' + f'{CONN_TIMEOUT} seconds.', + ) + + parser.add_argument( + '--meas-timeout', + type=int, + default=MEAS_TIMEOUT, + help='Time (in seconds) to wait for measurement to finish. Defaults ' + f'to {MEAS_TIMEOUT} seconds.', + ) + + parser.add_argument( + '--save-acq-data', + '--sa', + action='store_true', + default=False, + help='Save BPMs acquisition data (unprocessed data) to a pickle file ' + 'named _acq_data.pickle. This can be useful for investigating ' + 'issues w/ the measurement or for testing different data processing. ' + 'These files can be quite large (~1-2 GB) and are not required for ' + 'LOCO fitting. Defaults to False.', + ) + + parser.add_argument( + '--save2configdb', + action='store_true', + default=False, + help='Save the measured AC ORM to the configDB server. ' + 'Caution: this can overwrite existing ORMs with the same name! ' + 'make sure to choose a unique ORM name.', + ) + + parser.add_argument( + '--ref-respmat-name', + type=str, + default=params.ref_respmat_name, + help='Name of the reference ORM to be used during the AC ORM ' + 'measurement processing (determining scale factors and compare ' + 'evaluate measurement quality). Make sure to input a valid ' + 'name, existing in the machine database. Defaults to ' + f'"{params.ref_respmat_name}".', + ) + + parser.add_argument( + '--correct_orbit_between_acqs', + action='store_true', + default=params.correct_orbit_between_acqs, + help='Correct orbit between acquisitions. An ACORM measurment ' + 'consists of several BPMs acquisitions for each set of corrector ' + 'magnets excitations. If this flag is set, the orbit will be ' + 'corrected to SOFBs current reference orbit in between acquisitions' + f'Defaults to {params.correct_orbit_between_acqs}.', + ) + + args = parser.parse_args() + + name = args.name + + meas_orm = MeasACORM(isonline=True) + + if check_configdb_entry(args.ref_respmat_name, meas_orm): + print( + 'No reference respmat found with res name ' + args.ref_respmat_name + ) + print('Exiting.') + sys.exit(1) + + signal.signal(signal.SIGINT, partial(_stop_now, meas_orm)) + signal.signal(signal.SIGTERM, partial(_stop_now, meas_orm)) + + if check_previous_loco_input_data(name): + sys.exit(1) + + configure(meas_orm, args) + + print('Waiting PVs to connect...') + + if not meas_orm.wait_for_connection(CONN_TIMEOUT): + print('\tSome PVs did not connect! Disconnected PVs:\n') + for pvname in meas_orm.disconnected_pvnames: + print(f'\t{pvname}') + print('Exiting.') + sys.exit(1) + + print('\tDone!') + + print('Measurement configured.') + + if args.print_setup: + print(meas_orm.params) + + if not args.run_meas: + print( + 'Exiting.' + + 'If you want to run the measurement, use the --run-meas flag.' + ) + sys.exit(0) + + print(80 * '#') + print('Starting AC ORM measurement.') + + meas_orm.start() + meas_orm.wait_measurement(MEAS_TIMEOUT) + meas_orm.process_data() + + print('Measurement finished and processed.') + + print(f'\tFinished ok? {meas_orm.check_measurement_finished_ok()}') + print(f'\tGood quality? {meas_orm.check_measurement_quality()}') + + if args.save_acq_data: + print('Saving acquisitions data...') + meas_orm.save_data(name + '_acq_data.pickle') + print( + 'Acquisitions data (unprocessed) saved to ' + + f'{name}_acq_data.pickle' + ) + + print('Saving LOCO input data...') + meas_orm.save_loco_input_data(name + '_loco_input_data.pickle') + print(f'LOCO input data saved to {name}_loco_input_data.pickle') + print( + 'Use `sirius-script-si-loco-run_fitting.py` to fit model to this data' + ) + + if args.save2configdb: + if check_configdb_entry(name, meas_orm, True): + print('Saving measured AC ORM to configDB...') + meas_orm.save_respmat_to_configdb(name) + print('Done!') + else: + print('Data not saved to configDB!') + + # meas_respmat = meas_orm.build_respmat() + # ref_respmat = meas_orm.get_ref_respmat() + # TODO: proceed with analysis and analysis report (similar to LOCO's) + + +if __name__ == '__main__': + main() From 717c91ec86bc7195954755d4fce005b9c50a938d Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 6 Apr 2026 14:55:15 -0300 Subject: [PATCH 2/5] ENH (ACORM): modularize code - less of a monolith, more modular script - not yet tested --- bin/sirius-script-si-loco-measure-acorm.py | 286 +++++++++++---------- 1 file changed, 147 insertions(+), 139 deletions(-) diff --git a/bin/sirius-script-si-loco-measure-acorm.py b/bin/sirius-script-si-loco-measure-acorm.py index e462e23..f9bbe32 100644 --- a/bin/sirius-script-si-loco-measure-acorm.py +++ b/bin/sirius-script-si-loco-measure-acorm.py @@ -1,18 +1,19 @@ #!/usr/bin/env python-sirius -"""Script for running & analyzing AC ORM measurements for LOCO fittings.""" +"""Run and analyze AC ORM measurements for LOCO.""" +import argparse import signal import sys import time from functools import partial from threading import Lock -import numpy as _np +import numpy as np from apsuite.commisslib.meas_ac_orm import ACORMParams, MeasACORM from mathphys.functions import load -MEAS_TIMEOUT = 6 * 60 # [s] -CONN_TIMEOUT = 15 # [s] +MEAS_TIMEOUT_DEFAULT = 6 * 60 # [s] +CONN_TIMEOUT_DEFAULT = 15 # [s] lock_stop = Lock() @@ -39,97 +40,22 @@ def _stop_now(meas_orm, signum, frame): lock_stop.release() -def configure(meas_orm, args): +def parse_args(): """.""" - # only configuring parameters which differ from - # MeasACORM.params defaults or are changed by the flags of the script. - # TODO: review the class defaults. compare it to the last measrements. - meas_orm.params.ref_respmat_name = args.ref_respmat_name - meas_orm.params.correct_orbit_between_acqs = ( - args.correct_orbit_between_acqs - ) - - meas_orm.params.corrs_norm_kicks = True - meas_orm.params.corrs_ch_kick = 5.000 - meas_orm.params.corrs_cv_kick = 5.000 - meas_orm.params.corrs_dorb1ch = 40.000 - meas_orm.params.corrs_dorb1cv = 40.000 - - nrsecs = 1 - primes = meas_orm.params.find_primes(2 * 8 * nrsecs + 2, 3) - # TODO: do we still need to exclude frequencies close to 60 Hz even - # now without the PetraVII Cavity? - primes = _np.array(sorted(set(primes) - {59, 61})) - cv_freqs = primes[: 8 * nrsecs] - primes = _np.array(sorted(set(primes) - set(cv_freqs))) - ch_freqs = primes[: 6 * nrsecs] - - meas_orm.params.corrs_ch_freqs = ch_freqs - meas_orm.params.corrs_cv_freqs = cv_freqs - - meas_orm.params.rf_mode = 'Standard' - meas_orm.params.rf_step_kick = 75 / 2 - meas_orm.params.rf_step_delay = 0.2 - - -def check_configdb_entry(name, meas_orm, print_info=False): - """True if name is not a si_orbcorr_respm entry, False otherwise.""" - try: - info = meas_orm.configdb.get_config_info(name) - except Exception as e: - return True - if print_info: - print(f'An ORM with name "{name}" already exists in configDB ') - print('Info:') - for key, val in info.items(): - val = convert_timestamps(val) - print(f'\t{key}: {val}') - return False - - -def convert_timestamps(val): - """.""" - if isinstance(val, float): - return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(val)) - - elif isinstance(val, list): - return [convert_timestamps(v) for v in val] - return val - - -def check_previous_loco_input_data(name): - """.""" - try: - ln = name + '_loco_input_data.pickle' - _ = load(ln) - print( - f'There already is a LOCO input data file named {ln}. ' - ' Please, choose a different ORM name or delete/rename the ' - 'existing file. Exiting.' - ) - return True - except FileNotFoundError: - return False - - -def main(): - """Parse params, configure and run the AC ORM measurement.""" - import argparse as _argparse - params = ACORMParams() - parser = _argparse.ArgumentParser( - description='Measure AC ORM for LOCO fitting.' + parser = argparse.ArgumentParser( + description='Measure AC ORM for LOCO fitting' ) parser.add_argument( '-n', '--name', type=str, - default='acorm', - help='ORM nickname (without extension). Used for saving measurement ' + default='acorm_' + time.strftime('%Y-%m-%d-%H-%M'), + help='ORM nickname (without extension) used for saving measurement ' 'acquisitions data, LOCO input data and for saving the ORM to the ' - 'configDB (if --save2configdb is set). Defaults to "acorm".', + 'configDB. Defaults to "acorm_".', ) parser.add_argument( @@ -149,17 +75,17 @@ def main(): parser.add_argument( '--conn-timeout', type=int, - default=CONN_TIMEOUT, + default=CONN_TIMEOUT_DEFAULT, help='Time (in seconds) to wait for PVs to connect. Defaults to ' - f'{CONN_TIMEOUT} seconds.', + f'{CONN_TIMEOUT_DEFAULT} seconds.', ) parser.add_argument( '--meas-timeout', type=int, - default=MEAS_TIMEOUT, + default=MEAS_TIMEOUT_DEFAULT, help='Time (in seconds) to wait for measurement to finish. Defaults ' - f'to {MEAS_TIMEOUT} seconds.', + f'to {MEAS_TIMEOUT_DEFAULT} seconds.', ) parser.add_argument( @@ -205,89 +131,171 @@ def main(): f'Defaults to {params.correct_orbit_between_acqs}.', ) - args = parser.parse_args() + return parser.parse_args() - name = args.name - meas_orm = MeasACORM(isonline=True) +def configure_measurement(meas_orm, args): + """.""" + # only configuring parameters which differ from + # TODO: review the class defaults. compare it to the last measrements. + # MeasACORM.params defaults or are changed by the flags of the script. + + p = meas_orm.params + p.ref_respmat_name = args.ref_respmat_name + p.correct_orbit_between_acqs = args.correct_orbit_between_acqs + + p.corrs_norm_kicks = True + p.corrs_ch_kick = 5.0 + p.corrs_cv_kick = 5.0 + p.corrs_dorb1ch = 40.0 + p.corrs_dorb1cv = 40.0 + + nrsecs = 1 + primes = p.find_primes(2 * 8 * nrsecs + 2, 3) + # TODO: do we still need to exclude frequencies close to 60 Hz even + # now without the PetraVII Cavity? + primes = np.array(sorted(set(primes) - {59, 61})) + cv_freqs = primes[: 8 * nrsecs] + primes = np.array(sorted(set(primes) - set(cv_freqs))) + ch_freqs = primes[: 6 * nrsecs] + + p.corrs_ch_freqs = ch_freqs + p.corrs_cv_freqs = cv_freqs - if check_configdb_entry(args.ref_respmat_name, meas_orm): + p.rf_mode = 'Standard' + p.rf_step_kick = 75 / 2 + p.rf_step_delay = 0.2 + + +def config_exists(meas_orm, name, verbose=False): + """.""" + try: + info = meas_orm.configdb.get_config_info(name) + except Exception as e: + print(f'ConfigDB error: {e}') + return False + + if verbose: + print(f'An ORM w/ name "{name}" already exists in confgDB:') + for k, v in info.items(): + print(f'\t{k}: {convert_timestamps(v)}') + return True + + +def convert_timestamps(val): + """.""" + if isinstance(val, float): + return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(val)) + if isinstance(val, list): + return [convert_timestamps(v) for v in val] + return val + + +def loco_input_exists(name): + """.""" + fname = f'{name}_loco_input_data.pickle' + try: + load(fname) print( - 'No reference respmat found with res name ' + args.ref_respmat_name + f'A LOCO input data file named {fname} already exists. ' + + 'Please, choose a different ORM name or delete/rename the ' + 'existing file.' ) - print('Exiting.') - sys.exit(1) + return True + except FileNotFoundError: + return False - signal.signal(signal.SIGINT, partial(_stop_now, meas_orm)) - signal.signal(signal.SIGTERM, partial(_stop_now, meas_orm)) - if check_previous_loco_input_data(name): - sys.exit(1) +def ensure_connection(meas_orm, timeout): + """.""" + print('Connecting PVs...') + if meas_orm.wait_for_connection(timeout): + print('Connected.') + return True + + print('Connection failed. Missing PVs:') + for pv in meas_orm.disconnected_pvnames: + print(f'\t{pv}') + return False + - configure(meas_orm, args) +def run_measurement(meas_orm, timeout): + """.""" + meas_orm.start() + + if not meas_orm.wait_measurement(timeout): + print('Measurement timeout.') + return False - print('Waiting PVs to connect...') + return True - if not meas_orm.wait_for_connection(CONN_TIMEOUT): - print('\tSome PVs did not connect! Disconnected PVs:\n') - for pvname in meas_orm.disconnected_pvnames: - print(f'\t{pvname}') - print('Exiting.') + +def main(): + """.""" + args = parse_args() + meas_orm = MeasACORM(isonline=True) + + if not config_exists(meas_orm, args.ref_respmat_name): + print('Reference response matrix not found.') + print( + 'Please, make sure the name passed to `--ref-respmat-name`' + + ' is valid.' + ) sys.exit(1) - print('\tDone!') + if loco_input_exists(args.name): + sys.exit(1) - print('Measurement configured.') + configure_measurement(meas_orm, args) + + signal.signal(signal.SIGINT, partial(_stop_now, meas_orm)) + signal.signal(signal.SIGTERM, partial(_stop_now, meas_orm)) + + if not ensure_connection(meas_orm, args.conn_timeout): + sys.exit(1) if args.print_setup: print(meas_orm.params) if not args.run_meas: - print( - 'Exiting.' - + 'If you want to run the measurement, use the --run-meas flag.' - ) - sys.exit(0) + print('Dry run. Use `--run-meas` to execute.') + return - print(80 * '#') - print('Starting AC ORM measurement.') + print('#' * 80) + print('Starting measurement...') - meas_orm.start() - meas_orm.wait_measurement(MEAS_TIMEOUT) - meas_orm.process_data() + if not run_measurement(meas_orm, args.meas_timeout): + sys.exit(1) - print('Measurement finished and processed.') + meas_orm.process_data() - print(f'\tFinished ok? {meas_orm.check_measurement_finished_ok()}') - print(f'\tGood quality? {meas_orm.check_measurement_quality()}') + print('Measurement finished & processed.') + print(f'\tFinished OK? {meas_orm.check_measurement_finished_ok()}') + print(f'\tQuality? {meas_orm.check_measurement_quality()}') if args.save_acq_data: print('Saving acquisitions data...') - meas_orm.save_data(name + '_acq_data.pickle') - print( - 'Acquisitions data (unprocessed) saved to ' - + f'{name}_acq_data.pickle' - ) + fname = f'{args.name}_acq_data.pickle' + meas_orm.save_data(fname) + print(f'Saved: {fname}') print('Saving LOCO input data...') - meas_orm.save_loco_input_data(name + '_loco_input_data.pickle') - print(f'LOCO input data saved to {name}_loco_input_data.pickle') + loco_fname = f'{args.name}_loco_input_data.pickle' + meas_orm.save_loco_input_data(loco_fname) + print(f'Saved: {loco_fname}') print( - 'Use `sirius-script-si-loco-run_fitting.py` to fit model to this data' + 'Use `sirius-script-si-loco-run-fitting.py` to fit model to this data.' ) if args.save2configdb: - if check_configdb_entry(name, meas_orm, True): - print('Saving measured AC ORM to configDB...') - meas_orm.save_respmat_to_configdb(name) - print('Done!') + if config_exists(meas_orm, args.name, verbose=True): + print('Aborting save.') else: - print('Data not saved to configDB!') - - # meas_respmat = meas_orm.build_respmat() - # ref_respmat = meas_orm.get_ref_respmat() - # TODO: proceed with analysis and analysis report (similar to LOCO's) + print('Saving measured AC ORM to configDB...') + meas_orm.save_respmat_to_configdb(args.name) + print('Saved.') + # TODO: analysis & analysis report if __name__ == '__main__': main() From 18b89a3957c93d196a391bd495506d1e357a8a0a Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 10 Apr 2026 16:23:59 -0300 Subject: [PATCH 3/5] ENH (ACORM): add ORM report - adds the `ORMReport` dependency, which is responsible for producing the ORM measurement report - additional args: folder to output files, and whether to generate the report and clean the png files used for the report --- bin/sirius-script-si-loco-measure-acorm.py | 79 ++++++++++++++++++---- 1 file changed, 66 insertions(+), 13 deletions(-) mode change 100644 => 100755 bin/sirius-script-si-loco-measure-acorm.py diff --git a/bin/sirius-script-si-loco-measure-acorm.py b/bin/sirius-script-si-loco-measure-acorm.py old mode 100644 new mode 100755 index f9bbe32..63bf447 --- a/bin/sirius-script-si-loco-measure-acorm.py +++ b/bin/sirius-script-si-loco-measure-acorm.py @@ -3,13 +3,14 @@ import argparse import signal +import os import sys import time from functools import partial from threading import Lock import numpy as np -from apsuite.commisslib.meas_ac_orm import ACORMParams, MeasACORM +from apsuite.commisslib.meas_ac_orm import ACORMParams, MeasACORM, ORMReport from mathphys.functions import load MEAS_TIMEOUT_DEFAULT = 6 * 60 # [s] @@ -49,13 +50,21 @@ def parse_args(): ) parser.add_argument( - '-n', - '--name', + 'orm_name', type=str, - default='acorm_' + time.strftime('%Y-%m-%d-%H-%M'), - help='ORM nickname (without extension) used for saving measurement ' - 'acquisitions data, LOCO input data and for saving the ORM to the ' - 'configDB. Defaults to "acorm_".', + help='ORM nickname or keyword (without extension). Used for saving ' + 'the measurement acquisitions data, the LOCO input data and saving ' + 'the ORM to the configDB. ' + ) + + parser.add_argument( + '-f', + '--folder', + type=str, + default=os.getcwd(), + help='Path to the folder for output files (acquisition, LOCO input, ' + 'figures of the analysis and the measurement report). ' + 'Default is the current directory.', ) parser.add_argument( @@ -67,9 +76,9 @@ def parse_args(): parser.add_argument( '--run-meas', action='store_true', - help='Run the measurement. If not set, the script will only attempt ' - 'to connect to PVs and print the measurement setup if ' - '--print-setup is set.', + help='Run the measurement. If not set, the script will do a dry-run: ' + 'will only connect to PVs and print the measurement setup (if ' + '--print-setup is set).', ) parser.add_argument( @@ -131,6 +140,21 @@ def parse_args(): f'Defaults to {params.correct_orbit_between_acqs}.', ) + parser.add_argument( + '-r', + '--report', + action='store_true', + help='Create report. Default False, set to True if flag is given.' + ) + + parser.add_argument( + '-c', + '--cleanup', + action='store_true', + help='Cleanup .png files. ' + 'Default: False, set to True if flag is given.', + ) + return parser.parse_args() @@ -230,6 +254,24 @@ def run_measurement(meas_orm, timeout): return True +def cleanup_png_files(folder): + """Cleans up generated PNG plot files.""" + lst = [ + 'scale_factors', + 'correlation', + 'least_corr_ch', + 'least_corr_cv', + 'best_corr_ch', + 'best_corr_cv', + 'rf_column', + ] + for name in lst: + try: + os.remove(os.path.join(folder, name + '.png')) + except FileNotFoundError: + pass # silently ignore missing files + + def main(): """.""" args = parse_args() @@ -252,6 +294,7 @@ def main(): signal.signal(signal.SIGTERM, partial(_stop_now, meas_orm)) if not ensure_connection(meas_orm, args.conn_timeout): + print('Exiting.') sys.exit(1) if args.print_setup: @@ -273,15 +316,17 @@ def main(): print(f'\tFinished OK? {meas_orm.check_measurement_finished_ok()}') print(f'\tQuality? {meas_orm.check_measurement_quality()}') + folder = args.folder.strip('/') + '/' + if args.save_acq_data: print('Saving acquisitions data...') fname = f'{args.name}_acq_data.pickle' - meas_orm.save_data(fname) + meas_orm.save_data(folder + fname) print(f'Saved: {fname}') print('Saving LOCO input data...') loco_fname = f'{args.name}_loco_input_data.pickle' - meas_orm.save_loco_input_data(loco_fname) + meas_orm.save_loco_input_data(folder + loco_fname) print(f'Saved: {loco_fname}') print( 'Use `sirius-script-si-loco-run-fitting.py` to fit model to this data.' @@ -295,7 +340,15 @@ def main(): meas_orm.save_respmat_to_configdb(args.name) print('Saved.') - # TODO: analysis & analysis report + if args.report: + print('Creating report...') + report = ORMReport() + report.create_report(meas_orm=meas_orm, folder=folder) + + if args.cleanup: + cleanup_png_files(folder) + print('All .png files have been deleted.') + if __name__ == '__main__': main() From 62ef5efe006a49957d4a336d1e13aa3a546a172a Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 10 Apr 2026 16:24:31 -0300 Subject: [PATCH 4/5] ENH (ACORM) add the acorm measurement script to makefile --- bin/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/Makefile b/bin/Makefile index 0e8eff7..c3c7819 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -14,6 +14,7 @@ GENERALSCRIPTS = \ sirius-script-ps-wfmupdateauto-off.py \ sirius-script-clientarch-checkpv.py \ sirius-script-si-bpm-acquire-triggered-data.py \ + sirius-script-si-loco-measure-acorm.py \ sirius-script-si-loco-run-fitting.py \ sirius-script-si-loco-set-strengths.py \ sirius-script-si-bba-measure.py \ @@ -27,7 +28,7 @@ REPOSSCRIPTS = \ sirius-script-repos-install-update.bash \ sirius-script-repos-install.bash \ sirius-script-repos-deletetags.bash \ - sirius-script-repos-deploytag.bash + sirius-script-repos-deploytag.bash \ # sirius-script-deploy-tag.bash BBBSCRIPTS = \ From f2500b22ce83e8ec14ee488934020d6bb7efbb0e Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 10 Apr 2026 16:33:01 -0300 Subject: [PATCH 5/5] MNT (ACORM): remove comment about 60 Hz harmonics --- bin/sirius-script-si-loco-measure-acorm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/sirius-script-si-loco-measure-acorm.py b/bin/sirius-script-si-loco-measure-acorm.py index 63bf447..710ac97 100755 --- a/bin/sirius-script-si-loco-measure-acorm.py +++ b/bin/sirius-script-si-loco-measure-acorm.py @@ -176,8 +176,6 @@ def configure_measurement(meas_orm, args): nrsecs = 1 primes = p.find_primes(2 * 8 * nrsecs + 2, 3) - # TODO: do we still need to exclude frequencies close to 60 Hz even - # now without the PetraVII Cavity? primes = np.array(sorted(set(primes) - {59, 61})) cv_freqs = primes[: 8 * nrsecs] primes = np.array(sorted(set(primes) - set(cv_freqs)))