Example #1
0
 def __init__(self, ipv4, vessel_max=4, max_mfc_rate=0.5, setup_timeout=None):
     self.logger = BuiltinLogger("MechKLATest")
     self._max_mfc_rate = max_mfc_rate
     self._vessel_max = vessel_max
     self._setup_timeout = setup_timeout or (2 ** 31 - 1)
     self.app = open_hello(ipv4)
     self._reports = None
Example #2
0
    def __init__(self, ipv4, reactor_ctx=None, test_ctx=None):
        self.app = open_hello(ipv4)
        self.tests_to_run = []
        self.tests_run = []
        self.tests_skipped = []
        self.tests_pending = []
        self.ntests_run = 0

        self.logger = BuiltinLogger(self.__class__.__name__ + datetime.now().strftime("%m-%d-%Y %H-%M"))
        self.logger.handlers.pop(0)  # XXX bad practice

        if reactor_ctx is None:
            reactor_ctx = _default_r_ctx
        if test_ctx is None:
            test_ctx = _default_t_ctx

        self.reactor_ctx = reactor_ctx
        self.test_ctx = test_ctx
Example #3
0
class MechKLATest:
    """ KLA test runner designed ground-up to work for
    *3L Mag Wheel* only! If using any other setup, review code to verify
     it will work correctly!!!

     Since mag drive uses headspace to "sparge" the vessel with oxygen,
     no operator activity with tubing, gases, etc is necessary in certain
     circumstances.

     This class ASSUMES THE FOLLOWING:

     * 1.3 hello software
     * Logger settings are correct
     * N2 gas is connected to a tank with sufficient volume, to N2 AND O2 inlets
     * Air is connected to a compressor (or tank w/ sufficient volume) to air inlet
     * Vessel is inserted in reactor, with Main and Micro gas lines connected
     * All ports on the top of the vessel are closed
     * Filter oven is only open line for gas to escape
     * Vessel has Main Gas connector on L-plate snipped.
     * Vessel has Micro Gas connector on L-plate intact!
    """

    def __init__(self, ipv4, vessel_max=4, max_mfc_rate=0.5, setup_timeout=None):
        self.logger = BuiltinLogger("MechKLATest")
        self._max_mfc_rate = max_mfc_rate
        self._vessel_max = vessel_max
        self._setup_timeout = setup_timeout or (2 ** 31 - 1)
        self.app = open_hello(ipv4)
        self._reports = None

    def setup(self):

        self.logger.info("Initializing KLA Setup")

        app = self.app
        app.login()
        app.setag(1, 50)
        app.setdo(1, 0, 500)

        start = _time()

        self.logger.info("Begin setup. Waiting for DO < 20%")
        log_time = _time() + 10
        while app.getdopv() > 20:
            t = _time()
            if t > log_time:
                log_time = int(t) + 10
                self.logger.info("Waiting for DO to fall below 20.")
                self.logger.info("%d seconds: %.1f%% DO" % (t - start, app.getdopv()))
            _sleep(1)

        app.setdo(2, 0, 0)
        app.setmg(2, 0)

    def clear_headspace(self, media_volume):

        self.logger.info("Preparing to purge headspace")

        # math
        headspace = self._vessel_max - media_volume
        sleep_time = headspace / self._max_mfc_rate * 60

        app = self.app
        app.login()
        app.setdo(2, 0)
        app.setmg(1, self._max_mfc_rate)

        self.logger.info("Purging headspace at %.3f LPM for %d seconds" % (self._max_mfc_rate, sleep_time))

        time = _time
        sleep = _sleep
        t = time()
        end = t + sleep_time
        log_time = int(t) + 10

        while t < end:
            if t > log_time:
                log_time = int(t) + 10
                left = int(end - t)
                self.logger.info("Purging headspace. %s seconds remaining" % left)
            t = time()
            sleep(5)

        # login again in case sleep_time was long
        app.login()
        app.setmg(2, 0)

    def run(self, volume, experiments):
        # batches is list of batch names
        batches = self.run_experiments(volume, experiments)

        if self._reports is None:
            reports = self._reports = []
        else:
            reports = self._reports

        batch_list = self.app.getBatches()

        for name in batches:
            id = batch_list.getbatchid(name)
            r = self.app.getdatareport_bybatchid(id)
            b = KLARawDataFile(name, None, r)
            reports.append(b)
        return reports

    def run_experiments(self, volume, experiments):
        """
        @param volume: volume of media in L
        @param experiments: 3 tuple (ag_mode, ag_sp, flow_rate)
        @type experiments: ((int | float, int | float, int | float)) | list[(int | float, int | float, int | float)]
        @return: list of batches
        @rtype: list[str]
        """
        batches = []

        self.logger.info("Running %d experiments." % len(experiments))
        for i, (mode, sp, flowrate) in enumerate(experiments, 1):

            self.logger.info("Running test %d of %d" % (i, len(experiments)))

            try:
                self.setup()
            except KeyboardInterrupt:
                self.logger.error("Got keyboard interrupt, skipping setup.")

            try:
                self.clear_headspace(volume)
            except KeyboardInterrupt:
                self.logger.error("Got keyboard interrupt, skipping headspace purge.")

            try:
                b = self.experiment(mode, sp, flowrate, volume)
                batches.append(b)
            except KeyboardInterrupt:
                self.logger.error("Got keyboard interrupt, skipping test.")
                continue
            finally:
                mv = self.app.gpmv()
                if mv["do"]["mode"] != 2:
                    while True:
                        try:
                            self.app.login()
                            self.app.setdo(2, 0, 0)
                            break
                        except Exception:
                            self.logger.error("Error shutting down test.")
                            self.app.reconnect()

        return batches

    def experiment(self, ag_mode, ag_sp, flow_rate, volume):
        """
        @param flow_rate: flow rate in *mL per min*
        """
        app = self.app
        app.login()
        time = _time

        self.logger.info("Initializing Agitation with mode=%s sp=%s." % (ag_mode, ag_sp))
        app.setag(ag_mode, ag_sp)

        # if setpoint is auto mode, wait for pv to reach correct value
        if ag_mode == 0:
            timeout = time() + 10 * 60
            log_time = time() + 10
            while True:
                pv = app.getagpv()
                if ag_sp - 1 < pv < ag_sp + 1:
                    break
                t = time()
                if t > log_time:
                    log_time = int(t) + 10
                    self.logger.info("Waiting for Agitation to reach setpoint. PV = %d." % app.getagpv())
                if t > timeout:
                    raise KLAError("Agitation didn't reach setpoint.")
                _sleep(1)

        app.setmg(1, flow_rate / 1000)

        self.logger.info("Beginning KLA Experiment.")

        batch_name = "kla%s-%s-%s-%s" % (ag_mode, volume, ag_sp, flow_rate)

        self.logger.info("Starting new batch named '%s'." % batch_name)
        if app.batchrunning():
            app.endbatch()
        app.startbatch(batch_name)

        start = time()
        end = start + 14 * 60
        log_time = start + 10
        while True:
            t = time()
            pv = app.getdopv()
            if t > log_time:
                self.logger.info("Test running, %d seconds passed. DO PV = %.1f." % (t - start, pv))
                log_time += 10
            if t > end:
                break
            if pv > 90:
                break

        self.logger.info("Test finished. DO PV = %.1f after %d seconds." % (app.getdopv(), time() - start))

        self.logger.info("Ending batch")
        app.endbatch()
        return batch_name
Example #4
0
class AirKLATestRunner:
    """
    Run a group of KLA tests on an air wheel reactor.
    """

    def __init__(self, ipv4, reactor_ctx=None, test_ctx=None):
        self.app = open_hello(ipv4)
        self.tests_to_run = []
        self.tests_run = []
        self.tests_skipped = []
        self.tests_pending = []
        self.ntests_run = 0

        self.logger = BuiltinLogger(self.__class__.__name__ + datetime.now().strftime("%m-%d-%Y %H-%M"))
        self.logger.handlers.pop(0)  # XXX bad practice

        if reactor_ctx is None:
            reactor_ctx = _default_r_ctx
        if test_ctx is None:
            test_ctx = _default_t_ctx

        self.reactor_ctx = reactor_ctx
        self.test_ctx = test_ctx

    def print(self, *args, **kwargs):
        print(*args, **kwargs)

        msg = kwargs.get("sep", " ").join(args).replace("\r", "")
        if msg:
            self.logger.info(msg)

    def import_batch(self, batchname):
        filename = self.test_ctx.generate_filename(batchname)
        t = AirKLATest(self.app, 0, 0, 0, batchname, self.reactor_ctx, self.test_ctx)
        r = KLARawDataFile.from_download(batchname, filename, self.app.ipv4)
        t.report = r
        self.tests_run.append(t)

    def pickle_completed(self):
        pkl_file = self.test_ctx.savedir + "klapickle\\airklatestpikle.pkl"
        safe_pickle(self.tests_run, pkl_file)

    def add_test(self, test):
        """
        @type test: AirKLATest
        """
        test.print = self.print
        self.tests_to_run.append(test)

    def create_test(self, main_sp, micro_sp, volume, name):
        t = AirKLATest(self.app, main_sp, micro_sp, volume, name, self.reactor_ctx, self.test_ctx)
        self.add_test(t)
        return t

    def skip_current_test(self):
        t = self.tests_pending.pop()
        self.tests_skipped.append(t)

        self.app.login()
        if self.reactor_ctx.is_mag:
            self.app.setmg(2, 0)
        else:
            self.app.setag(2, 0)
        self.app.setph(2, 0, 0)
        self.app.setdo(2, 0, 0)
        self.app.logout()

    def run_once(self):
        self.ntests_run += 1
        t = self.tests_to_run.pop()
        self.print("-------------------------------------------")
        self.print("Test #%d starting: %s" % (self.ntests_run, t.get_info()))
        self.tests_pending.append(t)
        try:
            t.run()
        except SkipTest as e:
            self.print(e.args)
            self.skip_current_test()
        except Exception:
            traceback.print_exc()
            self.skip_current_test()
        else:
            self.tests_pending.pop()
            self.tests_run.append(t)
            assert t.report

    def run_all(self):
        # run all tests. reverse list in the beginning,
        # then run 1 by 1 using .pop() to iterate in
        # correct order while removing from list.
        self.tests_to_run.reverse()
        while self.tests_to_run:
            self.run_once()

        if self.tests_skipped:
            self.print("------------------------")
            self.print("Skipped tests:")
            for t in self.tests_skipped:
                self.print(t.get_info())