예제 #1
0
 def evapcheck(self, op, thresh=0.20):
     'Update amount of evaporation and check for issues'
     if self.plate.name == "Samples":
         dt = clock.pipetting - self.lastevapupdate  # Assume no evaporation while in PTC
         if dt < -0.1:
             # This may happen during thermocycler operation since pipetting while thermocycling is moved to pipthermotime after waitpgm() is called
             logging.notice(
                 "%s: clock went backwards: pipetting=%f, lastevapupdate=%f, dt=%f -- probably OK due to counting pipetting time during PTC operation"
                 % (self.name, clock.pipetting, self.lastevapupdate, dt))
     else:
         dt = clock.elapsed() - self.lastevapupdate
         if dt < -0.1:
             logging.error(
                 "%s: clock went backwards: elapsed=%f, lastevapupdate=%f, dt=%f"
                 % (self.name, clock.elapsed(), self.lastevapupdate, dt))
     if dt <= 0.1:
         return
     for i in range(
             10):  # Break it into smaller steps since volume affects rate
         evaprate = self.plate.getevaprate(max(0, self.volume - self.evap))
         self.evap += evaprate * dt / 3600 / 10
     if op == 'aspirate' and self.evap > thresh * self.volume and self.evap > 2.0 and self.volume > 0:
         pctevap = self.evap / self.volume * 100
         logging.warning(
             " %s (%s.%s, vol=%.1f ul) may have %.1f ul of evaporation (%.0f%%)"
             % (self.name, str(self.plate), self.plate.wellname(
                 self.well), self.volume, self.evap, pctevap))
         if "evap" in __historyOptions:
             self.history = self.history + (' [Evap: %0.1f ul]' %
                                            (self.evap))
     self.lastevapupdate += dt
예제 #2
0
 def savesummary(self, filename, settings=None):
     # Print amount of samples needed
     fd = open(filename, "w")
     # print >>fd,"Deck layout:"
     # print >>fd,decklayout.REAGENTPLATE
     # print >>fd,decklayout.SAMPLEPLATE
     # print >>fd,decklayout.QPCRPLATE
     # print >>fd,decklayout.WATERLOC
     # print >>fd,decklayout.WASTE
     # print >>fd,decklayout.BLEACHLOC
     # print >>fd,decklayout.WASHLOC
     # print >>fd
     #print >>fd,"DiTi usage:",worklist.getDITIcnt()
     #print >>fd
     print >> fd, "Generated %s (%s-%s pyTecan-%s)" % (
         datetime.now().ctime(), sys.argv[0], self.checksum, self.gitlabel)
     rtime = "Run time: %d (pipetting only) + %d (thermocycling only) + %d (both) = %d minutes (%.1f hours)\n" % (
         clock.pipetting / 60.0, clock.thermotime / 60,
         clock.pipandthermotime / 60, clock.elapsed() / 60,
         clock.elapsed() / 3600.0)
     print rtime
     print >> fd, rtime
     reagents.printprep(fd)
     Sample.printallsamples("All Samples:", fd, w=worklist)
     liquidclass.LC.printalllc(fd)
     if settings is not None:
         pprint(settings, stream=fd)
     fd.close()
예제 #3
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
 def shaken(plate,speed):
     'Called after shaking to mark all samples as mixed'
     for s in __allsamples:
         if plate==s.plate.name and s.volume>0:
             [minx,maxx]=s.plate.getmixspeeds(s.volume,s.volume)
             s.wellMixed=s.wellMixed or speed>=minx
             s.lastMixed=clock.elapsed()
예제 #4
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
 def shaken(plate, speed):
     'Called after shaking to mark all samples as mixed'
     for s in __allsamples:
         if plate == s.plate.name and s.volume > 0:
             [minx, maxx] = s.plate.getmixspeeds(s.volume, s.volume)
             s.wellMixed = s.wellMixed or speed >= minx
             s.lastMixed = clock.elapsed()
예제 #5
0
 def shaken(plate, speed):
     'Called after shaking to mark all samples as mixed'
     for s in __allsamples:
         if plate == s.plate.name and s.volume > 0:
             if not s.wellMixed:
                 (minx, maxx) = s.getmixspeeds()
                 s.wellMixed = speed >= minx - 1
             s.lastMixed = clock.elapsed()
예제 #6
0
 def isMixed(self):
     'Check if sample is currently mixed'
     if self.lastMixed is None:
         return False
     elif not self.hasBeads:
         return True
     else:
         return clock.elapsed() - self.lastMixed < BEADSETTLINGTIME
예제 #7
0
 def isMixed(self):
     'Check if sample is currently mixed'
     if self.lastMixed is None:
         return False
     elif not self.hasBeads:
         return True
     else:
         return clock.elapsed()-self.lastMixed < BEADSETTLINGTIME
예제 #8
0
 def shaken(plate,speed):
     'Called after shaking to mark all samples as mixed'
     for s in __allsamples:
         if plate==s.plate.name and s.volume>0:
             if not s.wellMixed:
                 (minx,maxx)=s.getmixspeeds()
                 s.wellMixed=speed>=minx-1
             s.lastMixed=clock.elapsed()
예제 #9
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
 def evapcheck(self,op,thresh=0.20):
     'Update amount of evaporation and check for issues'
     if self.plate.name=="Samples":
         dt=clock.pipetting-self.lastevapupdate	# Assume no evaporation while in PTC
     else:
         dt=clock.elapsed()-self.lastevapupdate
     if dt<-0.1:
         print  "***ERROR*** -- clock went backwards: elapsed=",clock.elapsed(),", lastevapupdate=",self.lastevapupdate,", dt=",dt
         assert False
     if dt<=0.1:
         return
     for i in range(10):   # Break it into smaller steps since volume affects rate
         evaprate=self.plate.getevaprate(max(0,self.volume-self.evap))
         self.evap+=evaprate*dt/3600/10
     if op=='aspirate' and self.evap>thresh*self.volume and self.evap>2.0 and self.volume>0:
         pctevap=self.evap/self.volume*100
         print "WARNING:  %s (%s.%s, vol=%.1f ul) may have %.1f ul of evaporation (%.0f%%)"%(self.name,str(self.plate),self.plate.wellname(self.well),self.volume,self.evap,pctevap)
         self.history= self.history + (' [Evap: %0.1f ul]'%(self.evap))
     self.lastevapupdate+=dt
예제 #10
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
 def evapcheck(self, op, thresh=0.20):
     'Update amount of evaporation and check for issues'
     if self.plate.name == "Samples":
         dt = clock.pipetting - self.lastevapupdate  # Assume no evaporation while in PTC
     else:
         dt = clock.elapsed() - self.lastevapupdate
     if dt < -0.1:
         print "***ERROR*** -- clock went backwards: elapsed=", clock.elapsed(
         ), ", lastevapupdate=", self.lastevapupdate, ", dt=", dt
         assert False
     if dt <= 0.1:
         return
     for i in range(
             10):  # Break it into smaller steps since volume affects rate
         evaprate = self.plate.getevaprate(max(0, self.volume - self.evap))
         self.evap += evaprate * dt / 3600 / 10
     if op == 'aspirate' and self.evap > thresh * self.volume and self.evap > 2.0 and self.volume > 0:
         pctevap = self.evap / self.volume * 100
         print "WARNING:  %s (%s.%s, vol=%.1f ul) may have %.1f ul of evaporation (%.0f%%)" % (
             self.name, str(self.plate), self.plate.wellname(
                 self.well), self.volume, self.evap, pctevap)
         self.history = self.history + (' [Evap: %0.1f ul]' % (self.evap))
     self.lastevapupdate += dt
예제 #11
0
    def savesummary(self, filename):
        # Print amount of samples needed
        fd = open(filename, "w")
        # print >>fd,"Deck layout:"
        # print >>fd,decklayout.REAGENTPLATE
        # print >>fd,decklayout.SAMPLEPLATE
        # print >>fd,decklayout.QPCRPLATE
        # print >>fd,decklayout.WATERLOC
        # print >>fd,decklayout.WASTE
        # print >>fd,decklayout.BLEACHLOC
        # print >>fd,decklayout.WASHLOC
        # print >>fd
        #print >>fd,"DiTi usage:",worklist.getDITIcnt()
        #print >>fd

        rtime = "Run time: %d (pipetting only) + %d (thermocycling only) + %d (both) = %d minutes\n" % (
            clock.pipetting / 60.0, clock.thermotime / 60,
            clock.pipandthermotime / 60, clock.elapsed() / 60)
        print rtime
        print >> fd, rtime
        reagents.printprep(fd)
        Sample.printallsamples("All Samples:", fd, w=worklist)
        liquidclass.LC.printalllc("All LC:", fd)
        fd.close()
예제 #12
0
    def __init__(self,
                 name,
                 plate,
                 well=None,
                 conc=None,
                 volume=0,
                 hasBeads=False,
                 extraVol=50,
                 mixLC=liquidclass.LCMixBottom,
                 firstWell=None,
                 extrainfo=[],
                 ingredients=None,
                 atEnd=False):
        while True:
            # wrap with a loop to allow use of backupPlate
            # If firstWell is not None, then it is a hint of the first well position that should be used
            if well != None and well != -1:
                if not isinstance(well, int):
                    well = plate.wellnumber(well)
                if well not in plate.wells:
                    logging.warning(
                        "Attempt to assign sample %s to well %d (%s) which is not legal on plate %s"
                        % (name, well, plate.wellname(well), plate.name))
                for s in __allsamples:
                    if s.well == well and s.plate == plate:
                        logging.warning(
                            "Attempt to assign sample %s to plate %s, well %s that already contains %s"
                            % (name, str(plate), plate.wellname(well), s.name))
                        if firstWell is None:
                            firstWell = well
                        well = None
                        break

            if well is None:
                # Find first unused well
                found = False
                if firstWell is not None:
                    # First check only wells>=firstWell
                    for well in plate.wells:
                        if well < firstWell:
                            continue
                        found = True
                        for s in __allsamples:
                            if s.plate == plate and s.well == well:
                                well = well + 1
                                found = False
                                break
                        if found:
                            break

                if not found:
                    well = max(plate.wells) if atEnd else min(plate.wells)
                    while (well >= 0) if atEnd else (well <= max(plate.wells)):
                        found = True
                        for s in __allsamples:
                            if s.plate == plate and s.well == well:
                                well = well + (-1 if atEnd else 1)
                                found = False
                                break
                        if found:
                            break
            elif well == -1:
                well = None

            if well >= plate.nx * plate.ny:
                # Overflow
                if plate.backupPlate is not None:
                    # Overflow onto backup plate
                    logging.warning(
                        "Overflow of %s plate, moving %s to %s plate -- verify carefully!"
                        % (plate.name, name, plate.backupPlate.name))
                    plate = plate.backupPlate
                    well = None
                    continue
                else:
                    logging.error("Overflow of plate %s while adding %s" %
                                  (str(plate), name))

            break

        for s in __allsamples:
            if s.plate == plate and s.well == well:
                logging.error(
                    "Attempt to assign sample %s to plate %s, well %s that already contains %s"
                    % (name, str(plate), plate.wellname(well), s.name))

        if name in [s.name for s in __allsamples]:
            while name in [s.name for s in __allsamples]:
                name = name + "#"
            logging.notice("renaming sample to %s" % name)
        self.name = name
        self.plate = plate
        self.well = well
        if isinstance(conc, Concentration) or conc is None:
            self.conc = conc
        else:
            self.conc = Concentration(conc)
        self.volume = volume
        self.initVol = volume
        if volume > 0:
            if ingredients is None:
                self.ingredients = {name: volume}
            else:
                self.ingredients = ingredients.copy()
                total = sum([v for v in ingredients.values()])
                for k in self.ingredients:
                    self.ingredients[k] = self.ingredients[k] * volume / total
            self.lastvolcheck = None
        else:
            self.ingredients = {}
            self.lastvolcheck = 0  # Assume that it has already been checked for 0 (since it can't be any less...)

        self.checkingredients()

        if plate.pierce:
            self.bottomLC = liquidclass.LCWaterPierce
            self.bottomSideLC = self.bottomLC  # Can't use side with piercing
            self.inliquidLC = self.bottomLC  # Can't use liquid detection when piercing
        else:
            self.bottomLC = liquidclass.LCWaterBottom
            self.bottomSideLC = liquidclass.LCWaterBottomSide
            self.inliquidLC = liquidclass.LCWaterInLiquid

        self.beadsLC = liquidclass.LCWaterBottomBeads
        self.mixLC = mixLC
        self.airLC = liquidclass.LCAir
        # Same as bottom for now
        self.emptyLC = self.bottomLC
        self.history = ""
        __allsamples.append(self)
        if hasBeads:
            self.lastMixed = None
        else:
            self.lastMixed = clock.elapsed(
            ) - 20 * 60  # Assume it was last mixed an 20 min before start of run
        self.wellMixed = True
        self.initHasBeads = hasBeads
        self.hasBeads = hasBeads  # Setting this to true overrides the manual conditioning
        self.extraVol = extraVol  # Extra volume to provide
        self.evap = 0  # Amount that has evaporated
        if self.plate.name == "Samples":
            self.lastevapupdate = clock.pipetting
        else:
            self.lastevapupdate = clock.elapsed()
        self.extrainfo = extrainfo
        self.emptied = False
예제 #13
0
    def mix(self,tipMask,preaspirateAir=False,nmix=4):
        if self.isMixed() and self.wellMixed:
            logging.notice( "mix() called for sample %s, which is already mixed"%self.name)
            return False
        logging.mixwarning("Pipette mixing of %s may introduce bubbles"%self.name)

        self.volcheck(tipMask,[self.well],0)

        blowvol=5
        mstr=""
        extraspace=blowvol+0.1
        if preaspirateAir:
            extraspace+=5
        mixvol=self.volume		  # -self.plate.unusableVolume;  # Can mix entire volume, if air is aspirated, it will just be dispensed first without making a bubble
        if self.volume>MAXVOLUME-extraspace:
            mixvol=MAXVOLUME-extraspace
            logging.mixwarning("Mix of %s limited to %.0f ul instead of full volume of %.0ful"%(self.name,mixvol,self.volume))
        well=[self.well if self.well!=None else 2**(tipMask-1)-1 ]
        mixprefillvol=5
        if mixvol<self.plate.unusableVolume-mixprefillvol:
            logging.notice("Not enough volume in sample %s (%.1f) to mix"%(self.name,self.volume))
            self.history+="(UNMIXED)"
            return False
        else:
            if preaspirateAir:
                # Aspirate some air to avoid mixing with excess volume aspirated into pipette from source in previous transfer
                self.aspirateAir(tipMask,5)
            if False:		# this results in losing mixprefillvol of sample which was not mixed; remainder has different concentration than planned
                worklist.aspirateNC(tipMask,well,self.inliquidLC,mixprefillvol,self.plate)
                self.volume-=mixprefillvol
                self.addhistory("(PRE)",-mixprefillvol,tipMask)
                worklist.mix(tipMask,well,self.mixLC,mixvol,self.plate,nmix)
                mstr="(MB)"
            elif False: # self.volume>=MINLIQUIDDETECTVOLUME:    # Another short-lived strategy
                worklist.mix(tipMask,well,self.inliquidLC,mixvol,self.plate,nmix)
                self.history+="(MLD)"
            else:
                height=self.plate.getliquidheight(self.volume)
                if height is None:
                    worklist.mix(tipMask,well,self.mixLC,mixvol,self.plate,nmix)
                    mstr="(MB)"
                else:
                    mixheight=math.floor(height-1)			# At least 1mm below liquid height
                    if mixheight<2:
                        mixheight=2
#                    print 'Vol=%.1f ul, height=%.1f mm, mix=%d, blow=%d'%(self.volume,height,mixheight,blowheight)
                    mixLC=liquidclass.LCMix[min(12,mixheight)]
                    if blowvol>0:
                        blowoutLC=liquidclass.LCBlowoutLD
                        worklist.aspirateNC(tipMask,well,self.airLC,(blowvol+0.1),self.plate)
                    if self.volume<30:
                        worklist.mix(tipMask,well,self.mixLC,mixvol,self.plate,nmix)
                        mstr="(MB)"
                    else:
                        for _ in range(nmix):
                            worklist.aspirateNC(tipMask,well,mixLC,mixvol,self.plate)
                            worklist.dispense(tipMask,well,mixLC,mixvol,self.plate)
                        mstr="(M@%d)"%(mixheight)
                    if blowvol>0:
                        worklist.dispense(tipMask,well,blowoutLC,blowvol,self.plate)
                        worklist.dispense(tipMask,well,liquidclass.LCDip,0.1,self.plate)

            self.volume-=MIXLOSS
            self.addhistory(mstr,-MIXLOSS,tipMask)
            self.lastMixed=clock.elapsed()
            self.wellMixed=True
            return True
예제 #14
0
    def __init__(self,name,plate,well=None,conc=None,volume=0,hasBeads=False,extraVol=50,mixLC=liquidclass.LCMixBottom,firstWell=None,extrainfo=[],ingredients=None,atEnd=False):
        # If firstWell is not None, then it is a hint of the first well position that should be used
        if well!=None and well!=-1:
            if not isinstance(well,int):
                well=plate.wellnumber(well)
            if well not in plate.wells:
                logging.warning("Attempt to assign sample %s to well %d (%s) which is not legal on plate %s"%(name,well,plate.wellname(well),plate.name))
            for s in __allsamples:
                if s.well==well and s.plate==plate:
                    logging.warning("Attempt to assign sample %s to plate %s, well %s that already contains %s"%(name,str(plate),plate.wellname(well),s.name))
                    well=None
                    break

        if well is None:
            # Find first unused well
            found=False
            if firstWell is not None:
                # First check only wells>=firstWell
                for well in plate.wells:
                    if well<firstWell:
                        continue
                    found=True
                    for s in __allsamples:
                        if s.plate==plate and s.well==well:
                            well=well+1
                            found=False
                            break
                    if found:
                        break

            if not found:
                well=max(plate.wells) if atEnd else min(plate.wells) 
                while (well>=0) if atEnd else (well<=max(plate.wells)):
                    found=True
                    for s in __allsamples:
                        if s.plate==plate and s.well==well:
                            well=well+(-1 if atEnd else 1)
                            found=False
                            break
                    if found:
                        break
        elif well==-1:
            well=None

        for s in __allsamples:
            if s.plate==plate and s.well==well:
                logging.error("Attempt to assign sample %s to plate %s, well %s that already contains %s"%(name,str(plate),plate.wellname(well),s.name))
        if name in [s.name for s in __allsamples]:
            while name in [s.name for s in __allsamples]:
                name=name+"#"
            logging.notice("renaming sample to %s"%name)
        self.name=name
        self.plate=plate
        if well>=plate.nx*plate.ny:
            logging.error("Overflow of plate %s while adding %s"%(str(plate),name))

        self.well=well
        if isinstance(conc,Concentration) or conc is None:
            self.conc=conc
        else:
            self.conc=Concentration(conc)
        self.volume=volume
        self.initVol=volume
        if volume>0:
            if ingredients is None:
                self.ingredients={name:volume}
            else:
                self.ingredients=ingredients
                total=sum([v for v in ingredients.values()])
                for k in self.ingredients:
                    self.ingredients[k]=self.ingredients[k]*volume/total
            self.lastvolcheck=None
        else:
            self.ingredients={}
            self.lastvolcheck=0   # Assume that it has already been checked for 0 (since it can't be any less...)

        if plate.pierce:
            self.bottomLC=liquidclass.LCWaterPierce
            self.bottomSideLC=self.bottomLC  # Can't use side with piercing
            self.inliquidLC=self.bottomLC  # Can't use liquid detection when piercing
        else:
            self.bottomLC=liquidclass.LCWaterBottom
            self.bottomSideLC=liquidclass.LCWaterBottomSide
            self.inliquidLC=liquidclass.LCWaterInLiquid

        self.beadsLC=liquidclass.LCWaterBottomBeads
        self.mixLC=mixLC
        self.airLC=liquidclass.LCAir
        # Same as bottom for now
        self.emptyLC=self.bottomLC
        self.history=""
        __allsamples.append(self)
        if hasBeads:
            self.lastMixed=None
        else:
            self.lastMixed=clock.elapsed()-20*60		# Assume it was last mixed an 20 min before start of run
        self.wellMixed=True
        self.initHasBeads=hasBeads
        self.hasBeads=hasBeads		# Setting this to true overrides the manual conditioning
        self.extraVol=extraVol			# Extra volume to provide
        self.evap=0   # Amount that has evaporated
        if self.plate.name=="Samples":
            self.lastevapupdate=clock.pipetting
        else:
            self.lastevapupdate=clock.elapsed()
        self.extrainfo=extrainfo
        self.emptied=False
예제 #15
0
    def aspirate(self,tipMask,volume,multi=False):
        self.evapcheck('aspirate')
        if self.plate.curloc=='PTC':
            logging.error( "Aspirate from PTC!, loc=%d,%d"%(self.plate.grid,self.plate.pos))

        removeAll=volume==self.volume
        if removeAll:
            logging.notice("Removing all contents (%.1ful) from %s"%(volume,self.name))
            
        if volume<0.1:
            logging.warning("attempt to aspirate only %.1f ul from %s ignored"%(volume,self.name))
            return
        if volume<2 and not multi and self.name!="Water":
            logging.warning("Inaccurate for < 2ul:  attempting to aspirate %.1f ul from %s"%(volume,self.name))
        if volume>self.volume and self.volume>0:
            logging.error("Attempt to aspirate %.1f ul from %s that contains only %.1f ul"%(volume, self.name, self.volume))
        if not self.isMixed() and self.plate.curloc!="Magnet":
            if self.hasBeads and self.lastMixed is not None:
                logging.mixwarning("Aspirate %.1f ul from sample %s that has beads and has not been mixed for %.0f sec. "%(volume,self.name,clock.elapsed()-self.lastMixed))
            else:
                logging.mixwarning("Aspirate %.1f ul from unmixed sample %s. "%(volume,self.name))
        if not self.wellMixed and self.plate.curloc!="Magnet":
            logging.mixwarning("Aspirate %.1f ul from poorly mixed sample %s (shake speed was too low). "%(volume,self.name))

        if self.well is None:
            well=[]
            for i in range(4):
                if (tipMask & (1<<i)) != 0:
                    well.append(i)
        else:
            well=[self.well]

        lc=self.chooseLC(volume)
            
        self.volcheck(tipMask,well,volume)

        if (self.hasBeads and self.plate.curloc=="Magnet") or removeAll:
            # With beads don't do any manual conditioning and don't remove extra (since we usually want to control exact amounts left behind, if any)
            worklist.aspirateNC(tipMask,well,lc,volume,self.plate)
            remove=lc.volRemoved(volume,multi=False)
            if self.volume==volume:
                # Removing all, ignore excess remove
                remove=self.volume-0.1   # Leave behind enough to be able to keep track of ingredients
                self.emptied=True
        else:
            worklist.aspirate(tipMask,well,lc,volume,self.plate)
            # Manual conditioning handled in worklist
            remove=lc.volRemoved(volume,multi=True)

            if self.volume<remove+0.1 and self.volume>0:
                logging.warning("Removing all contents (%.1f from %.1ful) from %s"%(remove,self.volume,self.name))
                remove=self.volume-0.1   # Leave residual

        for k in self.ingredients:
            self.ingredients[k] *= (self.volume-remove)/self.volume

        self.volume=self.volume-remove
        if self.volume+.001<self.plate.unusableVolume and self.volume+remove>0 and not (self.hasBeads and self.plate.curloc=='Magnet') and not removeAll:
            logging.warning("Aspiration of %.1ful from %s brings volume down to %.1ful which is less than its unusable volume of %.1f ul"%(remove,self.name,self.volume,self.plate.unusableVolume))
            
        self.addhistory("",-remove,tipMask)
예제 #16
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
    def aspirate(self, tipMask, volume, multi=False):
        self.evapcheck('aspirate')
        if self.plate.curloc == 'PTC':
            print "Aspirate from PTC!, loc=", self.plate.grid, ",", self.plate.pos
            assert False

        if volume < 0.1:
            print "WARNING: attempt to aspirate only %.1f ul from %s ignored" % (
                volume, self.name)
            return
        if volume < 2 and not multi and self.name != "Water":
            print "WARNING: Inaccurate for < 2ul:  attempting to aspirate %.1f ul from %s" % (
                volume, self.name)
        if volume > self.volume and self.volume > 0:
            print "ERROR:Attempt to aspirate %.1f ul from %s that contains only %.1f ul" % (
                volume, self.name, self.volume)
        if not self.isMixed() and self.plate.curloc != "Magnet":
            if self.hasBeads and self.lastMixed is not None:
                print "WARNING: Aspirate %.1f ul from sample %s that has beads and has not been mixed for %.0f sec. " % (
                    volume, self.name, clock.elapsed() - self.lastMixed)
            else:
                print "WARNING: Aspirate %.1f ul from unmixed sample %s. " % (
                    volume, self.name)
        if not self.wellMixed:
            print "WARNING: Aspirate %.1f ul from poorly mixed sample %s (shake speed was too low). " % (
                volume, self.name)

        if self.well is None:
            well = []
            for i in range(4):
                if (tipMask & (1 << i)) != 0:
                    well.append(i)
        else:
            well = [self.well]

        lc = self.chooseLC(volume)
        if self.hasBeads and self.plate.curloc == "Magnet":
            # With beads don't do any manual conditioning and don't remove extra (since we usually want to control exact amounts left behind, if any)
            worklist.aspirateNC(tipMask, well, lc, volume, self.plate)
            remove = lc.volRemoved(volume, multi=False)
            if self.volume == volume:
                # Removing all, ignore excess remove
                remove = self.volume
                self.ingredients = {}
        else:
            worklist.aspirate(tipMask, well, lc, volume, self.plate)
            # Manual conditioning handled in worklist
            remove = lc.volRemoved(volume, multi=True)

        if self.volume < remove and self.volume > 0:
            print "WARNING: Removing all contents (%.1f from %.1ful) from %s" % (
                remove, self.volume, self.name)
            remove = self.volume
            self.ingredients = {}
        for k in self.ingredients:
            if self.plate.curloc == "Magnet" and k == 'BIND':
                pass
            else:
                self.ingredients[k] *= (self.volume - remove) / self.volume

        self.volume = self.volume - remove
        if self.volume + .001 < self.plate.unusableVolume and self.volume + remove > 0 and not (
                self.hasBeads and self.plate.curloc == 'Magnet'):
            print "WARNING: Aspiration of %.1ful from %s brings volume down to %.1ful which is less than its unusable volume of %.1f ul" % (
                remove, self.name, self.volume, self.plate.unusableVolume)

        self.addhistory("", -remove, tipMask)
예제 #17
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
    def __init__(self,name,plate,well=None,conc=None,volume=0,hasBeads=False,extraVol=50,mixLC=liquidclass.LCMixBottom):
        if well!=None and well!=-1:
            if not isinstance(well,int):
                well=plate.wellnumber(well)
            if well not in plate.wells:
                print "Attempt to assign sample %s to well %d (%s) which is not legal on plate %s"%(name,well,plate.wellname(well),plate.name)
            for s in __allsamples:
                if s.well==well and s.plate==plate:
                    print "Attempt to assign sample %s to plate %s, well %s that already contains %s"%(name,str(plate),plate.wellname(well),s.name)
                    well=None
                    break

        if well is None:
            # Find first unused well
            found=False
            for well in plate.wells:
                found=True
                for s in __allsamples:
                    if s.plate==plate and s.well==well:
                        well=well+1
                        found=False
                        break
                if found:
                    break
        elif well==-1:
            well=None

        for s in __allsamples:
            if s.plate==plate and s.well==well:
                print "Attempt to assign sample %s to plate %s, well %s that already contains %s"%(name,str(plate),plate.wellname(well),s.name)
#                print "Aliasing %s as %s"%(s.name,name)
                assert False
        if name in [s.name for s in __allsamples]:
            while name in [s.name for s in __allsamples]:
                name=name+"#"
            print "NOTICE: renaming sample to %s"%name
        self.name=name
        self.plate=plate
        if well>=plate.nx*plate.ny:
            print "Overflow of plate %s"%str(plate)
            for s in __allsamples:
                if s.plate==plate:
                    print s
            assert False

        self.well=well
        if isinstance(conc,Concentration) or conc is None:
            self.conc=conc
        else:
            self.conc=Concentration(conc)
        self.volume=volume
        if volume>0:
            self.ingredients={name:volume}
        else:
            self.ingredients={}

        if plate.pierce:
            self.bottomLC=liquidclass.LCWaterPierce
            self.bottomSideLC=self.bottomLC  # Can't use side with piercing
            self.inliquidLC=self.bottomLC  # Can't use liquid detection when piercing
        else:
            self.bottomLC=liquidclass.LCWaterBottom
            self.bottomSideLC=liquidclass.LCWaterBottomSide
            self.inliquidLC=liquidclass.LCWaterInLiquid

        self.beadsLC=liquidclass.LCWaterBottomBeads
        self.mixLC=mixLC
        self.airLC=liquidclass.LCAir
        # Same as bottom for now
        self.emptyLC=self.bottomLC
        self.history=""
        __allsamples.append(self)
        if hasBeads:
            self.lastMixed=None
        else:
            self.lastMixed=clock.elapsed()-20*60		# Assume it was last mixed an 20 min before start of run
        self.wellMixed=True
        self.initHasBeads=hasBeads
        self.hasBeads=hasBeads		# Setting this to true overrides the manual conditioning
        self.extraVol=extraVol			# Extra volume to provide
        self.evap=0   # Amount that has evaporated
        if self.plate.name=="Samples":
            self.lastevapupdate=clock.pipetting
        else:
            self.lastevapupdate=clock.elapsed()
예제 #18
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
    def __init__(self,
                 name,
                 plate,
                 well=None,
                 conc=None,
                 volume=0,
                 hasBeads=False,
                 extraVol=50,
                 mixLC=liquidclass.LCMixBottom):
        if well != None and well != -1:
            if not isinstance(well, int):
                well = plate.wellnumber(well)
            if well not in plate.wells:
                print "Attempt to assign sample %s to well %d (%s) which is not legal on plate %s" % (
                    name, well, plate.wellname(well), plate.name)
            for s in __allsamples:
                if s.well == well and s.plate == plate:
                    print "Attempt to assign sample %s to plate %s, well %s that already contains %s" % (
                        name, str(plate), plate.wellname(well), s.name)
                    well = None
                    break

        if well is None:
            # Find first unused well
            found = False
            for well in plate.wells:
                found = True
                for s in __allsamples:
                    if s.plate == plate and s.well == well:
                        well = well + 1
                        found = False
                        break
                if found:
                    break
        elif well == -1:
            well = None

        for s in __allsamples:
            if s.plate == plate and s.well == well:
                print "Attempt to assign sample %s to plate %s, well %s that already contains %s" % (
                    name, str(plate), plate.wellname(well), s.name)
                #                print "Aliasing %s as %s"%(s.name,name)
                assert False
        if name in [s.name for s in __allsamples]:
            while name in [s.name for s in __allsamples]:
                name = name + "#"
            print "NOTICE: renaming sample to %s" % name
        self.name = name
        self.plate = plate
        if well >= plate.nx * plate.ny:
            print "Overflow of plate %s" % str(plate)
            for s in __allsamples:
                if s.plate == plate:
                    print s
            assert False

        self.well = well
        if isinstance(conc, Concentration) or conc is None:
            self.conc = conc
        else:
            self.conc = Concentration(conc)
        self.volume = volume
        if volume > 0:
            self.ingredients = {name: volume}
        else:
            self.ingredients = {}

        if plate.pierce:
            self.bottomLC = liquidclass.LCWaterPierce
            self.bottomSideLC = self.bottomLC  # Can't use side with piercing
            self.inliquidLC = self.bottomLC  # Can't use liquid detection when piercing
        else:
            self.bottomLC = liquidclass.LCWaterBottom
            self.bottomSideLC = liquidclass.LCWaterBottomSide
            self.inliquidLC = liquidclass.LCWaterInLiquid

        self.beadsLC = liquidclass.LCWaterBottomBeads
        self.mixLC = mixLC
        self.airLC = liquidclass.LCAir
        # Same as bottom for now
        self.emptyLC = self.bottomLC
        self.history = ""
        __allsamples.append(self)
        if hasBeads:
            self.lastMixed = None
        else:
            self.lastMixed = clock.elapsed(
            ) - 20 * 60  # Assume it was last mixed an 20 min before start of run
        self.wellMixed = True
        self.initHasBeads = hasBeads
        self.hasBeads = hasBeads  # Setting this to true overrides the manual conditioning
        self.extraVol = extraVol  # Extra volume to provide
        self.evap = 0  # Amount that has evaporated
        if self.plate.name == "Samples":
            self.lastevapupdate = clock.pipetting
        else:
            self.lastevapupdate = clock.elapsed()
예제 #19
0
    def savesummary(self,filename):
        # Print amount of samples needed
        fd=open(filename,"w")
        # print >>fd,"Deck layout:"
        # print >>fd,decklayout.REAGENTPLATE
        # print >>fd,decklayout.SAMPLEPLATE
        # print >>fd,decklayout.QPCRPLATE
        # print >>fd,decklayout.WATERLOC
        # print >>fd,decklayout.WASTE
        # print >>fd,decklayout.BLEACHLOC
        # print >>fd,decklayout.WASHLOC
        # print >>fd
        #print >>fd,"DiTi usage:",worklist.getDITIcnt()
        #print >>fd

        rtime="Run time: %d (pipetting only) + %d (thermocycling only) + %d (both) = %d minutes\n"%(clock.pipetting/60.0,clock.thermotime/60, clock.pipandthermotime/60, clock.elapsed()/60)
        print rtime
        print >>fd,rtime
        reagents.printprep(fd)
        Sample.printallsamples("All Samples:",fd,w=worklist)
        liquidclass.LC.printalllc("All LC:",fd)
        fd.close()
예제 #20
0
파일: sample.py 프로젝트: qPCR4vir/pyTecan
    def aspirate(self,tipMask,volume,multi=False):
        self.evapcheck('aspirate')
        if self.plate.curloc=='PTC':
            print "Aspirate from PTC!, loc=",self.plate.grid,",",self.plate.pos
            assert False

        if volume<0.1:
            print "WARNING: attempt to aspirate only %.1f ul from %s ignored"%(volume,self.name)
            return
        if volume<2 and not multi and self.name!="Water":
            print "WARNING: Inaccurate for < 2ul:  attempting to aspirate %.1f ul from %s"%(volume,self.name)
        if volume>self.volume and self.volume>0:
            print "ERROR:Attempt to aspirate %.1f ul from %s that contains only %.1f ul"%(volume, self.name, self.volume)
        if not self.isMixed() and self.plate.curloc!="Magnet":
            if self.hasBeads and self.lastMixed is not None:
                print "WARNING: Aspirate %.1f ul from sample %s that has beads and has not been mixed for %.0f sec. "%(volume,self.name,clock.elapsed()-self.lastMixed)
            else:
                print "WARNING: Aspirate %.1f ul from unmixed sample %s. "%(volume,self.name)
        if not self.wellMixed:
            print "WARNING: Aspirate %.1f ul from poorly mixed sample %s (shake speed was too low). "%(volume,self.name)
                
        if self.well is None:
            well=[]
            for i in range(4):
                if (tipMask & (1<<i)) != 0:
                    well.append(i)
        else:
            well=[self.well]

        lc=self.chooseLC(volume)
        if self.hasBeads and self.plate.curloc=="Magnet":
            # With beads don't do any manual conditioning and don't remove extra (since we usually want to control exact amounts left behind, if any)
            worklist.aspirateNC(tipMask,well,lc,volume,self.plate)
            remove=lc.volRemoved(volume,multi=False)
            if self.volume==volume:
                # Removing all, ignore excess remove
                remove=self.volume
                self.ingredients={}
        else:
            worklist.aspirate(tipMask,well,lc,volume,self.plate)
            # Manual conditioning handled in worklist
            remove=lc.volRemoved(volume,multi=True)

        if self.volume<remove and self.volume>0:
            print "WARNING: Removing all contents (%.1f from %.1ful) from %s"%(remove,self.volume,self.name)
            remove=self.volume
            self.ingredients={}
        for k in self.ingredients:
            if self.plate.curloc=="Magnet" and k=='BIND':
                pass
            else:
                self.ingredients[k] *= (self.volume-remove)/self.volume

        self.volume=self.volume-remove
        if self.volume+.001<self.plate.unusableVolume and self.volume+remove>0 and not (self.hasBeads and self.plate.curloc=='Magnet'):
            print "WARNING: Aspiration of %.1ful from %s brings volume down to %.1ful which is less than its unusable volume of %.1f ul"%(remove,self.name,self.volume,self.plate.unusableVolume)
            
        self.addhistory("",-remove,tipMask)
예제 #21
0
    def aspirate(self, tipMask, volume, multi=False):
        self.evapcheck('aspirate')
        if self.plate.curloc == 'PTC':
            logging.error("Aspirate from PTC!, loc=%d,%d" %
                          (self.plate.grid, self.plate.pos))

        removeAll = volume == self.volume
        if removeAll:
            logging.notice("Removing all contents (%.1ful) from %s" %
                           (volume, self.name))

        if volume < 0.1:
            logging.warning(
                "attempt to aspirate only %.1f ul from %s ignored" %
                (volume, self.name))
            return
        if volume < 2 and not multi and self.name != "Water":
            logging.warning(
                "Inaccurate for < 2ul:  attempting to aspirate %.1f ul from %s"
                % (volume, self.name))
        if volume > self.volume and self.volume > 0:
            logging.error(
                "Attempt to aspirate %.1f ul from %s that contains only %.1f ul"
                % (volume, self.name, self.volume))
        if not self.isMixed() and self.plate.curloc != "Magnet":
            if self.hasBeads and self.lastMixed is not None:
                logging.mixwarning(
                    "Aspirate %.1f ul from sample %s that has beads and has not been mixed for %.0f sec. "
                    % (volume, self.name, clock.elapsed() - self.lastMixed))
            else:
                logging.mixwarning(
                    "Aspirate %.1f ul from unmixed sample %s. " %
                    (volume, self.name))
        if not self.wellMixed and self.plate.curloc != "Magnet":
            logging.mixwarning(
                "Aspirate %.1f ul from poorly mixed sample %s (shake speed was too low). "
                % (volume, self.name))

        if self.well is None:
            well = []
            for i in range(4):
                if (tipMask & (1 << i)) != 0:
                    well.append(i)
        else:
            well = [self.well]

        lc = self.chooseLC(volume)

        self.volcheck(tipMask, well, volume)

        if (self.hasBeads and self.plate.curloc == "Magnet") or removeAll:
            # With beads don't do any manual conditioning and don't remove extra (since we usually want to control exact amounts left behind, if any)
            worklist.aspirateNC(tipMask, well, lc, volume, self.plate)
            remove = lc.volRemoved(volume, multi=False)
            if self.volume == volume:
                # Removing all, ignore excess remove
                remove = self.volume - 0.1  # Leave behind enough to be able to keep track of ingredients
                self.emptied = True
        else:
            worklist.aspirate(tipMask, well, lc, volume, self.plate)
            # Manual conditioning handled in worklist
            remove = lc.volRemoved(volume, multi=True)

            if self.volume < remove + 0.1 and self.volume > 0:
                logging.warning(
                    "Removing all contents (%.1f from %.1ful) from %s" %
                    (remove, self.volume, self.name))
                remove = self.volume - 0.1  # Leave residual

        self.removeVolume(remove)
        if self.volume + .001 < self.plate.unusableVolume and self.volume + remove > 0 and not (
                self.hasBeads
                and self.plate.curloc == 'Magnet') and not removeAll:
            logging.warning(
                "Aspiration of %.1ful from %s brings volume down to %.1ful which is less than its unusable volume of %.1f ul"
                % (remove, self.name, self.volume, self.plate.unusableVolume))

        self.addhistory("", -remove, tipMask)
예제 #22
0
 def savesummary(self,filename):
     # Print amount of samples needed
     fd=open(filename,"w")
     # print >>fd,"Deck layout:"
     # print >>fd,decklayout.REAGENTPLATE
     # print >>fd,decklayout.SAMPLEPLATE
     # print >>fd,decklayout.QPCRPLATE
     # print >>fd,decklayout.WATERLOC
     # print >>fd,decklayout.WASTE
     # print >>fd,decklayout.BLEACHLOC
     # print >>fd,decklayout.WASHLOC
     # print >>fd
     #print >>fd,"DiTi usage:",worklist.getDITIcnt()
     #print >>fd
     print >>fd,"Generated %s (%s-%s pyTecan-%s)"%(datetime.now().ctime(),sys.argv[0],self.checksum,self.gitlabel)
     rtime="Run time: %d (pipetting only) + %d (thermocycling only) + %d (both) = %d minutes (%.1f hours)\n"%(clock.pipetting/60.0,clock.thermotime/60, clock.pipandthermotime/60, clock.elapsed()/60, clock.elapsed()/3600.0)
     print rtime
     print >>fd,rtime
     reagents.printprep(fd)
     Sample.printallsamples("All Samples:",fd,w=worklist)
     liquidclass.LC.printalllc(fd)
     fd.close()
예제 #23
0
    def mix(self, tipMask, preaspirateAir=False, nmix=4):
        if self.isMixed() and self.wellMixed:
            logging.notice(
                "mix() called for sample %s, which is already mixed" %
                self.name)
            return False
        logging.mixwarning("Pipette mixing of %s may introduce bubbles" %
                           self.name)

        self.volcheck(tipMask, [self.well], 0)

        blowvol = 5
        mstr = ""
        extraspace = blowvol + 0.1
        if preaspirateAir:
            extraspace += 5
        mixvol = self.volume  # -self.plate.unusableVolume;  # Can mix entire volume, if air is aspirated, it will just be dispensed first without making a bubble
        if self.volume > MAXVOLUME - extraspace:
            mixvol = MAXVOLUME - extraspace
            logging.mixwarning(
                "Mix of %s limited to %.0f ul instead of full volume of %.0ful"
                % (self.name, mixvol, self.volume))
        well = [self.well if self.well != None else 2**(tipMask - 1) - 1]
        mixprefillvol = 5
        if mixvol < self.plate.unusableVolume - mixprefillvol:
            logging.notice("Not enough volume in sample %s (%.1f) to mix" %
                           (self.name, self.volume))
            self.history += "(UNMIXED)"
            return False
        else:
            if preaspirateAir:
                # Aspirate some air to avoid mixing with excess volume aspirated into pipette from source in previous transfer
                self.aspirateAir(tipMask, 5)
            if False:  # this results in losing mixprefillvol of sample which was not mixed; remainder has different concentration than planned
                worklist.aspirateNC(tipMask, well, self.inliquidLC,
                                    mixprefillvol, self.plate)
                self.removeVolume(mixprefillvol)
                self.addhistory("(PRE)", -mixprefillvol, tipMask)
                worklist.mix(tipMask, well, self.mixLC, mixvol, self.plate,
                             nmix)
                mstr = "(MB)"
            elif False:  # self.volume>=MINLIQUIDDETECTVOLUME:    # Another short-lived strategy
                worklist.mix(tipMask, well, self.inliquidLC, mixvol,
                             self.plate, nmix)
                self.history += "(MLD)"
            else:
                height = self.plate.getliquidheight(self.volume)
                if height is None:
                    worklist.mix(tipMask, well, self.mixLC, mixvol, self.plate,
                                 nmix)
                    mstr = "(MB)"
                else:
                    mixheight = math.floor(
                        height - 1)  # At least 1mm below liquid height
                    if mixheight < 2:
                        mixheight = 2
#                    print 'Vol=%.1f ul, height=%.1f mm, mix=%d, blow=%d'%(self.volume,height,mixheight,blowheight)
                    mixLC = liquidclass.LCMix[min(12, mixheight)]
                    if blowvol > 0:
                        blowoutLC = liquidclass.LCBlowoutLD
                        worklist.aspirateNC(tipMask, well, self.airLC,
                                            (blowvol + 0.1), self.plate)
                    if self.volume < 30:
                        worklist.mix(tipMask, well, self.mixLC, mixvol,
                                     self.plate, nmix)
                        mstr = "(MB)"
                    else:
                        for _ in range(nmix):
                            worklist.aspirateNC(tipMask, well, mixLC, mixvol,
                                                self.plate)
                            worklist.dispense(tipMask, well, mixLC, mixvol,
                                              self.plate)
                        mstr = "(M@%d)" % (mixheight)
                    if blowvol > 0:
                        worklist.dispense(tipMask, well, blowoutLC, blowvol,
                                          self.plate)
                        worklist.dispense(tipMask, well, liquidclass.LCDip,
                                          0.1, self.plate)

            self.removeVolume(MIXLOSS)
            self.addhistory(mstr, -MIXLOSS, tipMask)
            self.lastMixed = clock.elapsed()
            self.wellMixed = True
            return True