Beispiel #1
0
    def __init__(self, cycle, fc):
        self.maestro = MaestroFunctions()
        self.cycle_name = cycle
        self.flowcell = fc
        self.aexpose = Autoexpose()

        self.TDI_flag = 0
        self.num_arrays = 1
        self.auto_exposure = 0

        """
        is this being called to do darkfield imaging or fluorescence imaging?
        darkfield imaging is specified by cycle name starting w/ 'WL';
        assume all other cycle names specify fluorescence imaging
        for darkfield imaging, numeric suffix on cycle name tells whether
        the run is for one flowcell or two
        """
        if self.cycle_name.find("WL") is not -1:
            self.fluor_imaging = 0
            if self.cycle_name.find("1") is not -1:  # this is a single-fc run
                self.dual_fc = 0
            else:
                self.dual_fc = 1
                # WL2 specifies dual-flowcell run
                self.flowcell = self.flowcell + 2
            """
            specifies how many images to average for each WL image; we use 5 
            because the time required to acquire & average 5 is approx equal to 
            the time required to segment the image
            """
            self.WL_num_to_avg = 1

            # specifies the integration time (in msec) for brightfield imaging
            self.WL_integration_time = 35
            self.WL_gain = 70

            # construct cycle name for WL imaging
            today = datetime.date.today()
            fn = "%02d%02d%04d" % (today.month, today.day, today.year)
            self.cycle_name = "%c%c%c%c%c%c" % (fn[0], fn[1], fn[2], fn[3], fn[6], fn[7])
        # end if
        else:
            self.fluor_imaging = 1
            self.cycle_name = cycle
        # end else

        self.flowcell = fc
        # these are used for both manual exposures and autoexposure;
        # the order of these values corresponds to the fluor order
        # in array fluors[]
        self.integration_times = [35, 35, 35, 35, 35]
        self.manual_gains = [45, 120, 70, 50]
        # fluors = ['cy5', 'fam', 'cy3', 'txred']

        # this is run as a thread, so invoke Thread's constructor
        threading.Thread.__init__(self)
Beispiel #2
0
class Imager(threading.Thread):
    global WL_num_to_avg
    global WL_integration_time
    global fluor_imaging
    global cycle_name
    global flowcell
    global dual_fc
    global integration_times
    global manual_gains
    global aexpose

    global num_arrays
    global num_imgs
    global TDI_flag
    global auto_exposure

    def __init__(self, cycle, fc):
        self.maestro = MaestroFunctions()
        self.cycle_name = cycle
        self.flowcell = fc
        self.aexpose = Autoexpose()

        self.TDI_flag = 0
        self.num_arrays = 1
        self.auto_exposure = 0

        """
        is this being called to do darkfield imaging or fluorescence imaging?
        darkfield imaging is specified by cycle name starting w/ 'WL';
        assume all other cycle names specify fluorescence imaging
        for darkfield imaging, numeric suffix on cycle name tells whether
        the run is for one flowcell or two
        """
        if self.cycle_name.find("WL") is not -1:
            self.fluor_imaging = 0
            if self.cycle_name.find("1") is not -1:  # this is a single-fc run
                self.dual_fc = 0
            else:
                self.dual_fc = 1
                # WL2 specifies dual-flowcell run
                self.flowcell = self.flowcell + 2
            """
            specifies how many images to average for each WL image; we use 5 
            because the time required to acquire & average 5 is approx equal to 
            the time required to segment the image
            """
            self.WL_num_to_avg = 1

            # specifies the integration time (in msec) for brightfield imaging
            self.WL_integration_time = 35
            self.WL_gain = 70

            # construct cycle name for WL imaging
            today = datetime.date.today()
            fn = "%02d%02d%04d" % (today.month, today.day, today.year)
            self.cycle_name = "%c%c%c%c%c%c" % (fn[0], fn[1], fn[2], fn[3], fn[6], fn[7])
        # end if
        else:
            self.fluor_imaging = 1
            self.cycle_name = cycle
        # end else

        self.flowcell = fc
        # these are used for both manual exposures and autoexposure;
        # the order of these values corresponds to the fluor order
        # in array fluors[]
        self.integration_times = [35, 35, 35, 35, 35]
        self.manual_gains = [45, 120, 70, 50]
        # fluors = ['cy5', 'fam', 'cy3', 'txred']

        # this is run as a thread, so invoke Thread's constructor
        threading.Thread.__init__(self)

    def run(self):

        # are we doing fluorescent imaging (assume 4 colors) or
        # darkfield imaging?
        if self.fluor_imaging == 1:
            if 0:
                self.aexpose = self.aexpose.autoe()
                self.manual_gains = self.aexpose
                print "using gains found with autoexposgain.py"
            else:
                print "using gains entered by user"
            # this is the order of fluors in the integration and gain arrays;
            # it is also the order used by autoexposure
            fluors = ["cy5", "fam", "cy3", "txred"]

            """
            this is based on the nonamer synthesis, and is the sequence of 
            the probe strand therefore, the sequence of the template 
            (bead-bound) strand is the complement
            """
            fluor_to_base = {"cy5": "T", "cy3": "A", "txred": "C", "fam": "G", "none": "N"}

            # order to do the fluorescence imaging; fam is the most photolabile,
            # so we do it first
            imaging_order = ["fam", "cy3", "txred", "cy5", "none"]

            # now do 4 colors of imaging; each time, perform the stage alignment
            # first to minimize image alignment drift
            i = 0

            while i < 4:

                # perform stage alignment
                cmd = (os.environ["POLONATOR_PATH"] + "/bin/Polonator-stagealign %d") % (self.flowcell)
                print cmd
                os.system(cmd)
                print "STARTING CHECK ........................"
                if self.auto_exposure == 1:
                    j = 60
                    curr_name_new = "%s" % (imaging_order[i])
                    cmd = os.environ["POLONATOR_PATH"] + "/bin/PolonatorUtils gotostagealignpos 0 0"
                    print cmd
                    os.system(cmd)

                    cmd = os.environ["POLONATOR_PATH"] + "/bin/PolonatorUtils snap1 %s %f %d %d" % (
                        curr_name_new,
                        0.035,
                        j,
                        j + 150,
                    )
                    print cmd
                    os.system(cmd)

                # end if

                # turn the darkfield illuminator off if it was left on
                self.maestro.darkfield_off()
                print "STARTING SETUP IMAGE........................"
                # setup controller for current color
                self.maestro.setup_imaging(
                    imaging_order[i],
                    self.integration_times[fluors.index(imaging_order[i])] - 5,
                    1,
                    self.num_arrays,
                    self.flowcell,
                    0,
                    self.TDI_flag,
                )

                # start Polonator-acq which receives images from camera
                # and sends to processing pipeline
                #
                # construct current image-set name (cycle name plus base identity)
                curr_name = "%s_%s" % (self.cycle_name, fluor_to_base[imaging_order[i]])

                # this must be called w/ sudo so that the thread has a high
                # enough priority to ensure images aren't missed often
                tcmd = (os.environ["POLONATOR_PATH"] + "/bin/Polonator-acquirer %s %d %d %d %d") % (
                    curr_name,
                    self.integration_times[fluors.index(imaging_order[i])] - 5,
                    self.manual_gains[fluors.index(imaging_order[i])],
                    self.flowcell,
                    self.num_arrays,
                )
                print tcmd
                cmd = os.environ["POLONATOR_PATH"] + "/bin/Polonator-acquirer"
                print "STARTING ACQUIRE........................"

                # spawn thread to receive the images and wait for it to return;
                # it will exit w/ value of 10 if it did not acquire all images -- in
                # this case, repeat the current color
                if (
                    os.spawnlp(
                        os.P_WAIT,
                        cmd,
                        cmd,
                        curr_name,
                        str(self.integration_times[fluors.index(imaging_order[i])]),
                        str(self.manual_gains[fluors.index(imaging_order[i])]),
                        str(self.flowcell),
                        str(self.num_arrays),
                    )
                    != 10
                ):
                    # move on to next color if all images were received
                    i += 1
                else:
                    print "Polonator-acquirer exited with error"

        # we're doing darkfield imaging; assume we've just started the run and
        # tell Polonator-stagealign to zero out the offsetlog and collect a new
        # base image
        else:

            # generate the 'base' image for the stage alignment tool
            # if this is a dual-flowcell run, we must convert the flowcell == 2 or 3
            # to flowcell == 0 or 1
            if self.dual_fc == 1:
                cmd = (os.environ["POLONATOR_PATH"] + "/bin/Polonator-stagealign %d 1") % (self.flowcell - 2)
            else:
                cmd = (os.environ["POLONATOR_PATH"] + "/bin/Polonator-stagealign %d 1") % (self.flowcell)

            print cmd
            os.system(cmd)

            # we are doing darkfield imaging
            self.maestro.darkfield_on()

            self.maestro.setup_imaging(
                "none",
                self.WL_integration_time - 5,
                self.WL_num_to_avg,
                self.num_arrays,
                self.flowcell,
                1,
                self.TDI_flag,
            )

            """
             start Polonator-acq
             during brightfield imaging (the start of the run), we need to tell 
             the processing computer whether it should expect 1 or 2 flowcells' 
             worth of data; we do this by changing the flowcell number from
             0 for a single-flowcell run to either 2 or 3 for a dual flowcell 
             run (fc 0 or 1, respectively) 
             the imaging software (Polonator-acquirer) understands this 
             convention and converts the 2 or a 3 to a 0 or a 1 after sending 
             the proper flag to the processing pipeline
            """
            cmd = (os.environ["POLONATOR_PATH"] + "/bin/Polonator-acquirer %s %d %d %d %d %d") % (
                self.cycle_name,
                self.WL_integration_time - 5,
                self.WL_gain,
                self.flowcell,
                self.num_arrays,
                self.WL_num_to_avg,
            )
            print cmd
            os.system(cmd)
            self.maestro.darkfield_off()

        return 1