From 0c928a8bb134a199bc05817db3c351f5a4fdcb37 Mon Sep 17 00:00:00 2001 From: reiche Date: Wed, 5 Jul 2023 09:16:18 +0200 Subject: [PATCH] Improved snapshot interface with saving snapshot files in the OP configuration. Added app support for stabilizing XTCAV. Added a BSacquisition based on BSCache --- app/__init__.py | 1 + app/dispersiontools.py | 9 +++++---- app/xtcavstabilizer.py | 19 +++++++++++++++---- ext/__init__.py | 1 + ext/bscacquisition.py | 42 ++++++++++++++++++++++++++++++++++++++++++ interface/__init__.py | 1 + interface/snap.py | 17 ++++++++++++++--- 7 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 ext/bscacquisition.py diff --git a/app/__init__.py b/app/__init__.py index ac9d226..13ed080 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,3 +2,4 @@ from .adaptiveorbit import AdaptiveOrbit from .spectralanalysis import SpectralAnalysis from .hero import LaserPower,EnergyModulation from .dispersiontools import Dispersion +from .xtcavstabilizer import XTCAVStabilizer diff --git a/app/dispersiontools.py b/app/dispersiontools.py index ff5689a..ff2b6be 100644 --- a/app/dispersiontools.py +++ b/app/dispersiontools.py @@ -9,6 +9,7 @@ from slic.core.adjustable import PVAdjustable from slic.core.acquisition import BSAcquisition, PVAcquisition from slic.core.scanner import Scanner from sfbd.ext import CounterAdjustable +from sfbd.ext import BSCAcquisition def getAux(pvs=None): if not pvs: @@ -95,7 +96,7 @@ class Dispersion: sensor1 = getBSChannels('SATBD02-DBPM.*:Y2$') sensor2 = getBSChannels('SATCB.*-RLLE-DSP:.*-VS$') self.sensor = sensor1+sensor2 - self.acq = [BSAcquisition(".",pgroup, default_channels=self.sensor)] + self.acq = [BSCAcquisition(".",pgroup, default_channels=self.sensor)] # auxiliar data to be read one self.aux = self.getRFCalibrationChannels(sensor2,'SATCL01-MBND100:ENERGY-OP') @@ -159,7 +160,7 @@ class Dispersion: def setup(self,scl = 1, Nsteps=5, Nsamples=5): val = self.adj.get_current_value(readback=False) dval = self.amp*scl - dval = 0 + dval = 0 ######## edit this self.N = Nsteps self.Ns= Nsamples self.values=np.linspace(val-dval,val+dval,num=self.N) @@ -179,10 +180,10 @@ class Dispersion: self.sc=self.scanner.ascan_list(self.adj,self.values, filename=self.branch,start_immediately = False, n_pulses=self.Ns,return_to_initial_values=True) - self.preaction() +# self.preaction() ###### self.sc.run() self.auxdata = getAux(self.aux) - self.postaction() +# self.postaction() ####### def stop(self): diff --git a/app/xtcavstabilizer.py b/app/xtcavstabilizer.py index 1e58ce1..830085f 100644 --- a/app/xtcavstabilizer.py +++ b/app/xtcavstabilizer.py @@ -2,18 +2,29 @@ import time import numpy as np from bstrd import BSCache +from epics import PV + class XTCAVStabilizer: """ Wrapper class to bundle all daq/io needed for stabilizing the XTCAV """ def __init__(self): + + # the PV + self.PVTCAV = PV('SATMA02-RMSM:SM-GET',connection_timeout=0.9, callback=self.stateChanged) + self.state=self.PVTCAV.value == 9 + + # the BS channels self.bs = BSCache(100000,10000) # 100 second timeout, size for 100 second data taken - self.channels = ['SATBD02-DBPM040:X2','SATMA02-RLLE-DSP:PHASE-VS'] + self.channels = ['SATBD02-DBPM040:X2','SATMA02-RLLE-DSP:PHASE-VS','SATBD02-DBPM040:X2-VALID'] + self.validation = self.channels[2] self.bs.get_vars(self.channels) # this starts the stream into the cache self.bs.stop() - + def stateChanged(self,pvname=None, value=0, **kws): + self.state = value == 9 + def terminate(self): print('Stopping BSStream Thread...') self.bs.stop() @@ -23,7 +34,7 @@ class XTCAVStabilizer: self.bs.flush() def read(self): - data=self.bs.__next__() - return data['pid'],data[self.channels[0]],data[self.channels[1]] # returns PID, BPM reading, TCAV Phase + return self.bs.__next__() + diff --git a/ext/__init__.py b/ext/__init__.py index 01b2db3..976402d 100644 --- a/ext/__init__.py +++ b/ext/__init__.py @@ -1,3 +1,4 @@ from .magnet import Magnet from .camacquisition import CamAcquisition from .counteradjustable import CounterAdjustable +from .bscacquisition import BSCAcquisition diff --git a/ext/bscacquisition.py b/ext/bscacquisition.py new file mode 100644 index 0000000..21495ee --- /dev/null +++ b/ext/bscacquisition.py @@ -0,0 +1,42 @@ +import zmq +import h5py + + +from bstrd import BSCache +from slic.core.acquisition.acquisition import Acquisition +from slic.core.acquisition import BSAcquisition, PVAcquisition + +# class using the BSQueue to avoid to reestablish a stream for each step. + +class BSCAcquisition(Acquisition): + + def release(self): + if not self.queue == None: + del self.queue + self.queue = None + + def _acquire(self, filename, channels=None, data_base_dir=None, scan_info=None, n_pulses=100, **kwargs): + if not hasattr(self,'queue'): + self.queue = getStream(channels) + elif not self.queue: + self.queue = getStream(channels) + + self.queue.flush() + print('Acquiring',n_pulses,'samples') + data = [] + for i in range(n_pulses): + data.append(self.queue.__next__()) + hid = h5py.File(filename,'w') + gid = hid.create_group(channels[0]) + for key in data[0].keys(): + gid.create_dataset(key, data = [rec[key].value for rec in data]) + hid.close() + + +def getStream(channels): + print('Generating stream with channels:',channels) + bs = BSCache(100000,10000) # 1 second time out, capazity for 100 second. + bs.get_vars(channels) + return bs + + diff --git a/interface/__init__.py b/interface/__init__.py index 3aa44be..8f3efde 100644 --- a/interface/__init__.py +++ b/interface/__init__.py @@ -1,4 +1,5 @@ from .snap import getSnap +from .snap import saveSnap from .save import saveDataset from .load import loadDataset from .elog import writeElog diff --git a/interface/snap.py b/interface/snap.py index 4b14b90..ddd2841 100644 --- a/interface/snap.py +++ b/interface/snap.py @@ -1,13 +1,12 @@ import numpy as np import yaml import os - +import datetime import epics # things to do: # 1. Read a snapshot file (not request file) -# 2. Save a snapshot file -# 3. add parameters and performance channels (e.g. AT photon energies) +# 2. add parameters and performance channels (e.g. AT photon energies) def parseSnapShotReqYAML(filename): # read the snapshot request file @@ -63,6 +62,18 @@ def getSnap(pvs=None): epics.ca.clear_cache() return ret +def saveSnap(pvs={},label="", comment = "generated by application"): + filename = datetime.datetime.now().strftime('/sf/data/applications/snapshot/SF_settings_%Y%m%d_%H%M%S.snap') + with open(filename,'w') as fid: + fid.write('#{"labels":["%s"],"comment":"%s", "machine_parms":{}, "save_time": 0.0, "req_file_name": "SF_settings.yaml"}\n' % (label,comment)) + for key in pvs.keys(): + if isinstance(pvs[key],int): + fid.write('%s,{"val": %d}\n' % (key,pvs[key])) + elif isinstance(pvs[key],float): + fid.write('%s,{"val": %f}\n' % (key,pvs[key])) + elif isinstance(pvs[key],str): + fid.write('%s,{"val": %s}\n' % (key,pvs[key])) +