From bf5427bd04e261636b5fde5d1ab1a8c1329834b8 Mon Sep 17 00:00:00 2001 From: x07maop Date: Mon, 24 Aug 2015 08:28:12 +0200 Subject: [PATCH] Startup --- config/config.properties | 5 +- config/config.properties~ | 25 +++ plugins/EnergyScan.java | 35 ++-- script/Dy_hyst_plus.py | 106 ------------ script/EnergyScan.py | 86 ---------- script/HystScan.py | 162 ------------------ script/MgE_plus.py | 27 --- script/local.py | 41 +---- script/tutorial/01_LineScan.py | 25 +++ script/tutorial/02_ScanCallbacks.py | 20 +++ script/tutorial/03_ManipulatingScanData.py | 21 +++ script/tutorial/04_AreaScan.py | 12 ++ script/tutorial/05_RelativeScan.py | 12 ++ script/tutorial/06_VectorScan.py | 22 +++ script/tutorial/07_MathFit.py | 59 +++++++ script/tutorial/08_MathMultipleGaussians.py | 38 +++++ script/tutorial/09_PseudoDevices.py | 26 +++ script/tutorial/10_DeviceListener.py | 25 +++ script/tutorial/11_ParametersAndReturn.py | 22 +++ script/tutorial/12_ManualScan.py | 33 ++++ script/tutorial/13_CustomPlot.py | 19 +++ script/tutorial/14_DataManipulation.py | 69 ++++++++ script/tutorial/15_Pararellization.py | 51 ++++++ script/tutorial/16_SimultaneousScans.py | 15 ++ script/tutorial/17_DirectEpicsAccess.py | 36 ++++ script/tutorial/18_Imaging.py | 21 +++ script/tutorial/19_ContinuousScan.py | 15 ++ script/tutorial/devices.py | 175 ++++++++++++++++++++ 28 files changed, 768 insertions(+), 435 deletions(-) create mode 100644 config/config.properties~ delete mode 100644 script/Dy_hyst_plus.py delete mode 100644 script/EnergyScan.py delete mode 100644 script/HystScan.py delete mode 100644 script/MgE_plus.py create mode 100644 script/tutorial/01_LineScan.py create mode 100644 script/tutorial/02_ScanCallbacks.py create mode 100644 script/tutorial/03_ManipulatingScanData.py create mode 100644 script/tutorial/04_AreaScan.py create mode 100644 script/tutorial/05_RelativeScan.py create mode 100644 script/tutorial/06_VectorScan.py create mode 100644 script/tutorial/07_MathFit.py create mode 100644 script/tutorial/08_MathMultipleGaussians.py create mode 100644 script/tutorial/09_PseudoDevices.py create mode 100644 script/tutorial/10_DeviceListener.py create mode 100644 script/tutorial/11_ParametersAndReturn.py create mode 100644 script/tutorial/12_ManualScan.py create mode 100644 script/tutorial/13_CustomPlot.py create mode 100644 script/tutorial/14_DataManipulation.py create mode 100644 script/tutorial/15_Pararellization.py create mode 100644 script/tutorial/16_SimultaneousScans.py create mode 100644 script/tutorial/17_DirectEpicsAccess.py create mode 100644 script/tutorial/18_Imaging.py create mode 100644 script/tutorial/19_ContinuousScan.py create mode 100644 script/tutorial/devices.py diff --git a/config/config.properties b/config/config.properties index 82cb45d..5613e48 100644 --- a/config/config.properties +++ b/config/config.properties @@ -1,7 +1,7 @@ -#Tue Jul 28 15:18:34 CEST 2015 +#Mon Aug 24 08:28:02 CEST 2015 autoSaveScanData=true createSessionFiles=false -dataPath={data}/{year}_{month}/{date}/{date}_{time}_{context} +dataPath={data}/{year}_{month}/{date}/{date}_{time}_{exec} dataProvider=txt dataScanFlushRecords=true dataScanStrategy=table @@ -11,6 +11,7 @@ imageSourcesFile={config}/imaging.properties logDaysToLive=-1 logLevel=Info logLevelConsole=Off +logPath={logs}/{date}_{time} scriptType=py serverEnabled=false serverPort=8080 diff --git a/config/config.properties~ b/config/config.properties~ new file mode 100644 index 0000000..82cb45d --- /dev/null +++ b/config/config.properties~ @@ -0,0 +1,25 @@ +#Tue Jul 28 15:18:34 CEST 2015 +autoSaveScanData=true +createSessionFiles=false +dataPath={data}/{year}_{month}/{date}/{date}_{time}_{context} +dataProvider=txt +dataScanFlushRecords=true +dataScanStrategy=table +devicePoolFile={config}/devices.properties +deviceUpdateStrategyFile={config}/update.properties +imageSourcesFile={config}/imaging.properties +logDaysToLive=-1 +logLevel=Info +logLevelConsole=Off +scriptType=py +serverEnabled=false +serverPort=8080 +simulation=false +tasksFile={config}/tasks.properties +terminalEnabled=true +terminalPort=3579 +userAuthenticator= +userManagement=false +versionTrackingEnabled=true +versionTrackingLogin={config}/agkey +versionTrackingRemote=ssh\://git@github.psi.ch\:7999/psd/x07ma.git diff --git a/plugins/EnergyScan.java b/plugins/EnergyScan.java index 482af41..6cef62a 100644 --- a/plugins/EnergyScan.java +++ b/plugins/EnergyScan.java @@ -2,24 +2,7 @@ * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. */ -import ch.psi.pshell.core.Controller.ControllerStateException; -import ch.psi.pshell.data.PlotDescriptor; -import ch.psi.pshell.dev.Device; -import ch.psi.pshell.dev.DeviceListener; -import ch.psi.pshell.epics.ChannelDoubleArray; -import ch.psi.pshell.epics.ChannelInteger; -import ch.psi.pshell.plot.LinePlot; -import ch.psi.pshell.plot.LinePlotBase; -import ch.psi.pshell.plot.LinePlotSeries; -import ch.psi.pshell.plot.Plot; -import ch.psi.pshell.ui.Panel; -import ch.psi.utils.Chrono; -import ch.psi.utils.State; -import ch.psi.utils.swing.SwingUtils; -import ch.psi.wsaf.DsvEditor; -import ch.psi.wsaf.Editor.EditorDialog; import java.awt.Component; -import java.awt.Desktop; import java.io.FileInputStream; import java.nio.file.Files; import java.nio.file.Path; @@ -30,6 +13,22 @@ import java.util.Properties; import java.util.logging.Level; import javax.swing.DefaultComboBoxModel; import javax.swing.JLabel; +import ch.psi.utils.Chrono; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import ch.psi.utils.swing.DsvEditor; +import ch.psi.utils.swing.Editor.EditorDialog; +import ch.psi.pshell.core.Controller.ControllerStateException; +import ch.psi.pshell.data.PlotDescriptor; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.device.DeviceListener; +import ch.psi.pshell.epics.ChannelDoubleArray; +import ch.psi.pshell.epics.ChannelInteger; +import ch.psi.pshell.plot.LinePlot; +import ch.psi.pshell.plot.LinePlotBase; +import ch.psi.pshell.plot.LinePlotSeries; +import ch.psi.pshell.plot.Plot; +import ch.psi.pshell.ui.Panel; /** * @@ -834,7 +833,7 @@ public class EnergyScan extends Panel { String[] columns = new String[]{"Element", "E1", "E2", "Time", "Delay", "OffPlus", "OffMinus", "OffLH", "OffLV"}; Class[] types = new Class[]{String.class, Double.class, Double.class, Double.class, Double.class, Double.class, Double.class, Double.class, Double.class}; DsvEditor editor = new DsvEditor(columns , types, " "); - dlgConfig = editor.getDialog(false); + dlgConfig = editor.getDialog(getView(),false); editor.load(getConfigFile().toString()); editor.setTitle("Energy Scan Configuration"); } diff --git a/script/Dy_hyst_plus.py b/script/Dy_hyst_plus.py deleted file mode 100644 index 58e3a3a..0000000 --- a/script/Dy_hyst_plus.py +++ /dev/null @@ -1,106 +0,0 @@ -#Script imported from: Dy_hyst_plus.xml - -#Pre-actions -cawait('ACOAU-ACCU:OP-MODE', 'Light Available', type = 's') -caput('X07MA-ID:MODE', 'CIRC +') -time.sleep(1.0) -cawait('X07MA-ID:DONE', 'DONE', type = 's') -caput('X07MA-ID:ENERGY-OFFS', '-8.75') -cawait('X07MA-ID:DONE', 'DONE', type = 's') -caputq('X07MA-PC:CSCALER.INPB', '1') -caputq('X07MA-PC-PS2:SET:DMD:RAMPRATE:TPM', '2.0') -time.sleep(15.0) -caput('X07MA-OP-VG13:WT_SET', 'Try open') -time.sleep(5.0) - -#TODO: Set the diplay names of positioners and detectors -scan = ManualScan(['field', 'Energy'], ['TEY', 'I0', 'trans', 'polarization', 'polAngle', 'temperature', 'RingCurrent', 'fieldAnalogX', 'tey_norm', 'trans_norm'] , [0.0, 1283.8], [55.0, 1291.8], [55, 1]) -scan.start() - -#Dimension 1 - -#RegionPositioner field -field = Channel('X07MA-PC:GO', type = 'd') -fieldReadback = Channel('X07MA-PC-PS2:STS:PMCURRENT', type = 'd') -for setpoint1 in frange(0.0, 55.0, 1.0, True): - #Region 1 pre-actions - if setpoint1 == 0.0: - caputq('X07MA-PC-PS2:M:GO.A', '-3') - field.put(setpoint1, 2.0) # TODO: Add appropriate timeout - readback1 = fieldReadback.get() - if abs(readback1 - setpoint1) > 0.5 : # TODO: Check accuracy - raise Exception('Actor field could not be set to the value ' + str(setpoint1)) - #Dimension 2 - - #ScalarDetector TEY - TEY = Channel('X07MA-ES1-AI:SIGNAL0', type = 'd') - #ScalarDetector I0 - I0 = Channel('X07MA-ES1-AI:SIGNAL1', type = 'd') - #ScalarDetector trans - trans = Channel('X07MA-ES1-AI:SIGNAL2', type = 'd') - #ScalarDetector polarization - polarization = Channel('X07MA-ID:MODE', type = 'd') - #ScalarDetector polAngle - polAngle = Channel('X07MA-ID:ALPHA', type = 'd') - #ScalarDetector temperature - temperature = Channel('X07MA-PC-TC:STS:T1', type = 'd') - #ScalarDetector RingCurrent - RingCurrent = Channel('ARIDI-PCT:CURRENT', type = 'd') - #ScalarDetector fieldAnalogX - fieldAnalogX = Channel('X07MA-ES1-AI:SIGNAL4', type = 'd') - #ArrayPositioner Energy - Energy = Channel('X07MA-PHS-E:GO.A', type = 'd') - EnergyReadback = Channel('X07MA-PGM:CERBK', type = 'd') - for setpoint2 in (1291.8, 1283.8): - Energy.put(setpoint2) # TODO: Add appropriate timeout - readback2 = EnergyReadback.get() - if abs(readback2 - setpoint2) > 0.1 : # TODO: Check accuracy - raise Exception('Actor Energy could not be set to the value ' + str(setpoint2)) - time.sleep( 0.5 ) # Settling time - #Detector TEY - detector1 = TEY.get() - #Detector I0 - detector2 = I0.get() - #Detector trans - detector3 = trans.get() - #Detector polarization - detector4 = polarization.get() - #Detector polAngle - detector5 = polAngle.get() - #Detector temperature - detector6 = temperature.get() - #Detector RingCurrent - detector7 = RingCurrent.get() - #Detector fieldAnalogX - detector8 = fieldAnalogX.get() - #Manipulation tey_norm - #Variable Mappings - c = detector1 - d = detector2 - - import math - tey_norm = c/d - - #Manipulation trans_norm - #Variable Mappings - c = detector3 - d = detector2 - - import math - trans_norm = c/d - - scan.append ([setpoint1, setpoint2], [readback1, readback2], [detector1, detector2, detector3, detector4, detector5, detector6, detector7, detector8, tey_norm, trans_norm]) - Energy.close() - EnergyReadback.close() - TEY.close() - I0.close() - trans.close() - polarization.close() - polAngle.close() - temperature.close() - RingCurrent.close() - fieldAnalogX.close() -field.close() -fieldReadback.close() - -scan.end() diff --git a/script/EnergyScan.py b/script/EnergyScan.py deleted file mode 100644 index 24bdf41..0000000 --- a/script/EnergyScan.py +++ /dev/null @@ -1,86 +0,0 @@ -#Script imported from: MgE_plus.xml - -#Parameters -""" -E1 = 710 -E2 = 720 -TIME = 1 #min -DELAY = 10.0 #s -MODE = 'CIRC +' -OFFSET = -9.0 -FOLDER = '2015_04/20150417' -FILE = 'Fe_plus' -ALPHA=0 -""" - - -print "\nStarting energy scan - Parameters: ", -print E1,E2,TIME,DELAY,MODE ,OFFSET ,FOLDER ,FILE ,ALPHA - -start = time.localtime() - -folder = os.path.expanduser("~/Data1/") + FOLDER + "/"; -def getNewestFile(): - global folder - import glob - try: - return max(glob.iglob(folder+'/*.txt'), key=os.path.getctime) - except: - return None -newest = getNewestFile() - -def wait_channel(name, value, type): - print "Waiting " + str(name) + " = " + str(value) - cawait(name, value, type = type) - print "Done" - - -#Pre-actions -#wait_channel('ACOAU-ACCU:OP-MODE', 'Light Available', type = 's') -caput('X07MA-ID:MODE', MODE) -time.sleep(1.0) -if MODE == 'LINEAR': - caput('X07MA-ID:ALPHA', ALPHA) -wait_channel('X07MA-ID:DONE', 'DONE', type = 's') -caput('X07MA-ID:ENERGY-OFFS', OFFSET) -wait_channel('X07MA-ID:DONE', 'DONE', type = 's') -caput('E1', E1) -caput('E2', E2) -caput('TIME', TIME) -caput('FOLDER', FOLDER) -caputq('X07MA-PHS-E:GO.A', E1) -wait_channel('X07MA-PHS:alldone', '1', type = 's') -time.sleep(0.5) -caput('FILE', FILE) -time.sleep(0.1) -caput('X07MA-OP-VG13:WT_SET', 'Try open') -time.sleep(5.0) -caput('X07MA-OP-VG13:WT_SET', 'Try open') -time.sleep(DELAY) -caput('START', '1') - -#Post-actions -wait_channel('START', 'STOP', type = 's') - -time.sleep(2.0) -print "Finished Energy scan" - - -#File convertion -newName = folder + time.strftime("%Y%m%d_%H%M_", start) + FILE + "_0000.txt"; -#name = caget("MSG").split(' ')[0] -name = getNewestFile() - -if name == newest: - raise Exception("Data file not created") - -if not os.path.isfile(name): - raise Exception("Data file not found: " + name) - -cmd = "/sls/X07MA/data/x07maop/bin/modify_otf.pl " + name + " " + newName; -print("Converting data file: " + cmd); -import os -os.system(cmd) -print("Success") - - diff --git a/script/HystScan.py b/script/HystScan.py deleted file mode 100644 index 0582e16..0000000 --- a/script/HystScan.py +++ /dev/null @@ -1,162 +0,0 @@ -#Script imported from: Fe_hyst_plus.xml - -#Parameters -START_FIELD = -0.2 -END_FIELD = 0.2 -ENERGIES = (707.90, 703.90) -RAMP_RATE = 2.0 -ENERGY_CHANGE_SLEEP = 0.5 - -#Pre-actions -#cawait('ACOAU-ACCU:OP-MODE', 'Light Available', type = 's') -#caput('X07MA-ID:MODE', 'CIRC +') -sleep(1.0) -#cawait('X07MA-ID:DONE', 'DONE', type = 's') -#caput('X07MA-ID:ENERGY-OFFS', '-1.0') -#cawait('X07MA-ID:DONE', 'DONE', type = 's') -caputq('X07MA-PC:CSCALER.INPB', '1') -caputq('X07MA-PC-PS2:SET:DMD:RAMPRATE:TPM', RAMP_RATE) -#sleep(15.0) - -if len(ENERGIES) ==2: - dif_series = plot([],"Dif", context="Dif")[0].getSeries(0) -else: - dif_series = None - -set_preference(Preference.ENABLED_PLOTS, ['field', 'tey_norm', 'trans_norm']) -set_preference(Preference.PLOT_TYPES, {'tey_norm':1, 'trans_norm':1}) - -#scan = ManualScan(['field', 'Energy'], ['TEY', 'I0', 'trans', 'polarization', 'polAngle', 'temperature', 'RingCurrent', 'fieldAnalogX', 'tey_norm','trans_norm']) -scan = ManualScan(['field', 'Energy'], ['TEY', 'I0', 'trans', 'polarization', 'polAngle', 'temperature', 'RingCurrent', 'fieldAnalogX', 'tey_norm','trans_norm'], [0.0, ENERGIES[0]], [0.0, ENERGIES[-1]], [0, len(ENERGIES)-1]) -scan.start() - -#Stop condition -ramp_done = Channel('X07MA-PC-MAG:X:RAMP:DONE', type = 'i') - -#Creating channels: dimension 1 -#RegionPositioner field -#field = Channel('X07MA-PC:GO', type = 'd') -fieldReadback = Channel('X07MA-PC-PS2:STS:PMCURRENT', type = 'd') -#Creating channels: dimension 2 -#ArrayPositioner Energy -Energy = sim_energy #Channel('X07MA-PHS-E:GO.A', type = 'd') -EnergyReadback = sim_energy_readback # Channel('X07MA-PGM:CERBK', type = 'd') -#ScalarDetector TEY -TEY = Channel('X07MA-ES1-AI:SIGNAL0', type = 'd') -#ScalarDetector I0 -I0 = Channel('X07MA-ES1-AI:SIGNAL1', type = 'd') -#ScalarDetector trans -trans = Channel('X07MA-ES1-AI:SIGNAL2', type = 'd') -#ScalarDetector polarization -#polarization = Channel('X07MA-ID:MODE', type = 'd') -#ScalarDetector polAngle -#polAngle = Channel('X07MA-ID:ALPHA', type = 'd') -#ScalarDetector temperature -temperature = Channel('X07MA-PC-TC:STS:T1', type = 'd') -#ScalarDetector RingCurrent -RingCurrent = Channel('ARIDI-PCT:CURRENT', type = 'd') -#ScalarDetector fieldAnalogX -fieldAnalogX = Channel('X07MA-ES1-AI:SIGNAL4', type = 'd') - - -print "Waiting for start field" -""" -#WORKAROUND TO BUG IN DRIVER -if abs(fieldReadback.get() - START_FIELD) < 0.005: - caput('X07MA-PC-PS2:M:GO.A', START_FIELD + 0.01) -caput('X07MA-PC-PS2:M:GO.A', START_FIELD) -#caputq('X07MA-PC-PS2:M:GO.A', START_FIELD) -""" - -caput("X07MA-PC-MAG:X:DMD", START_FIELD) -caput("X07MA-PC-MAG:STARTRAMP.PROC", 1) -ramp_done.wait_for_value(1.0) -print "Set end field" -caput("X07MA-PC-MAG:X:DMD", END_FIELD) -caputq("X07MA-PC-MAG:STARTRAMP.PROC", 1) - - -index = 0 -while(True): - #Dimension 2START_FIELD = -0.2 -END_FIELD = 0.2 -ENERGIES = (707.90, 703.90) -RAMP_RATE = 2.0 - - #ArrayPositioner Energy - for setpoint2 in ENERGIES: - Energy.put(setpoint2, timeout=None) # TODO: Set appropriate timeout - sleep( ENERGY_CHANGE_SLEEP ) # Settling time - - readback2 = EnergyReadback.get() - if abs(readback2 - setpoint2) > 0.1 : # TODO: Check accuracy - raise Exception('Actor Energy could not be set to the value ' + str(setpoint2)) - - #Detector field readback - field_readback = fieldReadback.get() - - #Detector TEY - detector1 = TEY.get() - #Detector I0 - detector2 = I0.get() - #Detector trans - detector3 = trans.get() - #Detector polarization - detector4 = sim_energy_readback.read() # polarization.get() - #Detector polAngle - detector5 = sim_energy_readback.read() #polAngle.get() - #Detector temperature - detector6 = temperature.get() - #Detector RingCurrent - detector7 = RingCurrent.get() - #Detector fieldAnalogX - detector8 = fieldAnalogX.get() - - - #Manipulation tey_norm - #Variable Mappings - - #TODO: Move, if needed, this import to the file header: import math - tey_norm = detector1/detector2 - - #Manipulation trans_norm - #Variable Mappings - - #TODO: Move, if needed, this import to the file header: import math - trans_norm = detector3/detector2 - - - if dif_series is not None: - if setpoint2 == ENERGIES[0]: - first = tey_norm - else: - dif = tey_norm-first - dif_series.appendData(field_readback,dif) - print [field_readback, setpoint2] - print [field_readback, readback2] - print [detector1, detector2, detector3, detector4, detector5, detector6, detector7, detector8, tey_norm, trans_norm] - scan.append ([field_readback, setpoint2], [field_readback, readback2], [detector1, detector2, detector3, detector4, detector5, detector6, detector7, detector8, tey_norm, trans_norm]) - - - print "Field = " + str(fieldReadback.get()) - if ramp_done.get() == 1: #If not ramping - print "Not ramping, breaking execution" - break - index = index+1 - -#Closing channels -Energy.close() -EnergyReadback.close() -TEY.close() -I0.close() -trans.close() -#polarization.close() -#polAngle.close() -temperature.close() -RingCurrent.close() -fieldAnalogX.close() -#field.close() -fieldReadback.close() -ramp_done.close() - -scan.end() diff --git a/script/MgE_plus.py b/script/MgE_plus.py deleted file mode 100644 index 6a10a48..0000000 --- a/script/MgE_plus.py +++ /dev/null @@ -1,27 +0,0 @@ -#Script imported from: MgE_plus.xml - -#Pre-actions -cawait('ACOAU-ACCU:OP-MODE', 'Light Available', type = 's') -caput('X07MA-ID:MODE', 'CIRC +') -time.sleep(1.0) -cawait('X07MA-ID:DONE', 'DONE', type = 's') -caput('X07MA-ID:ENERGY-OFFS', '-9.0') -cawait('X07MA-ID:DONE', 'DONE', type = 's') -caput('E1', '1290') -caput('E2', '1340') -caput('TIME', '2') -caput('FOLDER', '2015_04/20150417') -caputq('X07MA-PHS-E:GO.A', '1290') -cawait('X07MA-PHS:alldone', '1', type = 's') -time.sleep(0.5) -caput('FILE', 'MgE_plus') -time.sleep(0.1) -caput('X07MA-OP-VG13:WT_SET', 'Try open') -time.sleep(5.0) -caput('X07MA-OP-VG13:WT_SET', 'Try open') -time.sleep(10.0) -caput('START', '1') - -#Post-actions -cawait('START', 'STOP', type = 's') -time.sleep(2.0) diff --git a/script/local.py b/script/local.py index 87ac07e..3f00f7f 100644 --- a/script/local.py +++ b/script/local.py @@ -1,34 +1,7 @@ -energy = None -class SimulatedEnergy(Writable): - def getName(self): - return "Energy" - - def write(self, value): - self.put(value) - - def put(self, value, timeout = None): - global energy - energy = value - - def close(self): - pass - - -class SimulatedEnergyReadback(Readable): - def getName(self): - return "Energy Readback" - - def read(self): - global energy - return energy; - - def get(self): - return self.read() - - def close(self): - pass - -sim_energy = SimulatedEnergy() -sim_energy_readback = SimulatedEnergyReadback() - - +################################################################################################### +# Deployment specific global definitions - executed after startup.py +################################################################################################### + + +#Uncomment this line to create the simulated devices needed to the tutorial scripts. +#run("tutorial/devices") \ No newline at end of file diff --git a/script/tutorial/01_LineScan.py b/script/tutorial/01_LineScan.py new file mode 100644 index 0000000..5c38a31 --- /dev/null +++ b/script/tutorial/01_LineScan.py @@ -0,0 +1,25 @@ +""" +Demonstrate the use of Line Scan: one or multiple positioners move together linearly. +""" + +#This optional preference limits the displayed plots +#set_preference(Preference.ENABLED_PLOTS, [ai1, ai2,]) + +#This optional preference displays wf1 as a 1d plot at each scan point, instead of a matrix plot +#set_preference(Preference.PLOT_TYPES, {wf1:1}) + +#Execute the scan: 200 steps, a1 from 0 to 40 +a= lscan(ao1, (ai1,ai2,wf1,im1), 0, 40, 200, 0.01) + +#Alternative: Steps of size 0.1, a1 from 0 to 40 +#a= lscan(ao1, (ai1,ai2,wf1,im1), 0, 40, 0.5, 0.01) + +#2 positioners moving together in 200 steps, a1 from 0 to 40 and a2 from 0 to 100 +#a= lscan((ao1,ao2), (ai1,ai2,wf1,im1), (0, 0), (40, 100), 200, 0.01) + +#Setting attributes to the scan group +path = get_current_data_group() +set_attribute(path, "AttrString", "Value") +set_attribute(path, "AttrInteger", 1) +set_attribute(path, "AttrDouble", 2.0) +set_attribute(path, "AttrBoolean", True) diff --git a/script/tutorial/02_ScanCallbacks.py b/script/tutorial/02_ScanCallbacks.py new file mode 100644 index 0000000..c356f5f --- /dev/null +++ b/script/tutorial/02_ScanCallbacks.py @@ -0,0 +1,20 @@ +""" +Demonstrate use of scan callbacks to trigger a detector at falling edge. +""" + +def BeforeReadout(): + ao1.write(1) + ao1.write(0) + + #Example with an epics direct channel access + #caput("CHANNEL_NAME", 1) + #caput("CHANNEL_NAME", 0) + +index=0 + +def AfterReadout(): + global index + print "Aquired frame: " + str(index) + index=index+1 + +a= lscan((m1,m2), (ai1, ai2), (0,0), (4,40), steps=20, latency = 0.01, before_read=BeforeReadout, after_read=AfterReadout) \ No newline at end of file diff --git a/script/tutorial/03_ManipulatingScanData.py b/script/tutorial/03_ManipulatingScanData.py new file mode 100644 index 0000000..adc958d --- /dev/null +++ b/script/tutorial/03_ManipulatingScanData.py @@ -0,0 +1,21 @@ +""" +Processing and plotting scan data. +""" + +ao1.write(0.0) +scan1= lscan(ao1, (ai1,ai2,wf1), 0, 40, 40, 0.01, False, "Scan 1") +scan2= lscan(ao1, (ai1,ai2,wf1), 0, 40, 40, 0.01, False, "Scan 2") + + +from operator import add +result = map(add, scan1.getReadable(0), scan2.getReadable(0)) + +#Alternative: +#result=[] +#for i in range(len(scan1.records)): +# result.append(scan1.records[i].values[0]+scan2.records[i].values[0]) + + +plot(result) +print result + diff --git a/script/tutorial/04_AreaScan.py b/script/tutorial/04_AreaScan.py new file mode 100644 index 0000000..9f594e3 --- /dev/null +++ b/script/tutorial/04_AreaScan.py @@ -0,0 +1,12 @@ +""" +Area Scan: Multiple positioners, each one is one dimension. +""" + +#This optional preference displays wf1 as a 1d plot at each scan point, instead of a matrix plot +#set_preference(Preference.PLOT_TYPES, {wf1:1}) + +#The second sensor is an array. In the plot window it is overwritten in every same x position. +#The data window never displays 3d data, but the 3d data can be accesses during the scan in the Data tab. +ascan((m1,m2), (ai1,wf1), (0.0,0.0), (2.0,1.0), (20,20)) + + diff --git a/script/tutorial/05_RelativeScan.py b/script/tutorial/05_RelativeScan.py new file mode 100644 index 0000000..8809d6a --- /dev/null +++ b/script/tutorial/05_RelativeScan.py @@ -0,0 +1,12 @@ +""" +Demonstrate use of Relative Line Scan. +The arguments start and end are relative to the current position. +After the scan the positioner(s) move back to the initial position. +""" + +print "Initial position = " + str(m1.position) + +a= lscan(m1, (ai1,ai2,wf1,im1), start = -2, end =2, steps = 20, relative = True) + + +print "Final position = " + str(m1.position) \ No newline at end of file diff --git a/script/tutorial/06_VectorScan.py b/script/tutorial/06_VectorScan.py new file mode 100644 index 0000000..a845c2d --- /dev/null +++ b/script/tutorial/06_VectorScan.py @@ -0,0 +1,22 @@ +""" +Demonstrate use of Vector Scan: one or multiple positioners set according to a position vector. +""" + +#1D vector scan, plot to 1D Vector tab +vector = [ 1, 3, 5, 10, 25, 40, 45, 47, 49] +a= vscan(ao1,(ai1,ai2),vector,False, 0.5, context = "1D Vector") + + + + +#2D vector scan, plot to 2D Vector tab +vector = [ [1,1] , [1,2] , [1,3] , [1,4] , + [1.5,2.5] , + [2,1] , [2,2] , [2,3] , [2,4] , + [2.5,2.5] , + [3,1] , [3,2] , [3,3] , [3,4] ] + +a= vscan((m1,m2),(ai1,ai2),vector,False, 0.1, context = "2D Vector") + + + diff --git a/script/tutorial/07_MathFit.py b/script/tutorial/07_MathFit.py new file mode 100644 index 0000000..5ba916a --- /dev/null +++ b/script/tutorial/07_MathFit.py @@ -0,0 +1,59 @@ +""" +Function fitting and peak search with mathutils.py +!!! Require commons-math3-*.jar in the extensions folder!!! +""" + +from mathutils import fit_polynomial,fit_gaussian, fit_harmonic, calculate_peaks +from mathutils import PolynomialFunction, Gaussian, HarmonicOscillator +import math + + +start = 0 +end = 10 +step_size = 0.1 + +result= lscan(ao1,ai1,start,end,[step_size,],0.01) + +readable = result.getReadable(0) +positions = result.getPositions(0) + +def get_function_data(function, start, end, resolution): + ret = [] + for x in frange(start, end, resolution, True): + fit_polinomial.append(function.value(x)) + + +pars_polynomial = (a0, a1, a2, a3, a4, a5, a6) = fit_polynomial(readable, positions, 6) +fitted_polynomial_function = PolynomialFunction(pars_polynomial) +print pars_polynomial + +(normalization, mean, sigma) = fit_gaussian(readable, positions, True) +fitted_gaussian_function = Gaussian(normalization, mean, sigma) +print (normalization, mean, sigma) + +(amplitude, angular_frequency, phase) = fit_harmonic(readable, positions) +fitted_harmonic_function = HarmonicOscillator(amplitude, angular_frequency, phase) +print (amplitude, angular_frequency, phase) + + +resolution = step_size/100 +fit_polinomial = [] +fit_gaussian = [] +fit_harmonic = [] +for x in frange(start,end,resolution, True): + fit_polinomial.append(fitted_polynomial_function.value(x)) + fit_gaussian.append(fitted_gaussian_function.value(x)) + fit_harmonic.append(fitted_harmonic_function.value(x)) +x = frange(start, end+resolution, resolution) + + +peaks = calculate_peaks(fitted_polynomial_function) + +plots = plot([readable, fit_polinomial, fit_gaussian, fit_harmonic] , + ["data", "polinomial", "gaussian", "harmonic"], xdata = [positions,x,x,x], context="Data") + +for p in peaks: + print "Max: " + str(p) + plots[0].addMarker(p, None, "Max=" + str(round(p,2)), None) +import java.awt.Color +plots[0].addMarker(mean, None, "Mean=" + str(round(mean,2)), java.awt.Color.LIGHT_GRAY) \ No newline at end of file diff --git a/script/tutorial/08_MathMultipleGaussians.py b/script/tutorial/08_MathMultipleGaussians.py new file mode 100644 index 0000000..f217a01 --- /dev/null +++ b/script/tutorial/08_MathMultipleGaussians.py @@ -0,0 +1,38 @@ +""" +Multiple Gaussians peak search +!!! Require commons-math3-*.jar in the extensions folder!!! +""" + +from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list + +start = 0 +end = 50 +step_size = 0.2 + +result= lscan(ao1,ai1,start,end,[step_size,]) + +readable = result.getReadable(0) +positions = result.getPositions(0) + +threshold = (min(readable) + max(readable))/2 +min_peak_distance = 5.0 + +peaks = estimate_peak_indexes(readable, positions, threshold, min_peak_distance) +print "Peak indexes: " + str(peaks) +print "Peak x: " + str(map(lambda x:positions[x], peaks)) +print "Peak y: " + str(map(lambda x:readable[x], peaks)) + + + +gaussians = fit_gaussians(readable, positions, peaks) + + +plots = plot([readable],["sin"],[positions], context="Data" ) +for i in range(len(peaks)): + peak = peaks[i] + (norm, mean, sigma) = gaussians[i] + if abs(mean - positions[peak]) < min_peak_distance: + print "Peak -> " + str(mean) + plots[0].addMarker(mean, None, "N="+str(round(norm,2)), None) + else: + print "Invalid gaussian fit: " + str(mean) diff --git a/script/tutorial/09_PseudoDevices.py b/script/tutorial/09_PseudoDevices.py new file mode 100644 index 0000000..9f655d0 --- /dev/null +++ b/script/tutorial/09_PseudoDevices.py @@ -0,0 +1,26 @@ +""" +Using pseudo-device to : + - Add calculations to scan data. + - Execute logic during scan +""" + +class Clock(Readable): + def read(self): + return time.clock() + +class Averager(Readable): + def read(self): + arr = wf1.take() #Gets the CACHED waveform + return reduce(lambda x, y: x + y, arr) / len(arr) + +class Positioner(Writable): + def write(self,pos): + print "Step = " + str(pos) + +averager=Averager() +clock=Clock() +positioner=Positioner() + +a= lscan((ao1,positioner),(ai2,wf1,averager,clock),(0,0),(40,20),20,0.1) + + diff --git a/script/tutorial/10_DeviceListener.py b/script/tutorial/10_DeviceListener.py new file mode 100644 index 0000000..7cec0cc --- /dev/null +++ b/script/tutorial/10_DeviceListener.py @@ -0,0 +1,25 @@ +""" +Create a device listener to interrupt the scan +""" +import java.lang.InterruptedException + +class Listener (DeviceListener): + def onStateChanged(self, device, state, former): + pass + def onValueChanged(self, device, value, former): + if value > 1.01: + print "Value over limit-> aborting" + abort() + +listener = Listener() + +ai1.addListener(listener) +try: + lscan(ao1, (ai1), 0, 40, 200, 0.01) +except java.lang.InterruptedException: + print "Aborted" +finally: + ai1.removeListener(listener) + + + diff --git a/script/tutorial/11_ParametersAndReturn.py b/script/tutorial/11_ParametersAndReturn.py new file mode 100644 index 0000000..e5dda01 --- /dev/null +++ b/script/tutorial/11_ParametersAndReturn.py @@ -0,0 +1,22 @@ +""" +Settign script parameters and return value +""" + + +#Providing an array of global variables +#run ("tutorial/11_ParametersAndReturn", {"start":10.0, "end":50.0, "step":40}) + +#Providing the locals dictionary +# The parameters are not set as globals, and nor script definitions +#run ("tutorial/11_ParametersAndReturn", locals={"start":10.0, "end":50.0, "step":40}) + +#Setting sys.argv: +#run ("tutorial/11_ParametersAndReturn", [10.0, 50.0, 40]) +#start = sys.argv[0] +#end = sys.argv[1] +#step = sys.argv[2] + + +a= lscan(ao1, ai1, start, end, step, 0.1) +a.getReadable(0) +set_return(a.getReadable(0)) \ No newline at end of file diff --git a/script/tutorial/12_ManualScan.py b/script/tutorial/12_ManualScan.py new file mode 100644 index 0000000..50d9a05 --- /dev/null +++ b/script/tutorial/12_ManualScan.py @@ -0,0 +1,33 @@ +""" +Manual scan: Manually setting positioners and reading back sensors, but still using +the standard data handling and plotting of built-in scans. +""" + +MOTOR_RANGE = (0.0, 8.0) +OUTPUT_SETPOINTS = (1.0, 2.0, 3.0) +FIXED_X = True + + +writables_names = [m1.getName(), ao1.getName()] +readable_names = [ai1.getName(), ai2.getName()] +start = [ MOTOR_RANGE[0] if FIXED_X else -1, OUTPUT_SETPOINTS[0]] +stop = [ MOTOR_RANGE[1] if FIXED_X else -1, OUTPUT_SETPOINTS[-1]] +steps = [int(MOTOR_RANGE[1]-MOTOR_RANGE[0]), len(OUTPUT_SETPOINTS)-1 if FIXED_X else -1] + +scan = ManualScan(writables_names, readable_names ,start, stop, steps) + + +#This option is to plot the foe each output value one 1D series, intead of all in a matrix plot +set_preference(Preference.PLOT_TYPES, {ai1:1,ai2:1}) + + +scan.start() +m1.setSpeed(10.0) +for setpoint1 in frange(MOTOR_RANGE[0], MOTOR_RANGE[1], 1.0, True): + m1.move(setpoint1) + for setpoint2 in OUTPUT_SETPOINTS: + ao1.write(setpoint2) + scan.append ([setpoint1, setpoint2], [m1.read(), ao1.read()], [ai1.read(), ai2.read()]) + + +scan.end() diff --git a/script/tutorial/13_CustomPlot.py b/script/tutorial/13_CustomPlot.py new file mode 100644 index 0000000..3d9d970 --- /dev/null +++ b/script/tutorial/13_CustomPlot.py @@ -0,0 +1,19 @@ +""" +Custom plot: Example of creating a 1D plot for a 2D scan where each scanned row is a series + +""" + +#Setting the 1d preference would create in the place of the matrix plot, a 1d plot where +#each scanned column is a series +#set_preference(Preference.PLOT_TYPES, {'ai1':1}) + + + +p = plot(None, context="1d Plot")[0] +def AfterReadout(record, scan): + if record.setpoints[1] == scan.getStart()[1]: + p.addSeries(LinePlotSeries(str(record.positions[0]))) + p.getSeries(p.numberOfSeries-1).appendData(record.positions[1], record.values[0]) + + +ascan((ao1,ao2), (ai1), (0,10), (20,30), (20,20), 0.1, after_read=AfterReadout) \ No newline at end of file diff --git a/script/tutorial/14_DataManipulation.py b/script/tutorial/14_DataManipulation.py new file mode 100644 index 0000000..9478b3e --- /dev/null +++ b/script/tutorial/14_DataManipulation.py @@ -0,0 +1,69 @@ +""" +Data Manipulation: Using the data access API to generate and retrieve data + +""" + +#Creating a 1D dataset from an array +path="group/data1" +data1d = [1.0, 2.0, 3.0, 4.0, 5.0] +save_dataset(path, data1d) +#Reading ii back +read =load_data(path) +print read.tolist() +assert data1d==read.tolist() +plot(read) + +#Creating a 2D dataset from an array with some attributes +data2d = [ [1.0, 2.0, 3.0, 4.0, 5.0], [2.0, 3.0, 4.0, 5.0, 6.0, ], [3.0, 4.0, 5.0, 6.0, 7.0]] +path="group/data2" +save_dataset(path, data2d) +set_attribute(path, "AttrString", "Value") +set_attribute(path, "AttrInteger", 1) +set_attribute(path, "AttrDouble", 2.0) +set_attribute(path, "AttrBoolean", True) +#Reading it back +read =load_data(path) +print read.tolist() +plot(read) + +#Creating a 3D dataset from an array +data3d = [ [ [1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7]], [ [3,2,3,4,5], [4,3,4,5,6], [5,4,5,6,7]]] +path="group/data3" +save_dataset(path, data3d) +#Reading it back +read =load_data(path,0) +print read.tolist() +read =load_data(path,1) +print read.tolist() + +#Creating a INT dataset adding elements one by one +path = "group/data4" +create_dataset(path, 'i') +for i in range(10): + save_data_item(path,i) + + +#Creating a 2D data FLOAT dataset adding lines one by one +path = "group/data5" +create_dataset(path, 'd', False, (0,0)) +for row in data2d: + save_data_item(path, row) + + +#Creating a Table (compund type) +path = "group/data6" +names = ["a", "b", "c", "d"] +types = ["d", "d", "d", "[d"] +lenghts = [0,0,0,5] +dims = [0,0,0,0] +table = [ [1,2,3,[0,1,2,3,4]], + [2,3,4,[3,4,5,6,7]], + [3,4,5,[6,7,8,9,4]] ] +create_table(path, names, types, lenghts, dims) +for row in table: + save_table_item(path, row) +flush_data() +#Read it back +read =load_data(path) +print read + diff --git a/script/tutorial/15_Pararellization.py b/script/tutorial/15_Pararellization.py new file mode 100644 index 0000000..e2d35f5 --- /dev/null +++ b/script/tutorial/15_Pararellization.py @@ -0,0 +1,51 @@ +""" +Using Pararellization API to execute tasks concurrently + +""" +import traceback + +#Simple parallization +def task1(): + m1.moveRel(1.0) + return m1.getPosition() + +def task2(): + m2.moveRel(1.0) + return m1.getPosition() + +def task3(): + return ai1.read() + +ret = parallelize(task1, task2, task3) +print ret + + +#Fork amd join +ret = fork(task1, task2, task3) +print ai1.read() +ret = join(ret) +print ret + + + +#Functions with parameters +def moveRelative(motor, step): + print "Moving " + motor.getName() + " step = " + str(step) + motor.moveRel(step) + return motor.getPosition() + +ret = parallelize((moveRelative,(m1,-2)), (moveRelative,(m2,-2))) +print ret + + +#Exception in parallel task is thrown back to script +try: + parallelize((moveRelative,(ai1,1)), (moveRelative,(ai2,1))) +except: + print "Ok, caught exception:" + traceback.print_exc() + + + + + diff --git a/script/tutorial/16_SimultaneousScans.py b/script/tutorial/16_SimultaneousScans.py new file mode 100644 index 0000000..4fe0c11 --- /dev/null +++ b/script/tutorial/16_SimultaneousScans.py @@ -0,0 +1,15 @@ +""" +Example on running simultaneous scans. They should not manipulate same writables +""" + + +def scan1(): + print "scan1" + return lscan(ao1, ai1, 0, 40, 20, 0.1, context = "scan1") + +def scan2(): + print "scan2" + return lscan(ao2, wf1, 0, 40, 20, 0.1, context = "scan2") + + +parallelize(scan1, scan2) diff --git a/script/tutorial/17_DirectEpicsAccess.py b/script/tutorial/17_DirectEpicsAccess.py new file mode 100644 index 0000000..3522d24 --- /dev/null +++ b/script/tutorial/17_DirectEpicsAccess.py @@ -0,0 +1,36 @@ +""" +EPICS direct channel access. +EPICS devices implemented are included in PShell, package ch.psi.pshell.epics. +However direct channel access builtin functions are available. +""" + +channel_name = "TESTIOC:TESTCALCOUT:Output" + +#reading/writing to a channel +print (caget(channel_name)) +caput(channel_name, 0.0) +#Put with no wait +caput(channel_name, 0.0) +print (caget(channel_name)) + +#waiting for a channel valur +cawait(channel_name, 0.0, timeout = 10.0) + +#If many IO it is better to keep the same CA connection +channel = Channel(channel_name, 'd') +for i in range(100): + print channel.get() + +#In order to use in a scan we need to implement Readable/Writable interfaces. +#A wripper device can be created as: +channel = create_channel_device(channel_name, 'd') +lscan(channel, ai2, 0, 10, 0.1) + +#Or else we can use ch.psi.pshell.epics +import ch.psi.pshell.epics.ChannelDouble as ChannelDouble +channel = ChannelDouble("My Channel", channel_name) +channel.initialize() +lscan(channel, ai2, 0, 10, 0.1) + + + diff --git a/script/tutorial/18_Imaging.py b/script/tutorial/18_Imaging.py new file mode 100644 index 0000000..b7f2a8c --- /dev/null +++ b/script/tutorial/18_Imaging.py @@ -0,0 +1,21 @@ +import ch.psi.pshell.imaging.Filter as Filter +from ch.psi.pshell.imaging.Utils import * + + +class MyFilter(Filter): + def process(self, image, data): + image = grayscale(image) + image = blur(image) + image = sobel(image) + return image + +#Setting the filter to a source +src1.setFilter(MyFilter()) + +#Creating a new source with the filter +src2.setFilter(None) +add_image_source(MyFilter("f1"), True) +#f1.passive = True +src2.addListener(f1) + + diff --git a/script/tutorial/19_ContinuousScan.py b/script/tutorial/19_ContinuousScan.py new file mode 100644 index 0000000..0aed640 --- /dev/null +++ b/script/tutorial/19_ContinuousScan.py @@ -0,0 +1,15 @@ +""" +Demonstrate the use of Continuous Scan Scan: a Linear Scan with continuous motor move and +sampling on the fly. +""" + +#A single motor at current speed +a= cscan(m1, (ai1,ai2), -2, 3 , steps=100, relative=True) + + +#A single motor in a given time +a= cscan(m1, (ai1,ai2), -2.0, 3.0, steps=100 ,time = 4.0, relative=True) + +#Multiple motors in a given time +a= cscan((m1, m2), (ai1,ai2), (-2.0, -3), (3.0, 5.0), steps=100,time = 4.0, relative=True) + diff --git a/script/tutorial/devices.py b/script/tutorial/devices.py new file mode 100644 index 0000000..42ce7cc --- /dev/null +++ b/script/tutorial/devices.py @@ -0,0 +1,175 @@ +import random +import ch.psi.pshell.device.DummyMotor as DummyMotor +import ch.psi.pshell.device.DummyRegister as DummyRegister +import ch.psi.pshell.device.RegisterBase as RegisterBase +import ch.psi.pshell.device.ReadonlyRegisterBase as ReadonlyRegisterBase +import ch.psi.pshell.device.ReadonlyRegister.ReadonlyRegisterArray as ReadonlyRegisterArray +import ch.psi.pshell.device.ReadonlyRegister.ReadonlyRegisterMatrix as ReadonlyRegisterMatrix +import ch.psi.pshell.imaging.RegisterMatrixSource as RegisterMatrixSource + + +#################################################################################################### +# Simulated Devices +#################################################################################################### + +class AnalogOutput(RegisterBase): + def doRead(self): + return self.val if hasattr(self, 'val') else 0.0 + + def doWrite(self, val): + self.val = val + +class AnalogInput(ReadonlyRegisterBase): + def doRead(self): + time.sleep(0.01) + self.val = to_array(self.calc(), 'd') + return self.val + +class Waveform(ReadonlyRegisterBase, ReadonlyRegisterArray): + def doRead(self): + time.sleep(0.01) + self.val = to_array(self.calc(), 'd') + return self.val + + def getSize(self): + return len(self.take(-1)) #only reads if cache is None + +class Image(ReadonlyRegisterBase, ReadonlyRegisterMatrix): + def doRead(self): + time.sleep(0.01) + self.val = to_array(self.calc(), 'd') + return self.val + + def getWidth(self): + return len(self.take(-1)[0]) + + def getHeight(self): + return len(self.take(-1)) + + + +class Random(AnalogInput): + def calc(self): + return random.random() + + +class SinusoidSample(AnalogInput): + def calc(self): + self.x = self.x + 0.1 if hasattr(self, 'x') else 0.0 + noise = (random.random() - 0.5) / 10.0 + return math.sin(self.x) + noise + +class SinusoidTime(AnalogInput): + def calc(self): + noise = (random.random() - 0.5) / 10.0 + return math.sin(time.time()) + noise + + +class SinusoidWaveform(Waveform): + def calc(self): + ret = [] + x = random.random() + for i in range (20): + ret.append(math.sin(x)) + x = x + 0.1 + return ret + +class SinusoidImage(Image): + def calc(self): + (width, height) = (200, 100) + ret = [] + x = random.random(); + base = [] + for i in range (width): + base.append( math.sin(x)) + x = x + 0.05 + for i in range (height): + noise = (random.random() - 0.5)/5.0 + ret.append([x+noise for x in base]) + return ret + + +#Defintion +add_device(DummyMotor("m1"), True) +add_device(DummyMotor("m2"), True) +add_device(DummyRegister("reg1",3), True) +add_device(AnalogOutput("ao1"), True) +add_device(AnalogOutput("ao2"), True) +add_device(SinusoidSample("ai1"), True) +add_device(SinusoidTime("ai2"), True) +add_device(Random("ai3"), True) +add_device(SinusoidWaveform("wf1"), True) +add_device(SinusoidImage("im1"), True) + + +#Update +m1.setMonitored(True) +m2.setMonitored(True) + + + + +#################################################################################################### +# Simple Readable / Writable objects can be created and used in scans +#################################################################################################### +class WritableScalar(Writable): + def write(self, value): + pass + +class ReadableScalar(Readable): + def read(self): + return random.random() + + +class ReadableWaveform(ReadableArray): + def getSize(self): + return 20 + + def read(self): + ret = [] + for i in range (self.getSize()): + ret.append(random.random()) + return ret + +class ReadableImage(ReadableMatrix): + def read(self): + ret = [] + for i in range (self.getHeight()): + ret.append([random.random()] * self.getWidth()) + return to_array(ret, 'd') + + def getWidth(self): + return 80 + + def getHeight(self): + return 40 + + + +ws1 = WritableScalar() +rs1 = ReadableScalar() +rw1 = ReadableWaveform() +ri1 = ReadableImage() + + +#################################################################################################### +# Imaging +#################################################################################################### + +configured = os.path.exists(Device.getConfigFileName("src1")) + +add_image_source(RegisterMatrixSource("src1", im1), True) +add_image_source(RegisterMatrixSource("src2", ri1), True) + +#Some configuration for so the imaging will work out of the box +if not configured: + import ch.psi.pshell.imaging.Colormap + src1.config.dataPolling = 100 + src1.config.colormapAutomatic = True + src1.config.colormap = ch.psi.pshell.imaging.Colormap.Temperature + src1.config.save() + src2.config.dataPolling = 100 + src2.config.colormapAutomatic = True + src2.config.save() + +