From c39a305793ab25e8e1fa5f94b80d2ff4749170a4 Mon Sep 17 00:00:00 2001 From: Zoom Beamline Date: Tue, 11 Aug 2026 15:26:44 +0100 Subject: [PATCH 1/3] Leading and trailing whitespace removed from sample position strings before validation --- technique/sans/instrument.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/technique/sans/instrument.py b/technique/sans/instrument.py index c427406..f74196a 100755 --- a/technique/sans/instrument.py +++ b/technique/sans/instrument.py @@ -87,6 +87,8 @@ def method_iterator(self): callable(getattr(self, method)): yield method + + def set_default_dae(self, mode=None, trans=False): """Set the default DAE mode for SANS or TRANS measurements. @@ -448,7 +450,7 @@ def detector_on(self, powered=None, delay=True): else: self._detector_turn_off(delay=delay) return self._detector_is_on() - + def check_move_pos(self, pos): """Check whether the position is valid and return True or False @@ -458,8 +460,9 @@ def check_move_pos(self, pos): The sample changer position """ - if pos.upper() not in [pos_name.upper() for pos_name in self._poslist]: - warning(f"Error in script, position {pos} does not exist") + stripped_pos = pos.strip() + if stripped_pos.upper() not in [pos_name.upper() for pos_name in self._poslist]: + warning(f"Error in script, position {stripped_pos} does not exist") return False return True @@ -663,6 +666,18 @@ def _setup(self, title="", position=None, thickness=1.0, trans=False, if period: gen.change_period(period) + + + def _validate_sample_position(self, position): + if position is None: + raise ValueError("Sample position cannot be None") + + stripped_pos = position.strip() + if stripped_pos not in self._poslist: + raise ValueError(f"Invalid sample position: '{stripped_pos}'. " + f"Available positions are: {', '.join(self._poslist)}") + return stripped_pos + def _set_sample_position(self, position, dls_sample_changer=False): if isinstance(position, str): if dls_sample_changer and self.check_move_pos_dls(position): @@ -670,7 +685,7 @@ def _set_sample_position(self, position, dls_sample_changer=False): self.changer_pos_dls = position elif self.check_move_pos(position): info(f"Moving to sample changer position {position}") - self.changer_pos = position + self.changer_pos = self._validate_sample_position(position) else: raise RuntimeError( f"Position {position} does not exist") @@ -697,7 +712,8 @@ def _measure(self, title="", position=None, thickness=1.0, trans=False, dae=None, aperture="", period=None, time=None, _custom=True, **kwargs): - self._setup(title=title, position=position, thickness=thickness, trans=trans, + valid_pos = self._validate_sample_position(position) + self._setup(title=title, position=valid_pos, thickness=thickness, trans=trans, dae=dae, aperture=aperture, period=period, _custom=_custom, **kwargs) @@ -705,7 +721,7 @@ def _measure(self, title="", position=None, thickness=1.0, trans=False, if time or self.sanitised_timings(kwargs): self._do_measure(title=title, time=time, **kwargs) - def do_sans(self, title="", pos=None, thickness=1.0, dae=None, + def do_sans(self, title="", pos=None, thickness=1.0, dae="event", aperture="", period=None, time=None, dls_sample_changer=False, **kwargs): """A wrapper around ``measure`` which ensures that the instrument is in sans mode before running the measurement if a title is given. @@ -736,7 +752,7 @@ def do_sans(self, title="", pos=None, thickness=1.0, dae=None, dae=dae, aperture=aperture, period=period, time=time, _custom=False, dls_sample_changer=dls_sample_changer, **kwargs) - def do_trans(self, title="", pos=None, thickness=1.0, dae=None, + def do_trans(self, title="", pos=None, thickness=1.0, dae="transmission", aperture="", period=None, time=None, dls_sample_changer=False, **kwargs): """A wrapper around ``measure`` which ensures that the instrument is in transition mode before running the measurement if a title is given. It ensures that the From d2db0e546b2b2b57d82fbe577c5143165d1d3d87 Mon Sep 17 00:00:00 2001 From: Dirk Honecker Date: Tue, 11 Aug 2026 16:05:39 +0100 Subject: [PATCH 2/3] adding default standard configurations, and helpers for polarised measurements --- instrument/zoom/sans.py | 630 ++++++++++++++++++++++++++++++++++++--- instrument/zoom/scans.py | 3 +- instrument/zoom/util.py | 56 +++- 3 files changed, 635 insertions(+), 54 deletions(-) diff --git a/instrument/zoom/sans.py b/instrument/zoom/sans.py index 05bf8ea..b6efe8d 100644 --- a/instrument/zoom/sans.py +++ b/instrument/zoom/sans.py @@ -1,18 +1,26 @@ """This is the instrument implementation for the Zoom beamline.""" -from logging import warning +from logging import info, warning from technique.sans.instrument import ScanningInstrument +from technique.sans.genie import gen +#from genie_python import genie as gen obsolete and not used by other instrument from technique.sans.util import dae_setter from general.scans.util import local_wrapper -from .util import flipper1 +from .util import flipper1, flipper_on, flipper_off +def sleep(seconds): + """Override the sleep function to use genie. + + We need this override to ensure that simulated runs are forced to + wait for real sleeps.""" + return gen.waitfor(seconds=seconds) class Zoom(ScanningInstrument): """This class handles the Zoom beamline, it is an extension of the Scanning instrument class.""" def __init__(self): super().__init__() - self._set_poslist_dls() + #self._set_poslist_dls() def _generic_scan(self, detector, spectra, wiring="detector_1det_1dae3card.dat", tcbs=None): # Explicitly check and then set to default value to avoid UB. @@ -25,19 +33,40 @@ def _generic_scan(self, detector, spectra, wiring="detector_1det_1dae3card.dat", @property def TIMINGS(self): if self._dae_mode == "polsans" or self._dae_mode == "poltrans": - return self._TIMINGS + ["u", "d"] - return self._TIMINGS + return self._TIMINGS + ["up_state_frames", "down_state_frames"] + if self._dae_mode == "pasans" or self._dae_mode == "patrans": + return self._TIMINGS + ["no_flip_state_frames", "flip_state_frames"] + return self._TIMINGS @dae_setter("SANS", "sans") def setup_dae_event(self): + + gen.change_sync('ISIS') + gen.change_vetos(ext0=True) print("Setting DAE into event mode") self._generic_scan( detector="detector_1det_1dae3card.dat", spectra="spec2det_280318_to_test_18_1.txt", - wiring="wiring1det_event_200218.dat") + wiring="wiring1det_event_200218.dat",tcbs = [{"low": 5.0, "high": 100000.0, "step": 200.0, "trange": 1, "log": 0}, + {"low": 5.0, "high": 100000.0, "step": 2.0, "trange": 1, + "log": 0, "regime": 2}]) + + @dae_setter("SANS", "sans") + def setup_dae_event_m5(self): + gen.change_sync("isis") + gen.change_vetos(ext0=True) + print("Setting DAE into event mode") + self._generic_scan( + detector="wiring_1det_mon5_event_250925.dat", + spectra="spec2det_280318_to_test_18_1.txt", + wiring="wiring1det_event_200218.dat",tcbs = [{"low": 5.0, "high": 100000.0, "step": 200.0, "trange": 1, "log": 0}, + {"low": 5.0, "high": 100000.0, "step": 2.0, "trange": 1, + "log": 0, "regime": 2}]) @dae_setter("SANS", "sans") def setup_dae_histogram(self): + gen.change_sync("isis") + gen.change_vetos(ext0=True) self._generic_scan( detector="detector_1det_1dae3card.dat", spectra="spec2det_130218.txt", @@ -45,14 +74,24 @@ def setup_dae_histogram(self): @dae_setter("TRANS", "transmission") def setup_dae_transmission(self): + gen.change_sync("isis") + gen.change_vetos(ext0=True) print("Setting up DAE for trans") self._generic_scan( detector="detector_8mon_1dae3card_00.dat", spectra="spectrum_8mon_1dae3card_00.dat", wiring="wiring_8mon_1dae3card_00_hist.dat") - + + @staticmethod + def _begin_transmission(): + """Initialise a POLSANS run""" + gen.change(nperiods=1) + gen.begin(paused=0) + @dae_setter("SANS", "sans") def setup_dae_event_tshift(self): + gen.change_sync("isis") + gen.change_vetos(ext0=True) #second frame for 10-25 AA self._generic_scan( detector="detector_1det_1dae3card.dat", @@ -64,6 +103,8 @@ def setup_dae_event_tshift(self): @dae_setter("TRANS", "transmission") def setup_dae_transmission_tshift(self): + gen.change_sync("isis") + gen.change_vetos(ext0=True) #second frame for 10-25 AA print("Setting up DAE for trans") self._generic_scan( @@ -74,7 +115,7 @@ def setup_dae_transmission_tshift(self): {"low": 20000.0, "high": 120000.0, "step": 200.0, "trange": 1, "log": 0, "regime": 2}]) - @dae_setter("POLSANS", "polsans") + @dae_setter("SANS", "sans") def setup_dae_polsans(self): """Setup the instrument for POLSANS measurements.""" self.setup_dae_event() @@ -85,18 +126,20 @@ def _begin_polsans(): gen.change(nperiods=2) gen.begin(paused=1) - @dae_setter("POLTRANS", "poltrans") + @dae_setter("TRANS", "transmission") def setup_dae_poltrans(self): """Setup the instrument for POLSANS transmission measurements.""" self.setup_dae_transmission() + @staticmethod def _begin_poltrans(): """Initialise a POLSANS transmission run""" - Zoom._begin_polsans() + gen.change(nperiods=2) + gen.begin(paused=1) @staticmethod - def _waitfor_polsans(up_state_frames=600, down_state_frames=600, **kwargs): + def _waitfor_polsans(up_state_frames=300, down_state_frames=300, **kwargs): """Perform a POLSANS run""" if "uamps" in kwargs: get_total = gen.get_uamps @@ -114,10 +157,11 @@ def _waitfor_polsans(up_state_frames=600, down_state_frames=600, **kwargs): gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") up_state_frames=up_state_frames/10 down_state_frames=down_state_frames/10 - + + flipper_on() while gtotal < kwargs[key]: gen.change(period=1) - info("Flipper On") + print("Flipper On") flipper1(1) if key == "seconds": gen.resume() @@ -130,7 +174,7 @@ def _waitfor_polsans(up_state_frames=600, down_state_frames=600, **kwargs): gen.pause() gen.change(period=2) - info("Flipper Off") + print("Flipper Off") flipper1(0) if key == "seconds": gen.resume() @@ -144,9 +188,57 @@ def _waitfor_polsans(up_state_frames=600, down_state_frames=600, **kwargs): gen.pause() gtotal = get_total() - + @staticmethod + def _waitfor_poltrans(up_state_frames=300, down_state_frames=300, **kwargs): + """Setup the instrument for POLSANS transmission measurements.""" + if "uamps" in kwargs: + get_total = gen.get_uamps + key = "uamps" + elif "seconds" in kwargs: + get_total = gen.get_uamps + key = "seconds" + else: + get_total = gen.get_frames + key = "frames" + gfrm = gen.get_frames() + gtotal = get_total() + + if key == "seconds": + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + up_state_frames=up_state_frames/10 + down_state_frames=down_state_frames/10 + + flipper_on() + while gtotal < kwargs[key]: + gen.change(period=1) + print("Flipper On") + flipper1(1) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=up_state_frames) + gen.pause() + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + up_state_frames) + gen.pause() + + gen.change(period=2) + print("Flipper Off") + flipper1(0) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=down_state_frames) + gen.pause() + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + down_state_frames) + gen.pause() + gtotal = get_total() - @dae_setter("PASANS", "pasans") + @dae_setter("SANS", "sans") def setup_dae_pasans(self): """Setup the instrument for Polarisation Analysis SANS measurements.""" self.setup_dae_event() @@ -176,12 +268,13 @@ def _waitfor_pasans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") no_flip_state_frames=no_flip_state_frames/10 flip_state_frames=flip_state_frames/10 - + + flipper_on() while gtotal < kwargs[key]: gen.change(period=1) - info("Flipper On") + print("Flipper On") flipper1(1) - info("Analyser On State") + print("Analyser On State") self.send_pv('3HE:STATE', 1) if key == "seconds": gen.resume() @@ -195,9 +288,9 @@ def _waitfor_pasans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): gen.pause() gen.change(period=2) - info("Flipper Off") + print("Flipper Off") flipper1(0) - info("Analyser On State") + print("Analyser On State") self.send_pv('3HE:STATE', 1) if key == "seconds": gen.resume() @@ -211,9 +304,9 @@ def _waitfor_pasans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): gen.pause() gen.change(period=3) - info("Flipper Off") + print("Flipper Off") flipper1(0) - info("Analyser Off State") + print("Analyser Off State") self.send_pv('3HE:STATE', 0) if key == "seconds": gen.resume() @@ -227,9 +320,9 @@ def _waitfor_pasans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): gen.pause() gen.change(period=4) - info("Flipper On") + print("Flipper On") flipper1(1) - info("Analyser On State") + print("Analyser On State") self.send_pv('3HE:STATE', 0) if key == "seconds": gen.resume() @@ -243,19 +336,163 @@ def _waitfor_pasans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): gen.pause() gtotal = get_total() - @dae_setter("PATRANS", "patrans") + @dae_setter("TRANS", "trans") def setup_dae_patrans(self): """Setup the instrument for polarisation analysis SANS transmission measurements.""" self.setup_dae_transmission() - + + @staticmethod def _begin_patrans(): - """Initialise a polarisation analysis SANS transmission run""" - Zoom._begin_pasans() - + """Initialise a polarisation analysis Trans run""" + gen.change(nperiods=4) + gen.begin(paused=1) + + @staticmethod + def _waitfor_patrans(no_flip_state_frames=600, flip_state_frames=600, **kwargs): + """Setup the instrument for POLSANS transmission measurements.""" + if "uamps" in kwargs: + get_total = gen.get_uamps + key = "uamps" + elif "seconds" in kwargs: + get_total = gen.get_uamps + key = "seconds" + else: + get_total = gen.get_frames + key = "frames" + gfrm = gen.get_frames() + gtotal = get_total() + + if key == "seconds": + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + no_flip_state_frames=no_flip_state_frames/10 + flip_state_frames=flip_state_frames/10 + + flipper_on() + while gtotal < kwargs[key]: + gen.change(period=1) + print("Flipper On") + flipper1(1) + print("Analyser On State") + #gen.set_pv('3HE:STATE', 1) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=no_flip_state_frames) + gen.pause() + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + no_flip_state_frames) + gen.pause() + gen.change(period=2) + print("Flipper Off") + flipper1(0) + print("Analyser On State") + #gen.set_pv('3HE:STATE', 1) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=flip_state_frames) + gen.pause() + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + flip_state_frames) + gen.pause() + + gen.change(period=3) + print("Flipper Off") + flipper1(0) + print("Analyser Off State") + #gen.set_pv('3HE:STATE', 0) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=no_flip_state_frames) + gen.pause() + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + no_flip_state_frames) + gen.pause() + + gen.change(period=4) + print("Flipper On") + flipper1(1) + print("Analyser On State") + #gen.set_pv('3HE:STATE', 0) + if key == "seconds": + gen.resume() + gen.waitfor(seconds=flip_state_frames) + gen.pause() + gtotal=gen.get_pv("IN:ZOOM:DAE:RUNDURATION") + else: + gfrm = gen.get_frames() + gen.resume() + gen.waitfor(frames=gfrm + flip_state_frames) + gen.pause() + gtotal = get_total() + def set_aperture(self, size): - warning("Setting the aperture is not implemented.") + if size.upper() == "SMALL": + # JAWS + gen.cset(J1_HCENT=0) #Center jaws + gen.cset(J1_VCENT=0) + gen.cset(J2_VCENT=0) + gen.cset(J2_HCENT=0) + gen.cset(J3_VCENT=0) + gen.cset(J3_HCENT=0) + gen.cset(J4_VCENT=0) + gen.cset(J4_HCENT=0) + #gen.cset(J1_VGAP=16) physical source size + #gen.cset(J1_HGAP=26) + gen.cset(J1_VGAP=20) + gen.cset(J1_HGAP=20) + gen.cset(J2_VGAP=20) + gen.cset(J2_HGAP=20) + gen.cset(J3_VGAP=20) #(widely open ~71x71) + gen.cset(J3_HGAP=20) #(widely open ~71x71) + gen.cset(J4_VGAP=12) + gen.cset(J4_HGAP=12) + elif size.upper() == "MEDIUM": + # JAWS + gen.cset(J1_HCENT=0) #Center jaws + gen.cset(J1_VCENT=0) + gen.cset(J2_VCENT=0) + gen.cset(J2_HCENT=0) + gen.cset(J3_VCENT=0) + gen.cset(J3_HCENT=0) + gen.cset(J4_VCENT=0) + gen.cset(J4_HCENT=0) + gen.cset(J1_VGAP=20) + gen.cset(J1_HGAP=20) + gen.cset(J2_VGAP=20) + gen.cset(J2_HGAP=20) + gen.cset(J3_VGAP=20) #(widely open ~71x71) + gen.cset(J3_HGAP=20) #(widely open ~71x71) + gen.cset(J4_VGAP=12) + gen.cset(J4_HGAP=12) + elif size.upper() == "LARGE": + gen.cset(J1_HCENT=0) #Center jaws + gen.cset(J1_VCENT=0) + gen.cset(J2_VCENT=0) + gen.cset(J2_HCENT=0) + gen.cset(J3_VCENT=0) + gen.cset(J3_HCENT=0) + gen.cset(J4_VCENT=0) + gen.cset(J4_HCENT=0) + gen.cset(J1_VGAP=30) + gen.cset(J1_HGAP=30) + gen.cset(J2_VGAP=30) + gen.cset(J2_HGAP=30) + gen.cset(J3_VGAP=30) #(widely open ~71x71) + gen.cset(J3_HGAP=30) #(widely open ~71x71) + gen.cset(J4_VGAP=15) + gen.cset(J4_HGAP=15) + else: + info("Apertures unchanged") def _detector_is_on(self): """Is the detector currently on?""" @@ -263,14 +500,24 @@ def _detector_is_on(self): self.get_pv( "CAEN:hv0:4:{}:status".format(x)).lower() == "on" for x in range(8)]) + print(voltage_status) return voltage_status def _detector_turn_on(self, delay=True): - raise NotImplementedError("Detector toggling is not supported Zoom") + for i in range(8): + self.send_pv(f"CAEN:hv0:4:{i}:pwonoff", "On") + if delay: + print("Waiting For Detector To Power Up (120s)") + gen.waitfor(seconds = 120) def _detector_turn_off(self, delay=True): - raise NotImplementedError("Detector toggling is not supported on Zoom") + for i in range(8): + self.send_pv(f"CAEN:hv0:4:{i}:pwonoff", "Off") + if delay: + print("Waiting For Detector To Power Down (120s)") + gen.waitfor(seconds = 120) + def _configure_sans_custom(self): # move the transmission monitor out self.send_pv("VACUUM:MONITOR:2:EXTRACT","EXTRACT") @@ -293,41 +540,328 @@ def _configure_trans_custom(self): # self.send_pv("VACUUM:MONITOR:4:INSERT", "INSERT") + def col_8m(): print("8m configuration:choppers, colimator") gen.cset("PGC_Unit",101.45) - gen.cset("disk2",97000) + gen.cset("Chopper_Disk2",97000) + + def col_10m(): + print("10m configuration:choppers, colimator") + gen.cset("PGC_Unit",101.45) + gen.cset("Chopper_Disk2",93000) + + def set_ZOOM_SC_10m_8mm(self, BeamStop_X=27, BeamStop_Y=765): + #Based on ZOOM setup: 261, scans 2026-5-21 + print("Setup ZOOM for 8m configuration") + + + # CHOPPERS + gen.cset(target_chopper_freq=10) + gen.cset(Chopper_Disk1=3000) + gen.cset(inst_chopper_freq=10) + gen.cset(Chopper_Disk2=93000) + + # JAWS + gen.cset(J1_HCENT=0) #Center jaws + gen.cset(J1_VCENT=0) + gen.cset(J2_VCENT=0) + gen.cset(J2_HCENT=0) + gen.cset(J3_VCENT=0) + gen.cset(J3_HCENT=0) + gen.cset(J4_VCENT=0) + gen.cset(J4_HCENT=0) + gen.cset(J1_VGAP=20) + gen.cset(J1_HGAP=30) + gen.cset(J2_VGAP=16) + gen.cset(J2_HGAP=16) + gen.cset(J3_VGAP=16) + gen.cset(J3_HGAP=16) + gen.cset(J4_VGAP=13) + gen.cset(J4_HGAP=13) + + + # PGC unit (Polariser or Guide or Collimator) + self.send_pv("IN:ZOOM:LKUP:PGC:POSN:SP","Collimator") #Collimator in + gen.waitfor_move() + # BEAMSTOPPERS and MONITOR + #Small_BS =out + gen.cset(BeamStop_disc_x=-17.36)# it was -482 and -477 + gen.cset(BeamStop_disc_y=0) + + #Beamstop Monitor in + gen.cset(BeamStop_monitor_x=BeamStop_X) + gen.cset(BeamStop_monitor_y=BeamStop_Y) + + #gen.cset(Strip_beamstop=2831) + + # DETECTORS and BAFFLES + if 9400 Date: Tue, 11 Aug 2026 16:28:18 +0100 Subject: [PATCH 3/3] only commit changes for default behaviour setting up do_sans, do_trans --- technique/sans/instrument.py | 67 +++++++++++++++++------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/technique/sans/instrument.py b/technique/sans/instrument.py index f74196a..0bfc102 100755 --- a/technique/sans/instrument.py +++ b/technique/sans/instrument.py @@ -87,8 +87,6 @@ def method_iterator(self): callable(getattr(self, method)): yield method - - def set_default_dae(self, mode=None, trans=False): """Set the default DAE mode for SANS or TRANS measurements. @@ -241,10 +239,11 @@ def _generic_scan(self, detector, spectra, wiring, tcbs): '1WT', '2WT', '3WT', '4WT', '5WT', '6WT', '7WT', '8WT', '9WT', '10WT', '11WT', '12WT', '13WT', '14WT', '1GT', '2GT', '3GT', '4GT', '5GT', '6GT', '7GT', '8GT', '9GT', - '10GT', '11GT', '12GT', '1R', '2R', '3R', '4R', '5R', '6R', '7R'] + '10GT', '11GT', '12GT', '1R', '2R', '3R', '4R', '5R', '6R', '7R', + '1OX', '2OX', '3OX', '4OX', '5OX'] def _attempt_resume(self, title, pos, thick, dae, **kwargs): - if gen.get_title() != f"{title}{self.title_footer}": + if title is not None and gen.get_title() != f"{title}{self.title_footer}": raise RuntimeError( f'Attempted to continue measurement "{title}", but was already in ' f'the middle of measurement "{gen.get_title()}".') @@ -278,7 +277,7 @@ def _attempt_resume(self, title, pos, thick, dae, **kwargs): f'at {val}, but instead found it at {gen.cget(val)["value"]}. Please either ' f'correct the script or manually end the run.') - if gen.get_sample_pars()['THICK'] != thick: + if thick is not None and gen.get_sample_pars()['THICK'] != thick: raise RuntimeError( f'Expected to resume a run on a sample of thickness {thick}, ' f'but was already running a measurement on a sample of ' @@ -450,7 +449,7 @@ def detector_on(self, powered=None, delay=True): else: self._detector_turn_off(delay=delay) return self._detector_is_on() - + def check_move_pos(self, pos): """Check whether the position is valid and return True or False @@ -460,9 +459,8 @@ def check_move_pos(self, pos): The sample changer position """ - stripped_pos = pos.strip() - if stripped_pos.upper() not in [pos_name.upper() for pos_name in self._poslist]: - warning(f"Error in script, position {stripped_pos} does not exist") + if pos.upper() not in [pos_name.upper() for pos_name in self._poslist]: + warning(f"Error in script, position {pos} does not exist") return False return True @@ -547,7 +545,7 @@ def _setup_measurement_software(self, trans): else: self.setup_sans() - def measure(self, title="", position=None, thickness=1.0, trans=False, + def measure(self, title=None, position=None, thickness=None, trans=False, dae=None, aperture="", time=None, period=None, dls_sample_changer=False, **kwargs): """Take a sample measurement. If no timing parameter is provided @@ -631,7 +629,7 @@ def measure(self, title="", position=None, thickness=1.0, trans=False, dae=dae, aperture=aperture, time=time, period=period, _custom=True, dls_sample_changer=dls_sample_changer, **kwargs) - def _setup(self, title="", position=None, thickness=1.0, trans=False, + def _setup(self, title=None, position=None, thickness=None, trans=False, dae=None, aperture="", period=None, _custom=True, dls_sample_changer=False, **kwargs): # Check detector for sans @@ -645,8 +643,16 @@ def _setup(self, title="", position=None, thickness=1.0, trans=False, self.set_default_dae(dae, trans) self._setup_measurement_software(trans) - self.measurement_label = title - gen.change(title=title + self.title_footer) + if title is None: + full_title = gen.get_title() + part_title = title + if full_title.endswith(self.title_footer): + part_title = full_title[:-len(self.title_footer)] + self.measurement_label = part_title + gen.change(title=full_title) + else: + self.measurement_label = title + gen.change(title=title + self.title_footer) self.set_aperture(aperture) @@ -660,24 +666,13 @@ def _setup(self, title="", position=None, thickness=1.0, trans=False, info(f"Moving {arg} to {val}") gen.cset(arg, val) gen.waitfor_move() - gen.change_sample_par("Thick", thickness) + if thickness is not None: + gen.change_sample_par("Thick", thickness) info("Using the following Sample Parameters") self.print_sample_pars() if period: gen.change_period(period) - - - def _validate_sample_position(self, position): - if position is None: - raise ValueError("Sample position cannot be None") - - stripped_pos = position.strip() - if stripped_pos not in self._poslist: - raise ValueError(f"Invalid sample position: '{stripped_pos}'. " - f"Available positions are: {', '.join(self._poslist)}") - return stripped_pos - def _set_sample_position(self, position, dls_sample_changer=False): if isinstance(position, str): if dls_sample_changer and self.check_move_pos_dls(position): @@ -685,7 +680,7 @@ def _set_sample_position(self, position, dls_sample_changer=False): self.changer_pos_dls = position elif self.check_move_pos(position): info(f"Moving to sample changer position {position}") - self.changer_pos = self._validate_sample_position(position) + self.changer_pos = position else: raise RuntimeError( f"Position {position} does not exist") @@ -696,24 +691,26 @@ def _set_sample_position(self, position, dls_sample_changer=False): raise TypeError(f"Cannot understand position {position}") gen.waitfor_move() - def _do_measure(self, title="", time=None, **kwargs): + def _do_measure(self, title=None, time=None, **kwargs): if time: times = {"seconds": time} else: times = self.sanitised_timings(kwargs) unit, time = _get_times(times) - info(f"Measuring {title + self.title_footer} for {time} {unit}") + if title is None: + info(f"Measuring {gen.get_title()} for {time} {unit}") + else: + info(f"Measuring {title + self.title_footer} for {time} {unit}") self._begin() self._waitfor(**times) self._end() - def _measure(self, title="", position=None, thickness=1.0, trans=False, + def _measure(self, title=None, position=None, thickness=None, trans=False, dae=None, aperture="", period=None, time=None, _custom=True, **kwargs): - valid_pos = self._validate_sample_position(position) - self._setup(title=title, position=valid_pos, thickness=thickness, trans=trans, + self._setup(title=title, position=position, thickness=thickness, trans=trans, dae=dae, aperture=aperture, period=period, _custom=_custom, **kwargs) @@ -721,7 +718,7 @@ def _measure(self, title="", position=None, thickness=1.0, trans=False, if time or self.sanitised_timings(kwargs): self._do_measure(title=title, time=time, **kwargs) - def do_sans(self, title="", pos=None, thickness=1.0, dae="event", + def do_sans(self, title=None, pos=None, thickness=1.0, dae="event", aperture="", period=None, time=None, dls_sample_changer=False, **kwargs): """A wrapper around ``measure`` which ensures that the instrument is in sans mode before running the measurement if a title is given. @@ -752,7 +749,7 @@ def do_sans(self, title="", pos=None, thickness=1.0, dae="event", dae=dae, aperture=aperture, period=period, time=time, _custom=False, dls_sample_changer=dls_sample_changer, **kwargs) - def do_trans(self, title="", pos=None, thickness=1.0, dae="transmission", + def do_trans(self, title=None, pos=None, thickness=1.0, dae="transmission", aperture="", period=None, time=None, dls_sample_changer=False, **kwargs): """A wrapper around ``measure`` which ensures that the instrument is in transition mode before running the measurement if a title is given. It ensures that the @@ -1009,4 +1006,4 @@ def _set_poslist_dls(self): self._poslist_dls = self.get_pv("LKUP:DLS:POSITIONS").split() except AttributeError: warning("No positions found for DLS Sample Changer!") - self._poslist_dls = [] + self._poslist_dls = [] \ No newline at end of file