[WIP] PEN Scintillation Project Signal Analysis & Data Taking
PENAnalysisTools.jl
andPENAnalysisToolsLuis.jl
have been merged toPENScintAnalysis.jl
.PENScintAnalysis.jl
andPENBBControl.jl
have been merged. [06/2022]- Dark box control: so far, the XIMC motorised stages, HV control and Struck data taking are part of the package.
- Data analysis: handling Struck raw data, converting to LEGEND HDF5 (read & write)
A few packages required for PENScintAnalysis.jl
are not registered. These can be found here:
https://github.com/oschulz/StruckVMEDevices.jl#SIS3316Digitizers
https://github.com/oschulz/CompressedStreams.jl
For LEGEND software, add the LEGEND Julia registry: https://github.com/legend-exp/LegendJuliaRegistry
Then add LegendHDF5IO
and LegendDataTypes
.
There are two ways to read `.dat files now:
read_data_from_struck(filename::String; just_evt_t=false)
returnsTypedTable
read_raw_data(filename::String; nevents::Int=typemax(Int))
returnsDataFrame
Both accept a single string as input or an array of strings for the file paths. In case you use the array, the function returns one TypedTable/DataFrame consisting of all data!
read_old_h5_structure(filename::String; nevents::Int=typemax(Int), nsubfiles::Int=typemax(Int), subfiles=[])
Reads the outdated dataformat. Outdated means non-LegendHDF5IO compatible. You can see what is in one of those files by using get_h5_info_old(filename::String)
.
filename::String
: Path to *.h5 file with old formatting as a string.nevents::Int
: Number of events to read in. Default: all events.nsubfiles::Int
: Number of subfiles to read in. Default: all.subfiles
: Array of indices of subfiles to read in. Default: empty = all.
filename = "path/to/h5/file.h5"
file_info = get_h5_info_old(filename)
for i in eachindex(file_info["names"])
data = read_old_h5_structure(filename, subfiles=[i])
# Do analysis separate for each subfile to avoid OutOfMemory() issues
end
You can directly convert *.dat
files to *.h5
by using:
struck_to_h5(filename::String; conv_data_dir="../conv_data/")
Or you read in the data as before and store it using writeh5(filename::String, tt)
where tt
is your output from read_data_from_struck()
.
Please note that you can't store an array of vectors/arrays in HDF5! You have to convert that array with VectorOfArrays(ARRAY)
first.
Use:
take_struck_data(settings::NamedTuple)
Creates an individual pmt_daq.scala
file and takes data which are converted to a HDF5 file afterwards.
settings::NamedTuple
: NamedTuple containing all settings. See Example.
settings = (
fadc = "gelab-fadc08", # Your Struck device
output_basename = "test-measurement",
data_dir = "../data/", # where you want to store the raw data (*.dat)
conv_data_dir = "../conv_data/", # where you want to store the converted data (*.h5)
measurement_time = 20,
number_of_measurements = 5, # rather take more measurements instead of creating huge files
channels = [1,2,3,4,5,6],
trigger_threshold = [55], # in ADC
trigger_pmt = [5,6],
peakTime = 2,
gapTime = 2,
nPreTrig = 192,
nSamples = 256,
saveEnergy = true, # actually not implemented
delete_dat = true # delete the raw data file after converting
)
To start the connection to the motors, use motor = mymotor()
. It will automatically save the settings needed for the motors. They will be initialized when starting the connection, but can always be intialized by calling Initialize(motor)
. This overwrites the settings which might have changed after a power outage.
To calibrate the motors, i.e. to set the 0 to the end of the motor stage at the bottom left of the setup, the functions CalibrateX
and CalibrateY
are used.
For example, CalibrateX(motor)
calibrates the X-motor. If both motors should be calibrated, call Calibrate(motor)
.
To move the motors, the commands XMoveMM
and YMoveMM
are used. These functions take as arguments the position in mm and the motor.
For example XMoveMM(15,motor)
moves the X-motor to 15mm. This function blocks the program until the final destination is reached.
To avoid the block, call the function with the keyword argument XMoveMM(15,motor,block_till_arrival = false)
.
To get the position of the motors, call PosX(motor)
and PosY(motor)
. They are given in units of mm. To print it to the terminal, Pos(motor)
can be used. Note that the value at 0 has a negative sign, as the motor stage coordinates are inverted during the conversion to mm.
# Initialize
motor = mymotor()
Calibrate(motor)
# Get current position
pos_x = PosX(motor)
pos_y = PosY(motor)
@info(pos_x, pos_y)
# Move stage to x = 42, y = 24 in units of mm
XMoveMM(42.0,motor)
YMoveMM(24.0,motor)
When changing the connection of the motors to the serial hub (or using a different serial hub), please use:
device = "gelab-serialXX"
ports = [2001, 2011]
motor = mymotor(device, ports)
The HV supply for the PMTs can be controlled as follows:
Define the login details to establish the connection:
login_payload = JSON.json(Dict("i"=>"", "t" => "login", "c"=> Dict("l"=>"USERNAME", "p"=>"PASSWORD", "t" => ""), "r" => "websocket"))
ip = "ws://xxx.xxx.xxx.xxx:8080"
Basic controls
# Get all measured voltages
get_measured_HV(ip)
# Get all set voltages (to compare set and measured)
get_set_HV(ip)
# Set voltage (value) to one channel
voltage_goto(ip, channel::Int, value::Real)
# e.g. set channel 2 to -975 V
voltage_goto(ip, 2, -975)
To start a scan with the stage you have available 3 options:
PENBBScan2D(x_start, y_start, step_x, step_y, x_ends, y_ends, HolderName::String, time_per_point)
.
This function can used to perform an automate scan in 2D (x,y axis)
This function requires as input the starting point (x_start,y_start), and the end point (x_ends,y_ends) as well
as the step sizes in both axis(step_x,step_y). All values are in mm. The range specified muss be in the interval x in [0.0,100.0]
, y in [0.0,100.0]
In addition you can specify the name of the holder or sample and time of data taking for each position
PENBBScan2D(x_start, y_start, step_x, step_y, x_ends, y_ends, HolderName::String, time_per_point).
Example: PENBBScan2D(0.0,0.0,20.0,20.0,40.0,40.0,"small",2)
will do a scan in the rectangle x: 0.0->40 mm; y: 0.0 -> 40 mm with steps of 20. mm in each direction
x_start
: intial point in xy_start
: intial point in ystep_x
: step size in xstep_y
: step size in yx_ends
: final point in xy_ends
: final point in yHolderName::String
: name of the holder of piece you are scanningtime_per_point
: time of data taking in each point.
The next funtions will do a 1D scan.
PENBBScan1DY(x_start, y_start, step_y, y_ends, HolderName::String, time_per_point)
PENBBScan1DX(y_start, x_start, step_x, x_ends, HolderName::String, time_per_point)