API

Modules

    Types and constants

    Functions and macros

    Documentation

    Juleanita.GeBandgapMethod
    GeBandgap(T::Real)

    bandgap energy (eV) of germanium as a function of temperature (K)

    \[E_\textrm{gap}(T) = 0.744 - \frac{4.774 \cdot 10^{-4} \cdot T^2}{T + 235}\]

    source
    Juleanita.Ge_Energy_per_eholePairMethod
    Ge_Energy_per_eholePair(T::Real)

    energy (eV) required to create an electron-hole pair in germanium as a function of temperature (K)

    \[E(T) = 2.2 \cdot E_\textrm{gap}(T) + 1.99 \cdot E_\textrm{gap}(T)^{3/2} \cdot \exp(4.75 \cdot \frac{E_\textrm{gap}(T)}{T})\]

    source
    Juleanita.V_to_electronsMethod
    V_to_electrons(Voltage_V::Real, capacitance_F::Real; gain::Real = 1.0)

    Convert voltage into a charge in electrons based on the capacitance of the system (could be pulser, detector, or combination).

    \[Q[e^{-}] = \frac{V}{\textrm{gain}} \cdot \frac{C_{\textrm{inj}}}{e^{-}}\]

    source
    Juleanita._ADC_to_VMethod
    _ADC_to_V(ADC::Real, dynamicrange_V::Real, bits::Int)

    Convert ADC-code from digitizer into voltage. The ADC-code is assumed to be in the range [0, 2^bits] corresponding to voltages within the dynamic range.

    \[V = \frac{V_{\textrm{dynamic range}}}{2^{\textrm{bits}}} \cdot \textrm{ADC}\]

    Inputs:

    • ADC: ADC-code from digitizer
    • dynamicrange_V: dynamic range of the DAQ in Volts
    • bits: number of bits of the ADC
    source
    Juleanita._ADC_to_electronsMethod
    _ADC_to_electrons(ADC::Real, capacitance_F::Real; bits::Int = 14, dynamicrange_V::Real = 2.0, gain::Real = 1.0)

    Convert ADC-code from pulser into injected charge in pulserADCto_electrons

    \[Q[e^{-}] = (\frac{V_{\textrm{dynamic range}}}{2^{\textrm{bits}}} \cdot \textrm{ADC}) \cdot \frac{1}{\textrm{gain}} \cdot \frac{C_{\textrm{inj}}}{e^{-}}\]

    Inputs:

    • ADC: ADC-code from digitizer
    • capacitance_F: capacitance of the system (could be pulser, detector, or combination) in Farad
    • bits: number of bits of the ADC
    • dynamicrange_V: dynamic range of the DAQ in Volts
    • gain: gain of the system
    source
    Juleanita._ADC_to_keVMethod
    pulser_ADC_to_keV(ADC::Real, capacitance_F::Real; bits::Int = 14, dynamicrange_V::Real = 2.0, gain::Real = 1.0)

    Convert ADC-code from pulser into injected energy in keV. Inputs:

    • ADC: ADC-code from digitizer
    • capacitance_F: capacitance of the system (could be pulser, detector, or combination) in Farad
    • bits: number of bits of the DAQ
    • dynamicrange_V: dynamic range of the ADC in Volts
    • gain: gain of the system
    source
    Juleanita._is_valid_datestrMethod
    _is_valid_datestr(timestr_file::String; timezone::String = "PT")

    check if the time string in the filename is a valid date string

    source
    Juleanita.csv_to_lh5Method

    csvtolh5(data::LegendData, period::DataPeriod, run::DataRun, category::DataCategoryLike, channel::ChannelId, csv_folder::String; heading::Int = 17, nwvfmax::Union{Int, Float64, Vector{Int64}} = NaN, nChannels::Int = 2, ti::ClosedInterval{<:Quantity} = 0.0u"µs".. 550.0u"µs")

    • converts csv files from oscilloscope to lh5 files
    • format of csv file matches the one from an oscilloscope...might be different for other systems
    • saves the lh5 files in the raw tier defined in "LEGENDDATACONFIG"

    INPUTS:

    • data::LegendData LegendData object. You need "LEGEND_DATA_CONFIG" to construct this. this will define later where .lh5 files are saved
    • period::DataPeriod data period that you want to assign your data to
    • run::DataRun data run that you want to assign your data to
    • category::DataCategoryLike data category that you want to assign your data to
    • channel::ChannelId channel id that you want to assign your data to
    • csv_folder::String folder where the csv files are located
    • csv_heading::Int number of lines to skip in csv file
    • nwvfmax::Union{Int, Float64, Vector{Int64}} number of waveforms to read OR vector of waveforms indices to read
    • nChannels::Int number of channels in csv files to read (supports only 1 or 2)
    • ti::ClosedInterval{<:Quantity} time interval to truncate the waveforms to
    • wpf::Int waveforms per files –> number of waveforms to write per .lh5 file
    source
    Juleanita.fit_linearityMethod
    fit_linearity(pol_order::Int, µ::AbstractVector{<:Union{Real,Measurement{<:Real}}}, peaks::AbstractVector{<:Union{Real,Measurement{<:Real}}}; pull_t::Vector{<:NamedTuple}=fill(NamedTuple(), pol_order+1), v_init::Vector = [], uncertainty::Bool=true )

    Fit the calibration lines with polynomial function of polorder order polorder == 1 -> linear function pol_order == 2 -> quadratic function

    Returns

    * `result`: NamedTuple with the following fields
        * `par`: best-fit parameters
        * `gof`: godness of fit
    * `report`:
    source
    Juleanita.noise_sweepFunction
    noise_sweep(filter_type::Symbol, wvfs::ArrayOfRDWaveforms, dsp_config::DSPConfig, τ_pz::Quantity{T}; ft::Quantity{T}= 0.0u"µs", τ_cusp::Quantity{<:AbstractFloat} = 10000000.0u"µs", τ_zac::Quantity{<:AbstractFloat} = 10000000.0u"µs" ) where T<:Real
    noise_sweep(filter_type::Symbol, wvfs::ArrayOfRDWaveforms, dsp_config::DSPConfig; kwargs... )

    Noise sweep function used in DSP filter optimizatio. The goal is to find the optimal rise-time (for a given flat-top time) which minimizes ENC noise. This is an alternative approach to dsp_trap_rt_optimization.

    Strategy:

    • Shift waveforms to have a common baseline, and deconvolute them with the pole-zero correction (in case τ_pz > 0.0u"µs" )
    • Filter waveforms with given rise-time and flat-top time
    • Build histogram out of all samples in baseline from all waveforms. Remove bins at the beginning and end of the waveform to avoid edge effects.
    • Calculate the RMS of the baseline noise –> ENC noise

    Inputs:

    • filter_type::Symbol: filter type (:trap or :cusp)
    • wvfs::ArrayOfRDWaveforms: raw waveforms to be filtered
    • dsp_config::DSPConfig: DSP configuration object containing relevant parameters: ft, grid_rt, bl_window, flt_length_cusp, flt_length_zac
    • τ_pz::Quantity{T}: pole-zero decay time. If τ_pz = 0.0u"µs" (or none given), no pole-zero correction is applied.

    kwargs:

    • ft::Quantity{T}: fixed flat-top time for optimization
    • τ_cusp::Quantity{<:AbstractFloat}: cusp decay time; only relevant for cusp filter
    • τ_zac::Quantity{<:AbstractFloat}: cusp decay time; only relevant for zac filter
    source
    Juleanita.process_ctcMethod
    process_ctc(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, ecal_config::PropDict, ctc_config::PropDict;
                energy_types::Vector{Symbol} = Symbol.(ctc_config.energy_types), reprocess::Bool = false)
    process_ctc(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; kwargs...)

    Calculate charge-trapping correction: by looking at correlation between drift time and energy. Save correction function to rpars. Inputs:

    • data::LegendData: LegendData object
    • period::DataPeriod: data period
    • run::DataRun: data run
    • category::Union{Symbol, DataCategory}: data category, e.g. :cal
    • channel::ChannelId: channel id
    • ecal_config::PropDict: energy calibration configuration. If not specified use default from metadata
    • ctc_config::PropDict: charge-trapping correction configuration. If not specified use default from metadata

    Optional:

    • energy_types::Vector{Symbol}: energy types to process
    • reprocess::Bool: reprocess the files or not
    • juleana_logo::Bool: add juleana logo to plots
    source
    Juleanita.process_decaytimeFunction
    process_decaytime(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, min_τ::Quantity{T}, max_τ::Quantity{T}, nbins::Int, rel_cut_fit::Real, peak::Symbol, bl_window::ClosedInterval{<:Unitful.Time{<:T}}, tail_window::ClosedInterval{<:Unitful.Time{<:T}}; reprocess::Bool = false) where T <: Real
    
    process_decaytime(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, pz_config::PropDict, bl_window::ClosedInterval{<:Unitful.Time{<:T}}, tail_window::ClosedInterval{<:Unitful.Time{<:T}}; kwargs...) where T <: Real
    
    process_decaytime(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, pz_config::PropDict, dsp_config::DSPConfig; kwargs...)
    
    process_decaytime(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; kwargs...)

    Goal: calculate decay time used for pole-zero correction Inputs:

    • data::LegendData: LegendData object
    • period::DataPeriod: data period
    • run::DataRun: data run
    • category::Union{Symbol, DataCategory}: data category, e.g. :cal
    • channel::ChannelId: channel id
    • min_τ::Quantity{T}: minimum decay time
    • max_τ::Quantity{T}: maximum decay time
    • nbins::Int: number of bins for histogram
    • rel_cut_fit::Real: relative cut for truncated gauss
    • peak::Symbol: peak to use for decay time calculation. Can also be :all to use all :raw instead of :jlpeaks tier
    • bl_window::ClosedInterval{<:Unitful.Time{<:T}}: baseline window
    • tail_window::ClosedInterval{<:Unitful.Time{<:T}}: tail window

    Optional:

    • reprocess::Bool: reprocess the files or not
    • juleana_logo::Bool: add juleana logo to plots
    source
    Juleanita.process_dspFunction
    process_dsp(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, dsp_config::DSPConfig, τ_pz::Quantity{<:Real}, pars_filter::PropDict; reprocess::Bool = false )  
    process_dsp(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId ; kwargs... )

    Goal:

    • run the DSP processing for all raw files in the given period, run, category and channel.
    • based on simple_dsp function
    • save the results in the jldsp tier
    • if reprocess is false, it will skip the files that are already processed

    INPUTS: - data::LegendData LegendData object. You need "LEGEND_DATA_CONFIG" to construct this, e.g. l200 = LegendData(:l200) - period::DataPeriod data period, e.g. DataPeriod(1) - run::DataRun data run, e.g. DataRun(1) - category::Symbol data category, e.g. DataCategory(:cal) - channel::ChannelId channel id, e.g. ChannelId(1) (depending on your data!) - dsp_config::DSPConfig DSP configuration object. If not specified will take default from metadata - τ_pz::Quantity{<:Real} decay time used for pole-zero correction. If not specified will take from rpars.pz - pars_filter::PropDict optimized filter parameters used in DSP. If not specified will take from rpars.fltopt

    KWARGS: - reprocess::Bool reprocess the files or not

    OUTPUTS: - save the DSP results in the jldsp tier - print the progress - print the completion message

    source
    Juleanita.process_energy_calibrationFunction
    process_energy_calibration(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, source::Symbol; reprocess::Bool = true, ecal_config::PropDict = data.metadata.config.energy.energy_config.default, e_types::Vector{<:Symbol} = [:e_trap, :e_cusp, :e_zac])

    perform energy calibration: take uncalibration energy values from dsp files and calibrate them using calibration sources INPUTS:

    • data::LegendData: LegendData object
    • period::DataPeriod: data period
    • run::DataRun: data run
    • category::Union{Symbol, DataCategory}: data category, e.g. :cal
    • channel::ChannelId: channel id
    • source::Symbol: calibration source. :th228 or :co60 are supported at the moment

    OPTIONAL:

    • reprocess::Bool: reprocess the files or not
    • ecal_config::PropDict: energy calibration configuration. if not specified, it will take the default from metadata
    • etypes::Vector{<:Symbol}: energy types to calibrate. default is [:etrap, :ecusp, :ezac]

    OUTPUT:

    • save the calibration parameters as json files to disk (in generated/par/rpars/ecal/...)
    • save the calibration plots to disk (in generated/jlplt/rplt/...)
    source
    Juleanita.process_filteroptFunction
    process_filteropt(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, dsp_config::DSPConfig, τ_pz::Quantity{T}, peak::Symbol; rt_opt_mode::Symbol = :blnoise, reprocess::Bool = false, filter_types::Vector{Symbol} = [:trap, cusp])
    process_filteropt(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; kwargs...)

    Filter optimization for filter_types

    • load waveforms from peakfile, shift baseline and pole-zero
    • optimize rise-time for minimum baseline noise after filtering
    • optimize flat-top time for FWHM of peak
    • save results to disk
    • sanity plots for rise-time and flat-top time optimization

    Inputs:

    • data::LegendData: LegendData object
    • period::DataPeriod: data period
    • run::DataRun: data run
    • category::Union{Symbol, DataCategory}: data category, e.g. :cal
    • channel::ChannelId: channel id

    Optional:

    • dsp_config::DSPConfig: DSP configuration object. If not specified will take default from metadata
    • τ_pz::Quantity{T}: pole-zero decay time. If not specified will take default from metadata
    • peak::Symbol: peak to optimize for (needs existing peakfile!). If not specified will take default from metadata
    • rt_opt_mode::Symbol: mode for rise-time optimization (:blnoise or :pickoff) –> two different strategies for optimization
    • reprocess::Bool: reprocess the files or not
    • filter_types::Vector{Symbol}: filter types to optimize for
    source
    Juleanita.process_hitMethod
    processing_hit(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; reprocess::Bool = false, e_types::Vector{<:Symbol} = [:e_trap, :e_cusp, :e_zac])
    • run the hit processing for all dsp files in the given period, run, category and channel.
    • apply energy calibration to the dsp energy estimator and save the results in the jlhit tier
    • no PSD at the moment, will be added in future
    • if reprocess is false, it will skip the files that are already processed

    INPUTS:

    • data::LegendData LegendData object
    • period::DataPeriod data period
    • run::DataRun data run
    • category::Union{Symbol, DataCategory} data category, e.g. :cal
    • channel::ChannelId channel id
    • reprocess::Bool reprocess the files or not
    • e_types::Vector{<:Symbol} energy types to process. default is [:etrap, :ecusp, :e_zac]

    OUTPUTS:

    • save the hit results in the jlhit tier
    source
    Juleanita.process_peak_splitFunction
    process_peak_split(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, ecal_config::PropDict, dsp_config::DSPConfig, qc_config::PropDict; reprocess::Bool = false)
    process_peak_split(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; kwargs...)

    Create peak files containting only waveforms from peaks in the calibration spectrum.

    1. Read raw data
    2. Find peaks in the calibration spectrum using rough energy estimate data_fk.daqenergy
    3. Do simple DSP for peaks only
    4. apply quality cuts based on simple DSP
    5. Save waveforms after QC to peak files

    inputs:

    • data: LegendData object
    • period: DataPeriod object
    • run: DataRun object
    • category: Symbol or DataCategory object, e.g. :cal for calibration
    • channel: ChannelId for germanium detector
    • ecal_config: PropDict, energy calibration configuration
    • dsp_config: DSPConfig, DSP configuration
    • qc_config: PropDict, quality cut configuration

    keyword arguments:

    reprocess: Bool, default is false

    Output:

    • h_uncals histograms of peaksearch
    • peakpos

    Also, peak files containting only waveforms from peaks in the calibration spectrum are saved to jlpeaks folder.

    source
    Juleanita.process_peakfitsFunction
    progress_peakfits(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; reprocess::Bool = true, e_types::Vector{<:Symbol} = [:e_trap, :e_cusp, :e_zac], juleana_logo::Bool = false)
    Process the peak fits for the benchtest data.
    source
    Juleanita.process_qualitycutsFunction
    process_qualitycuts(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; reprocess::Bool = false, qc_config::PropDict = data.metadata.config.qc.qc_config.default)

    apply quality cuts based on dsp parameters inputs: data: LegendData object period: DataPeriod object run: DataRun object category: Symbol or DataCategory object channel: ChannelId object reprocess: Bool, default false qcconfig: PropDict, default data.metadata.config.qc.qcconfig.default

    source
    Juleanita.read_csv_metadataMethod
    read_csv_metadata(filepath::String; heading::Int = 17, nChannels::Int = 2, timezone = "PT")

    read metadata from a csv file (as taken from oscilloscope) input:

    • filepath::String: file name
    • heading::Int: number of lines (beginning at top) in csv file contain metadata
    • nChannels::Int: number of channels in csv file
    • timezone::String: timezone to which the timekey in filename refers (standard is PT = Pacific Time –> Berkeley)
    source
    Juleanita.read_folder_csv_oscilloscopeMethod
    read_folder_csv_oscilloscope(csv_folder::String; heading::Int = 17, nwvfmax::Union{Int, Float64, Vector{Int64}} = NaN, nChannels::Int = 2)

    read folder with csv files from oscilloscope input:

    • csv_folder::String: absolute csv folder path
    • heading::Int: number of lines to skip
    • nwvfmax::Union{Int, Float64, Vector{Int64}}: number of waveforms to read OR vector of waveforms indices to read
    • nChannels::Int: number of channels in csv files to read (1 or 2)
    source
    Juleanita.rmsMethod
    rms(x::Vector{T}) where {T <: Real}

    Calculate the RMS of a vector of real numbers.

    source
    Juleanita.simple_dspMethod
    simple_dsp(data::Q, dsp_config::DSPConfig; τ_pz::Quantity{T} = 0.0u"µs", pars_filter::PropDict) where {Q <: Table, T<:Real}

    dsp routine which calculates all relevant parameters for the waveform analysis

    • data::Q: input data, e.g. raw file, peakfile
    • dsp_config::DSPConfig: DSP configuration object
    • τ_pz::Quantity{T}: pole-zero decay time. If τ_pz = 0.0u"µs" (or none given), no pole-zero correction is applied.
    • pars_filter::PropDict: filter parameters for the different filter types. Use PropDict() to get default values from config.
    source
    Juleanita.simple_dsp_pulserMethod
    simple_dsp_pulser(data::Q, dsp_config::DSPConfig; τ_pz::Quantity{T} = 0.0u"µs", pars_filter::PropDict) where {Q <: Table, T<:Real}

    minimal version of simple_dsp for pulser channel

    source
    Juleanita.sktutek_csv_to_lh5Function
    skutek_csv_to_lh5(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId, csv_folder::String; timestep::Quantity = 0.01u"µs")
     skutek_csv_to_lh5(data::LegendData, period::DataPeriod, run::DataRun, category::Union{Symbol, DataCategory}, channel::ChannelId; kwargs...)

    convert csv files from Skutek digitizer "FemtoDAQ Vireo" to lh5 files

    • format of csv file matches the one of Skutek digitizer "FemtoDAQ Vireo ...might be different for other systems

    inputs:

    • data::LegendData LegendData object. You need "LEGEND_DATA_CONFIG" to construct this. this will define later where .lh5 files are saved
    • period::DataPeriod data period that you want to assign your data to
    • run::DataRun data run that you want to assign your data to
    • category::DataCategoryLike data category that you want to assign your data to
    • channel::ChannelId channel id that you want to assign your data to
    • csv_folder::String folder where the csv files are located (optinal). if not defined use the default folder

    kwargs

    • timestep::Quantity time step of the waveforms. default is 0.01µs –> 100 MHz sampling.
    • chmode::Symbol = :diff
      • :diff ch1 - ch2 is stored as raw/waveform
      • :diffplus ch1 - ch2 is stored as raw/waveform AND both channels are stored as raw/waveform_ch1 and raw/waveform_ch2 (if available in data)
      • :single ch1 is stored as raw/waveform and ch2 is stored as raw/waveform_ch2 (if available in data)
      • :pulser ch1 is stored as raw/waveform and ch2 is stored as raw/pulser
    source