def get_tc_infos(self, tc):
     rs = RunSelector(tc)
     return [
         SelectionInfo(
             rs.select_runs_from_runplan(rp, dut + 1, unselect=True))
         for rp in sorted(self.RunPlans[tc])
         for dut in range(rs.get_n_duts(run_plan=rp))
     ]
Exemple #2
0
    def __init__(self, multi, first_run=None, end_run=None, test_campaign=None, type_=None, verbose=False):

        self.Multi = multi
        self.Type = type_

        self.Selection = RunSelector(testcampaign=test_campaign, verbose=verbose)
        self.Run = self.Selection.Run
        self.StartAtRun = choose(first_run, self.get_all_runs()[0] if self.Multi else self.find_last_converted())
        self.StopAtRun = 1e9 if not multi or end_run is None else int(end_run)
        self.Runs = self.load_runs()
        self.Selection.select_runs(*[run.Number for run in self.Runs])
    def __init__(self, selection_name=None, verbose=False):

        self.Name = selection_name
        Analysis.__init__(
            self,
            verbose=verbose,
            results_dir='selections',
            sub_dir=selection_name if selection_name is not None else '')

        self.print_start(run=selection_name, tc=False, prnt=verbose)

        # Main
        self.Selections = self.load_selections()
        self.Selection = self.load_selection(selection_name)

        # Config
        self.DUTParser = load_parser(
            join(self.Dir, 'config', 'DiamondAliases.ini'))

        # Info
        self.RS = RunSelector()  # dummy for information
        self.RunPlans = self.load_runplans()
        self.TestCampaigns = self.load_test_campaigns()
        self.Info = self.load_selection_info()
        self.DUTName = self.load_dut_name()
        self.NPlans = len(self.Info) if self.Info else None
        self.Ana = self.load_dummy()

        if self.Info:
            self.show_selection()
        self.print_finished(prnt=verbose)
 def load_selection_info(self):
     selections = []
     if self.Selection is None:
         return
     for tc, rps in self.Selection.items():
         for rp, dut_nrs in rps.items():
             for dut_nr in array([dut_nrs]).flatten():
                 selections.append(
                     SelectionInfo(
                         RunSelector(tc).select_runs_from_runplan(
                             rp, dut_nr, unselect=True)))
     return selections
Exemple #5
0
    def __init__(self, analysis=None, test_campaign=None, dut=None, begin=None, end=None, averaging=None, verbose=None):
        Analysis.__init__(self, test_campaign if analysis is None else analysis.TCString, verbose=verbose, sub_dir='currents')

        # Settings
        self.Averaging = averaging
        self.TimeZone = timezone('Europe/Zurich')
        self.DataDir = join(self.TCDir, 'hv')

        # Config
        self.Ana = analysis
        self.IsCollection = hasattr(analysis, 'Runs')
        self.Type = self.Ana.Type if analysis is not None and self.IsCollection else 'None'
        self.RunSelection = RunSelector(testcampaign=self.TCString)
        self.RunLogs = self.RunSelection.RunInfos
        self.Run = self.RunSelection.Run if analysis is None else self.Ana.FirstAnalysis.Run if self.IsCollection else self.Ana.Run
        if self.IsCollection:
            self.Runs = self.Ana.Runs  # required for plotting
        self.RunPlan = self.load_run_plan()  # required for plotting
        self.HVConfig = self.load_parser()
        self.Bias = self.Ana.Bias if hasattr(self.Ana, 'Bias') else None
        self.Draw.ServerDir = analysis.Draw.ServerDir if analysis is not None else None

        # Times
        self.Begin, self.End = self.load_times(begin, end, dut)

        # DUT
        self.DUT = self.init_dut(dut)

        # HV Device Info
        self.Number = self.load_device_number()
        self.Channel = self.load_device_channel()
        self.Name = self.HVConfig.get('HV{}'.format(self.Number), 'name')
        self.Brand = remove_digits(self.Name.split('-')[0])
        self.Model = self.HVConfig.get('HV{}'.format(self.Number), 'model')
        self.Precision = .005 if '237' in self.Name else .05

        # data
        self.IgnoreJumps = True
        self.Data = self.load_data()
 def __init__(self, sel: RunSelector):
     self.RunInfo = sel.RunInfos
     self.Run = sel.Run
     self.TCString = sel.TCString
     self.RunPlan = sel.SelectedRunplan
     self.DUT = sel.SelectedDUT
     self.DUTName = self.DUT.Name
     self.DUTNr = self.DUT.Number
     self.IsPixel = 'pix' in (self.DUT.Type if type(self.DUT.Type) is str
                              else self.DUT.Type[self.TCString])
     self.Verbose = sel.Run.Verbose
     self.Bias = self.DUT.Bias
     self.Irradiation = self.DUT.get_irradiation(self.TCString)
     self.Type = sel.SelectedType.lower()
     self.Runs = sel.get_selected_runs()
     self.PulserType = sel.PulserType
     self.DUT = PixelDUT(self.DUT.Number, self.RunInfo[self.Runs[0]])
 def get_rp_diamonds(tc, rp):
     sel = RunSelector(tc).select_runs_from_runplan(rp, unselect=True)
     return sel.get_dut_names()
Exemple #8
0
class Currents(Analysis):
    """reads in information from the keithley log file"""

    VCol = 602  # 807
    CCol = 899  # 418
    MS = .3

    def __init__(self, analysis=None, test_campaign=None, dut=None, begin=None, end=None, averaging=None, verbose=None):
        Analysis.__init__(self, test_campaign if analysis is None else analysis.TCString, verbose=verbose, sub_dir='currents')

        # Settings
        self.Averaging = averaging
        self.TimeZone = timezone('Europe/Zurich')
        self.DataDir = join(self.TCDir, 'hv')

        # Config
        self.Ana = analysis
        self.IsCollection = hasattr(analysis, 'Runs')
        self.Type = self.Ana.Type if analysis is not None and self.IsCollection else 'None'
        self.RunSelection = RunSelector(testcampaign=self.TCString)
        self.RunLogs = self.RunSelection.RunInfos
        self.Run = self.RunSelection.Run if analysis is None else self.Ana.FirstAnalysis.Run if self.IsCollection else self.Ana.Run
        if self.IsCollection:
            self.Runs = self.Ana.Runs  # required for plotting
        self.RunPlan = self.load_run_plan()  # required for plotting
        self.HVConfig = self.load_parser()
        self.Bias = self.Ana.Bias if hasattr(self.Ana, 'Bias') else None
        self.Draw.ServerDir = analysis.Draw.ServerDir if analysis is not None else None

        # Times
        self.Begin, self.End = self.load_times(begin, end, dut)

        # DUT
        self.DUT = self.init_dut(dut)

        # HV Device Info
        self.Number = self.load_device_number()
        self.Channel = self.load_device_channel()
        self.Name = self.HVConfig.get('HV{}'.format(self.Number), 'name')
        self.Brand = remove_digits(self.Name.split('-')[0])
        self.Model = self.HVConfig.get('HV{}'.format(self.Number), 'model')
        self.Precision = .005 if '237' in self.Name else .05

        # data
        self.IgnoreJumps = True
        self.Data = self.load_data()

    # ----------------------------------------
    # region INIT
    def load_data(self):
        data_file = join(self.DataDir, 'data.hdf5')
        if not file_exists(data_file):
            self.convert_data()
        data = h5py.File(data_file, 'r')[f'{self.Name}_CH{self.Channel}']
        data = data[(data['timestamps'] >= time_stamp(self.Begin)) & (data['timestamps'] <= time_stamp(self.End))]
        if not data.size:
            return
        if self.IgnoreJumps:  # filter out jumps
            data = data[where(abs(data['currents']) < 1e20)]  # take out very large unphysical currents
            data = data[where(abs(data['currents'][:-1]) * 100 > abs(data['currents'][1:]))[0] + 1]  # take out the events that are 100 larger than the previous
        if not data.size:
            return
        data['currents'] *= 1e9 * sign(mean(data['currents']))  # convert to nA and flip sign if current is negative
        if self.Ana is not None:
            data['timestamps'] -= uint32(data['timestamps'][0] - time_stamp(self.load_ana_start_time()))  # synchronise time vectors
        return data

    def reload_data(self, ignore_jumps):
        if ignore_jumps != self.IgnoreJumps:
            self.IgnoreJumps = ignore_jumps
            self.Data = self.load_data()

    def load_run_plan(self):
        return self.RunSelection.SelectedRunplan if self.Ana is None else self.Ana.RunPlan if self.IsCollection else None

    def load_parser(self):
        file_path = join(self.DataDir, 'config.ini')
        if not file_exists(file_path):
            critical('HV info file "{f}" does not exist'.format(f=file_path))
        return Config(file_path)

    def load_times(self, begin, end, dut=1):
        if self.Ana is None:
            if str(begin).isdigit():  # run number or run plan is provided
                self.RunSelection.select_runs_in_range(begin, end if end is not None else begin, dut) if end or end is None else self.RunSelection.select_runs_from_runplan(begin)
                return self.RunSelection.get_start_time(), self.RunSelection.get_end_time()
            else:  # actual time strings are provided
                return (self.TimeZone.localize(datetime.strptime('{}-{}'.format(self.TestCampaign.year, t), '%Y-%m/%d-%H:%M:%S')) for t in [begin, end])
        return self.load_ana_start_time(), self.load_ana_end_time()

    def load_time(self, t, t_log):
        t = self.TimeZone.localize(datetime.fromtimestamp(t)) if t is not None else t_log
        return t_log if t.year < 2000 or t.day != t_log.day else t

    def load_ana_start_time(self):
        ana = self.Ana if not self.IsCollection else self.Ana.FirstAnalysis
        return self.load_time(ana.Run.StartTime if hasattr(ana.Run, 'StartTime') else None, ana.Run.LogStart)

    def load_ana_end_time(self):
        ana = self.Ana if not self.IsCollection else self.Ana.LastAnalysis
        return self.load_time(ana.Run.EndTime if hasattr(ana.Run, 'EndTime') else None, ana.Run.LogEnd)

    def init_dut(self, number):
        if self.Ana is not None:
            return self.Ana.DUT
        elif self.RunSelection.has_selected_runs:
            return self.RunSelection.SelectedDUT
        from dut import DUT
        return DUT(number, next(log for log in self.RunLogs.values() if conv_log_time(log['starttime0']) > self.Begin))

    def load_device_str(self):
        if self.Ana is not None:
            run_info = self.Ana.FirstAnalysis.Run.Info if self.IsCollection else self.Ana.Run.Info
        elif self.RunSelection.has_selected_runs:
            run_info = self.RunLogs[self.RunSelection.get_selected_runs()[0]]
        else:
            run_info = next(log for log in self.RunLogs.values() if conv_log_time(log['starttime0']) > self.Begin)
        return str(run_info['dia{}supply'.format(self.DUT.Number)])

    def load_device_number(self):
        return self.load_device_str().split('-')[0]

    def load_device_channel(self):
        words = self.load_device_str().split('-')
        return words[1] if len(words) > 1 else '0'
    # endregion INIT
    # ----------------------------------------

    # ----------------------------------------
    # region GET
    def get_runs(self):
        return self.Ana.get_runs()

    def get_fluxes(self, pbar=False):
        return self.Ana.get_fluxes(pbar=pbar)

    def get_analyses(self):
        return self.Ana.get_analyses()
    # endregion GET
    # ----------------------------------------

    # ----------------------------------------
    # region DATA ACQUISITION
    def get_log_date(self, name):
        log_date = ''.join(basename(name).split('_')[-6:])
        return self.TimeZone.localize(datetime.strptime(log_date, '%Y%m%d%H%M%S.log'))

    def convert_data(self):
        info('converting hv text files to hdf5 ...')
        self.PBar.start(len(glob(join(self.DataDir, '*', '*.log'))))
        f = h5py.File(join(self.DataDir, 'data.hdf5'), 'w')
        for d in glob(join(self.DataDir, '*_*')):
            arrays = []
            for file_name in sorted(glob(join(d, '*.log'))):
                if getsize(file_name) == 0:
                    remove_file(file_name)
                    self.PBar.update()
                    continue
                log_date = self.get_log_date(file_name)
                data = genfromtxt(file_name, usecols=arange(3), dtype=[('timestamps', 'U10'), ('voltages', 'f2'), ('currents', 'f4')], invalid_raise=False)
                data = data[invert(isnan(data['voltages']))]  # remove text entries
                data['timestamps'] = array(log_date.strftime('%Y-%m-%d ') + char.array(data['timestamps'])).astype(datetime64) - datetime64('1970-01-01T00:00:00') - log_date.utcoffset().seconds
                data = data.astype([('timestamps', 'u4'), ('voltages', 'f2'), ('currents', 'f4')])
                arrays.append(data)
                self.PBar.update()
            if len(arrays):
                f.create_dataset(basename(d), data=concatenate(arrays))
    # endregion DATA ACQUISITION
    # ----------------------------------------

    # ----------------------------------------
    # region GET
    def get(self):
        if self.Ana is not None and not self.Ana.DUT.Bias:
            warning('Bias of run {} is 0!'.format(self.Run.Number))
            return ufloat(0, 0)
        elif self.Data is None:
            warning('no current data!')
            return ufloat(0, 0)
        else:
            h = self.draw_distribution(show=False)
            if h.GetEntries() < 3:
                return None
            m, s = mean_sigma(*get_hist_vecs(h, err=False), err=False)
            fit = h.Fit('gaus', 'sq0', '', m - s, m + s)
            fm, fs = fit.Parameter(1), fit.Parameter(2)
            if .8 * m < fit.Parameter(1) < 1.2 * m and s > 0 and fs < fm and fit.ParError(1) < m:  # only use gauss fit if its not deviating too much from the the mean
                current = ufloat(fm, fit.ParError(1) + self.Precision / 2)
            else:
                current = ufloat(h.GetMean(), h.GetMeanError() + self.Precision / 2)
        return current

    def get_title(self):
        bias_str = 'at {b} V'.format(b=self.Bias) if self.Bias else ''
        run_str = '{n}'.format(n=self.Run.Number) if not self.IsCollection else 'Plan {rp}'.format(rp=self.Ana.RunPlan)
        return 'Currents of {dia} {b} - Run {r} - {n}'.format(dia=self.DUT.Name, b=bias_str, r=run_str, n=self.Name)

    def get_first_log(self):
        names = sorted(glob(join(self.DataDir, '{}_CH{}'.format(self.Name, self.Channel), '*.log')))
        for i, name in enumerate(names):
            if self.get_log_date(name) > self.Begin:
                return names[i - 1]

    def get_run_number(self):
        return None if self.Ana is None else 'RP{}'.format(self.Ana.RunPlan) if self.IsCollection else self.Ana.Run.Number

    def get_t0(self):
        return self.Data['timestamps'][0]
    # endregion GET
    # ----------------------------------------

    # ----------------------------------------
    # region PLOTTING
    def draw(self, rel_time=False, ignore_jumps=True, v_range=None, c_range=None, averaging=1, draw_opt='al', with_flux=False, f_range=None, cunit='nA', **dkw):
        self.reload_data(ignore_jumps)
        if self.Data is None:
            return warning('no current data!')
        t, c, v = (average_list(self.Data[n], averaging) for n in ['timestamps', 'currents', 'voltages'])
        gv = self.Draw.graph(t, v, title=self.get_title(), y_tit='Voltage [nA]', yax_col=self.VCol, color=self.VCol, y_range=choose(v_range, [-1100, 1100]), l_off_x=10, x_ticks=0, show=False, lw=2)
        if with_flux:
            gv = self.Ana.draw_flux(rel_time=rel_time, show=False)
            format_histo(gv, title=self.get_title(), fill_color=4000, fill_style=4000, lw=3, y_range=choose(f_range, [5, 20000]), y_tit='Flux [kHz/cm^{2}]')
        c = array(c) / {'nA': 1, '#muA': 1000}[cunit]
        gc = Draw.make_tgrapherrors(t, c)
        format_histo(gc, x_tit='Time [hh:mm]', y_tit=f'Current [{cunit}]', yax_col=self.CCol, color=self.CCol, y_range=choose(c_range, [round_down_to(min(c)), round_up_to(max(c))]))
        x_range = [gv.GetBinLowEdge(1), gv.GetBinLowEdge(gv.GetNbinsX() + 1)] if with_flux else [t[0], t[-1]]
        for g in [gc, gv]:
            format_histo(g, lab_size=.05, x_off=1.05, tit_size=.06, t_ax_off=t[0] if rel_time else 0, y_off=.8, center_y=True, x_range=x_range, markersize=self.MS, stats=0)
        m = [.09, .09, .2, .02]
        self.Draw(gv, **prep_kw(dkw, **Draw.mode(2), m=m, draw_opt='{}y+'.format('hist' if with_flux else 'al'), logy=with_flux))
        Draw.tpad('pc', transparent=True, margins=m)
        gc.Draw(draw_opt)
        self.Draw.save_plots(**prep_kw(dkw, savename=f'{self.get_run_number()}_{self.DUT}{"Flux" if with_flux else ""}', ftype='png'))
        return gc

    def draw_profile(self, bw=5, show=True):
        x, y = self.Data['timestamps'], self.Data['currents']
        return self.Draw.profile(x, y, make_bins(x[0], x[-1], bw), 'Leakage Current', x_tit='Time [hh:mm]', y_tit='Current [nA]', t_ax_off=0, markersize=.7, w=1.5,
                                 h=.75, lm=.08, y_off=.8, show=show, stats=set_entries())

    def draw_distribution(self, show=True):
        m, s = mean_sigma(self.Data['currents'], err=False)
        xmin, xmax = m - 4 * max(s, .1), m + 4 * max(s, .1)
        return self.Draw.distribution(self.Data['currents'], make_bins(xmin, xmax, self.Precision * 2), 'Current Distribution', show=show, x_tit='Current [nA]')

    def draw_flux_correlation(self, bin_fac=1, show=True):
        p1 = self.draw_profile(show=False)
        p2 = self.Ana.Tel.draw_flux(show=False)
        ybins = log_bins(int(sqrt(p1.GetNbinsX()) * bin_fac) * 3, .1, p1.GetMaximum() * 2)
        xbins = log_bins(int(sqrt(p1.GetNbinsX()) * bin_fac), .1, p2.GetMaximum() * 2)
        h = TH2F('gfcc', 'Correlation of Flux and Current', *(xbins + ybins))
        for i in range(p1.GetNbinsX()):
            if p1.GetBinContent(i) and p2.GetBinContent(i):
                h.Fill(p2.GetBinContent(i), p1.GetBinContent(i))
        format_histo(h, y_tit='Current [nA]', x_tit='Flux [kHz/cm^{2}', stats=0, y_off=1.2)
        self.Draw(h, 'FluxCurrent', draw_opt='colz', rm=.18, show=show, lm=.12, logy=True, logx=True)

    def draw_iv(self, show=True):
        x, y = self.Data['voltages'], self.Data['currents']
        return self.Draw.graph(x, y, 0, self.Precision, title='I-V Curve for {}'.format(self.DUT.Name), x_tit='Voltage [V]', y_tit='Current [nA]', show=show)

    @staticmethod
    def curr_args(y):
        return {'y_tit': 'Current [nA]', 'yax_col': Currents.CCol, 'color': Currents.CCol, 'y_range': ax_range(y, rnd=True), 'l_off_x': 1}

    def draw_ph(self, ph_range=None, **kwargs):
        x, y = self.Data['timestamps'], self.Data['currents']
        xargs = {'x_range': ax_range(x, fl=.05, fh=.05), 't_ax_off': 0, 'center_x': True}
        self.Draw.graph(Draw.make_graph_from_profile(self.Ana.draw_pulse_height(rel_t=False, show=False)[0]), **Draw.mode(2, rm=.08), **xargs, y_tit='Pulse Height [au]', y_range=ph_range)
        g = self.Draw.graph(x, y, 'g', Draw.tpad('pc', transparent=True), **self.curr_args(y), **kwargs, **Draw.mode(2, rm=.08), draw_opt='aly+')
        format_histo(g, **xargs, yax_col=Currents.CCol)
Exemple #9
0
class AutoConvert:

    def __init__(self, multi, first_run=None, end_run=None, test_campaign=None, type_=None, verbose=False):

        self.Multi = multi
        self.Type = type_

        self.Selection = RunSelector(testcampaign=test_campaign, verbose=verbose)
        self.Run = self.Selection.Run
        self.StartAtRun = choose(first_run, self.get_all_runs()[0] if self.Multi else self.find_last_converted())
        self.StopAtRun = 1e9 if not multi or end_run is None else int(end_run)
        self.Runs = self.load_runs()
        self.Selection.select_runs(*[run.Number for run in self.Runs])

    def find_last_converted(self):
        rdir = 'pads' if self.Type == 'pad' else 'pixel' if self.Type == 'pixel' else '*'
        converted = [int(remove_letters(basename(name))) for name in glob(join(self.Selection.Run.TCDir, 'root', rdir, 'TrackedRun*.root'))]
        return max(converted) if converted else self.get_all_runs()[0]

    def get_all_runs(self):
        all_runs = self.Selection.get_runplan_runs()
        return [r for r in all_runs if self.Selection.get_type(r) == self.Type] if self.Type is not None else all_runs

    def load_run(self, nr):
        return Run(nr, self.Selection.TCString, load_tree=False, verbose=self.Selection.Run.Verbose)

    def load_runs(self):
        runs = array([r for r in self.get_all_runs() if not file_exists(self.Selection.get_final_file_path(r))], 'i2')
        return [self.load_run(run) for run in runs[(runs >= self.StartAtRun) & (runs <= self.StopAtRun)]]

    def load_logged_runs(self):
        runs = self.Selection.load_runs()
        return runs[runs >= self.StartAtRun]

    def get_next_run(self):
        last = self.find_last_converted()
        runs = self.load_logged_runs()
        return None if not runs.size or last == runs[-1] else runs[0] if last is None else next(run for run in runs if run > last)

    def print_progress(self):
        pbar = PBar(len(self.load_runs()), counter=True, t='h')
        while not pbar.is_finished():
            sleep(5)
            pbar.update(pbar.N - len(self.load_runs()) - 1)

    def auto_convert(self):
        """Sequential conversion with check if the file is currently written. For usage during beam tests."""
        self.Runs = self.load_logged_runs()
        if self.Runs.size > 1:
            info(f'Converting runs {self.Runs[0]} - {self.Runs[-1]}')
            # self.multi()
        while max(self.load_logged_runs()) <= self.StopAtRun:
            run = self.get_next_run()
            t0 = time()
            while run is None:
                info(f'waiting for new run {self.find_last_converted() + 1} since {get_running_time(t0)}', endl=False)
                sleep(5)
                run = self.get_next_run()
            raw_file = self.Run.Converter.get_raw_file_path(run)
            if not file_exists(raw_file, warn=True):
                continue
            t0 = time()
            while file_is_beeing_written(raw_file):
                info(f'waiting until run {run} is finished since {get_running_time(t0)}', endl=False)
                sleep(5)
            r = Run(run, self.Run.TCString)
            info(f'{run} --> {timedelta(seconds=round(time() - r.InitTime))}')

    def multi(self):
        """parallel conversion"""
        info(f'Creating pool with {cpu_count()} processes')
        if not all([file_exists(run.Converter.RawFilePath) for run in self.Runs]):
            self.Selection.copy_raw_files(sel=True)
        with Pool() as pool:
            result = pool.starmap_async(make_run, [(run.Number, self.Selection.TCString) for run in self.Runs])
            print()
            runs = result.get()
            print_small_banner('Summary:')
            for run in runs:
                delta = timedelta(seconds=round(run.TInit))
                speed = 'NOT CONVERTED!' if run.RootFile is None else f'{run.NEvents}, {run.NEvents / delta.total_seconds():1.0f} Events/s'
                print(f'{run} --> {delta} ({speed})')

    def run(self):
        if not len(self.Runs):
            return info('There are no runs to convert :-)')
        self.multi() if self.Multi else self.auto_convert()
Exemple #10
0
 def get_high_rate_run(self, high=True):
     from src.run_selection import RunSelector
     return int(RunSelector(testcampaign=self.TCString).get_high_rate_run(self.Number, high))