Пример #1
0
    def runQPCRDIL(self,src,vol,srcdil,tgt=None,dilPlate=False,pipMix=False,dilutant=decklayout.SSDDIL):
        [src,vol,srcdil]=listify([src,vol,srcdil])
        vol=[float(v) for v in vol]
        if tgt is None:
            if dilPlate:
                tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.DILPLATE) for i in range(len(src))]
            else:
                tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.SAMPLEPLATE) for i in range(len(src))]

        srcvol=[vol[i]/srcdil[i] for i in range(len(vol))]
        watervol=[vol[i]-srcvol[i] for i in range(len(vol))]
        if len(watervol) > 4 and sum(watervol)>800:
            logging.notice("Could optimize distribution of "+str(len(watervol))+" moves of "+dilutant.name+": vol=["+str(["%.1f"%w for w in watervol])+"]")
        self.e.multitransfer(watervol,dilutant,tgt,(False,False))
        
        self.e.shakeSamples(src,returnPlate=True)
        for i in range(len(src)):
            tgt[i].conc=None		# Assume dilutant does not have a concentration of its own
            # Check if we can align the tips here
            if i<len(src)-3 and tgt[i].well+1==tgt[i+1].well and tgt[i].well+2==tgt[i+2].well and tgt[i].well+3==tgt[i+3].well and tgt[i].well%4==0 and self.e.cleanTips!=15:
                #print "Aligning tips"
                self.e.sanitize()
            self.e.transfer(srcvol[i],src[i],tgt[i],(not src[i].isMixed(),pipMix))
            if tgt[i].conc != None:
                tgt[i].conc.final=None	# Final conc are meaningless now
            
        return tgt
Пример #2
0
 def __str__(self):
     s=""
     logging.notice(self.logentries)
     for e in self.logentries:
         le=self.logentries[e]
         s=s+str(le[0].sample)+":""\n"
         for ee in self.logentries[e]:
             s=s+"  "+str(ee)+"\n"
     return s
Пример #3
0
    def logmeasure(self,tip,height,submerge,zmax,zadd,time):
        # Time is the time in seconds of this measurement
        sample=self.lastSample[tip]
        if len(sample.extrainfo)>0:
            elapsed=time-sample.extrainfo[0]
        else:
            elapsed=timedelta(0)

        #print "%s: %f"%(sample.name,elapsed)
        sample.extrainfo=[time]    # Keep track of last measurement time of this sample in the extrainfo list
        if sample.plate.location.zmax is not None:
            curzmax=2100-sample.plate.location.zmax-390+TIPOFFSETS[tip-1]
            if zmax!=curzmax:
                logging.warning("ZMax for plate %s, tip %d at time of run was %.0f, currently at %.0f"%(sample.plate.name, tip, zmax, curzmax))
                zmax=curzmax
        prevol=sample.volume-sample.lastadd		# Liquid height is measured before next op, whose volume effect has already been added to sample.volume
        if height==-1:
            vol=sample.plate.getliquidvolume((zadd+submerge)/10.0)
            if vol is not None:
                if prevol<vol and prevol!=0:
                    # The liquid measure failed, but based on the previous volume estimate, it was guaranteed to fail since the submerge depth would've been below bottom
                    # But if we don't know the volume (ie a prefilled tube -> prevol=0), then log this as a fail
                    h=" @[DEEP <%.1fmm:<%.1ful#%d]"%((zadd+submerge)/10.0,vol,tip)
                    #h=""
                else:
                    h=" @[FAIL <%.1fmm:<%.1ful#%d]"%((zadd+submerge)/10,vol,tip)
            else:
                h=" @[FAIL <%.1f#%d]"%((zadd+submerge)/10.0,tip)
        else:
            vol=sample.plate.getliquidvolume((height+submerge-zmax)/10.0)
            if vol is None:
                h=" @[%.1fmm,%.1fmm#%d]"%((height-zmax)/10.0,submerge/10.0,tip)
            else:
                if prevol==0:
                    logging.notice("Got a liquid height measurement for a well that should be empty -- assuming it was prefilled")
                    sample.volume=vol+sample.lastadd
                    prevol=vol
                expectHeight=sample.plate.getliquidheight(prevol)
                errorHeight=(height+submerge-zmax)-expectHeight*10
                h=" @[%.1fmm,%.1fmm:%.1ful#%d]"%((height-zmax)/10.0,submerge/10.0,vol,tip)
                if abs(errorHeight)>1:
                    if abs(errorHeight)>4:
                        emphasize="*"*(min(10,int(abs(errorHeight))-3))
                    else:
                        emphasize=''
                    h=h+"{%sE=%d;%.1ful}"%(emphasize,errorHeight,vol-prevol)
                sample.volume=sample.volume+(vol-prevol)
        # Insert BEFORE last history entry since the liquid height is measured before aspirate/dispense
        hsplit=sample.history.split(' ')
        if elapsed.total_seconds()>=600:   # Log elapsed time if more than 10 min
            sample.history=" ".join(hsplit[:-1]+["(T%.0f)"%(elapsed.total_seconds()/60)]+[h]+hsplit[-1:])
        else:
            sample.history=" ".join(hsplit[:-1]+[h]+hsplit[-1:])
Пример #4
0
    def __init__(self,op,tip,vol,wellx,welly,rack,grid,pos,lc,std,volset,isMulti):
        self.op=op
        self.tip=tip
        self.vol=vol
        self.lc=lc
        self.std=std
        self.volset=volset
        self.isMulti=isMulti
        self.sample=getSample(wellx,welly,rack,grid,pos)


        if lc=='Air' or lc[0:7]=='Blowout' or lc=='Dip':
            if op=='dispense':
                self.sample.addhistory(lc,vol,tip)
            elif op=='aspirate':
                self.sample.addhistory(lc,-vol,tip)
            else:
                logging.notice("LogEntry: bad op (%s) for LC %s"%(op,lc))
                assert False
            self.sample.lastadd=0
        elif op=='dispense':
            self.sample.addhistory("",vol,tip)
            self.sample.lastadd=vol
        elif op=='detect':
            self.sample.addhistory("detect",0,tip)
            self.sample.lastadd=0
        elif op=='aspirate':
            self.sample.addhistory("",-vol,tip)
            self.sample.lastadd=-(vol+SURFACEREMOVE)	# Extra for tip wetting
        elif op[0:3]=='mix':
            self.sample.addhistory(op,vol,tip)
            self.sample.lastadd=0
        else:
            logging.warning("LogEntry: bad op: %s"%op)
            assert False
        if self.sample.volume+self.sample.lastadd<0 and self.sample.volume!=0:
            self.sample.history=self.sample.history + ("{Emptied%.2f}"%(self.sample.volume+self.sample.lastadd))
            self.sample.volume=0
        else:
            self.sample.volume+=self.sample.lastadd
Пример #5
0
    def addSamples(self, src, needDil, primers, nreplicates=1, names=None, saveVol=None, saveDil=None, save=True):
        """Add sample(s) to list of qPCRs to do"""
        # print "addSamples(%s)"%src
        if not isinstance(src, list):
            src = [src]
        if save:
            # saveVol is total amount (after dilution) to be immediately saved
            if saveDil is None:
                saveDil = min(needDil, self.MAXDIL)
                if 1 < needDil / saveDil < 2:
                    saveDil = math.sqrt(needDil)
            elif saveDil > needDil:
                logging.warning("addSamples: saveDil=" + saveDil + ", but needDil is only " + needDil)
                saveDil = needDil

            if saveVol is None:
                saveVol = max(self.MINDILVOL * 1.0 / saveDil, self.TGTINVOL)

            if names is None:
                tgt = [Sample(diluteName(src[i].name, saveDil), decklayout.DILPLATE) for i in range(len(src))]
            else:
                tgt = [Sample(diluteName(names[i], saveDil), decklayout.DILPLATE) for i in range(len(src))]
            sv = tgt

            for i in range(len(sv)):
                # print "Save ",src[i]
                svtmp = self.trp.runQPCRDIL(src=[src[i]], vol=saveVol * saveDil, srcdil=saveDil, tgt=[tgt[i]],
                                            dilPlate=True, dilutant=self.dilutant)
                sv[i] = svtmp[0]
        else:
            saveDil = 1
            sv = src

        needDil = needDil / saveDil
        nstages = int(math.ceil(math.log(needDil) / math.log(self.MAXDIL)))
        ndil = len(src) * (nstages + (1 if save else 0))
        logging.notice("QPCR: %dQ/%dD [%s], dilution:%.1fx, primers: [%s]" % (
            len(src) * len(primers) * nreplicates, ndil,
            ",".join([s.name for s in src]) if names is None else ",".join(names), needDil, ",".join(primers)))

        for svi in range(len(sv)):
            s = sv[svi]
            if s.hasBeads:
                prereqs = []
            else:
                j0 = self.jobq.addShake(sample=s, prereqs=[])
                prereqs = [j0]
            intermed = s

            for i in range(nstages):
                dil = math.pow(needDil, 1.0 / nstages)
                # print "stage ",i,", needDil=",needDil,", dil=",dil
                if i > 0:
                    vol = self.MAXDILVOL
                else:
                    vol = min(self.MAXDILVOL * 1.0, max(self.MINDILVOL * 1.0, dil * self.TGTINVOL * 1.0))
                if intermed.plate == decklayout.DILPLATE:
                    firstWell = intermed.well + 4  # Skip by 4 wells at a time to optimize multi-tip movements
                else:
                    firstWell = 0
                if not save and i == 0 and names is not None:
                    # Need to replace the name in this condition
                    dest = Sample(diluteName(names[svi], dil), decklayout.DILPLATE, firstWell=firstWell)
                else:
                    dest = Sample(diluteName(intermed.name, dil), decklayout.DILPLATE, firstWell=firstWell)
                # print "dest=",dest
                j1 = self.jobq.addMultiTransfer(volume=vol * (dil - 1) / dil, src=self.dilutant, dest=dest, prereqs=[])
                prereqs.append(j1)
                j2 = self.jobq.addTransfer(volume=vol / dil, src=intermed, dest=dest, prereqs=prereqs)
                # print "Dilution of %s was %.2f instead of %.2f (error=%.0f%%)"%(dest.name,(dil/(1+dil))/(1/dil),dil,((dil/(1+dil))/(1/dil)/dil-1)*100)
                if dest.hasBeads:
                    prereqs = [j2]
                else:
                    j3 = self.jobq.addShake(sample=dest, prereqs=[j2])
                    prereqs = [j3]
                intermed = dest
            self.dilProds = self.dilProds + [intermed]
            self.primers = self.primers + [primers]
            self.nreplicates = self.nreplicates + [nreplicates]
Пример #6
0
 def logspeed(self,platename,speed):
     logging.notice("logspeed(%s,%d)"%(platename,speed))
     Sample.addallhistory("(S@%d)"%speed,onlyplate=platename)
Пример #7
0
    def oneround(self, q, input, prefixOut, stop, prefixIn, keepCleaved, t7vol,
                 rtvol, pcrdil, cycles, pcrvol, dolig):
        primerSet = [
            set(["MX", "REF", "T7X", prefixIn[i] + "X", prefixOut[i] + "X"])
            for i in range(len(prefixIn))
        ]

        if keepCleaved:
            print "Starting new cleavage round, will add prefix: ", prefixOut
            assert (dolig)
        else:
            print "Starting new uncleaved round, will retain prefix: ", prefixIn
        print "stop=", stop, "prefixOut=", prefixOut, ", prefixIn=", prefixIn, ",t7vol=", t7vol, ",rtvol=", rtvol, ",pcrdil=", pcrdil, ",cycles=", cycles, ",dolig=", dolig
        if self.rtCarryForward:
            assert (dolig)

        names = [i.name for i in input]

        if self.rnaInput:
            rxs = input
            stopDil = 1
        else:
            print "######## T7 ########### %.0f min" % (clock.elapsed() / 60)
            print "Inputs:  (t7vol=%.2f)" % t7vol
            inconc = [inp.conc.final for inp in input]
            for inp in input:
                if inp.conc.units == 'nM':
                    print "    %s:  %.1ful@%.1f %s, use %.1f ul (%.3f pmoles)" % (
                        inp.name, inp.volume, inp.conc.stock, inp.conc.units,
                        t7vol / inp.conc.dilutionneeded(),
                        t7vol * inp.conc.final / 1000)
                    needDil = max([inp.conc.stock
                                   for inp in input]) * 1.0 / self.qConc
                else:
                    print "    %s:  %.1ful@%.1f %s, use %.1f ul" % (
                        inp.name, inp.volume, inp.conc.stock, inp.conc.units,
                        t7vol / inp.conc.dilutionneeded())
                    needDil = 100 / self.qConc  # Assume 100nM
                # inp.conc.final=inp.conc.stock*self.templateDilution
            if self.directT7 and self.rndNum == 1:
                # Just add ligands and MT7 to each well
                if not keepCleaved:
                    for i in range(len(input)):
                        if self.inputs[i]['ligand'] is not None:
                            ligand = reagents.getsample(
                                self.inputs[i]['ligand'])
                            self.e.transfer(t7vol /
                                            ligand.conc.dilutionneeded(),
                                            ligand,
                                            input[i],
                                            mix=(False, False))
                            names[i] += "+"
                mconc = reagents.getsample("MT7").conc.dilutionneeded()
                for i in range(len(input)):
                    watervol = t7vol * (1 - 1 / mconc) - input[i].volume
                    if watervol > 0.1:
                        self.e.transfer(watervol,
                                        decklayout.WATER,
                                        input[i],
                                        mix=(False, False))
                    self.e.transfer(t7vol / mconc,
                                    reagents.getsample("MT7"),
                                    input[i],
                                    mix=(False, False))
                    assert (abs(input[i].volume - t7vol) < 0.1)
                rxs = input
            elif self.rndNum == len(
                    self.rounds) and self.finalPlus and keepCleaved:
                rxs = self.runT7Setup(
                    src=input,
                    vol=t7vol,
                    srcdil=[inp.conc.dilutionneeded() for inp in input])
                for i in range(len(input)):
                    inp = input[i]
                    if self.inputs[i]['ligand'] is not None:
                        rxs += self.runT7Setup(
                            ligands=[
                                reagents.getsample(self.inputs[i]['ligand'])
                            ],
                            src=[inp],
                            vol=t7vol,
                            srcdil=[inp.conc.dilutionneeded()])
                        prefixIn += [prefixIn[i]]
                        prefixOut += [prefixOut[i]]
                        stop += [stop[i]]
                        primerSet += [primerSet[i]]
                        names += ["%s+" % names[i]]
            elif keepCleaved:
                rxs = self.runT7Setup(
                    src=input,
                    vol=t7vol,
                    srcdil=[inp.conc.dilutionneeded() for inp in input])
            else:
                rxs = self.runT7Setup(
                    ligands=[
                        reagents.getsample(inp['ligand'])
                        for inp in self.inputs
                    ],
                    src=input,
                    vol=t7vol,
                    srcdil=[inp.conc.dilutionneeded() for inp in input])

            if self.rndNum == 1 and "template" in self.qpcrStages:
                # Initial input
                for i in range(len(rxs)):
                    q.addSamples(src=rxs[i],
                                 needDil=needDil,
                                 primers=primerSet[i],
                                 names=["%s.T" % names[i]])

            needDil = needDil * max(
                [inp.conc.dilutionneeded() for inp in input])
            self.runT7Pgm(dur=self.t7dur, vol=t7vol)
            for i in range(len(rxs)):
                rxs[i].name = "%s.t7" % names[i]

            print "Estimate usable RNA concentration in T7 reaction at %.0f nM" % self.rnaConc

            print "######## Stop ########### %.0f min" % (clock.elapsed() / 60)
            self.e.lihahome()

            print "Have %.1f ul before stop" % rxs[0].volume
            preStopVolume = rxs[0].volume
            self.addEDTA(tgt=rxs, finalconc=2)  # Stop to 2mM EDTA final

            stopDil = rxs[0].volume / preStopVolume

            if self.saveRNA:
                self.saveSamps(
                    src=rxs,
                    vol=5,
                    dil=self.saveRNADilution,
                    plate=decklayout.DILPLATE,
                    dilutant=reagents.getsample("TE8"),
                    mix=(False,
                         False))  # Save to check [RNA] on Qubit, bioanalyzer

        needDil = self.rnaConc / self.qConc / stopDil

        if "stopped" in self.qpcrStages:
            for i in range(len(rxs)):
                q.addSamples(src=rxs[i:i + 1],
                             needDil=needDil,
                             primers=primerSet[i],
                             names=["%s.stopped" % names[i]])

        print "######## RT  Setup ########### %.0f min" % (clock.elapsed() /
                                                           60)
        hiTemp = 95

        stop = ["%s-Stop" % n for n in stop]
        rt = self.runRT(src=rxs,
                        vol=rtvol,
                        srcdil=self.rtDil,
                        heatInactivate=self.rtHI,
                        hiTemp=hiTemp,
                        dur=self.rtdur,
                        incTemp=50,
                        stop=[reagents.getsample(s) for s in stop],
                        stopConc=self.stopConc
                        )  # Heat inactivate also allows splint to fold

        rxs = rt
        for i in range(len(rxs)):
            if dolig and not self.singlePrefix:
                rxs[i].name = names[i] + "." + prefixOut[i] + ".rt"
            else:
                rxs[i].name = names[i] + ".rt"

        print "RT volume= [", ",".join(["%.1f " % x.volume for x in rxs]), "]"

        needDil /= self.rtDil
        if self.rtpostdil[self.rndNum - 1] > 1:
            print "Dilution after RT: %.2f" % self.rtpostdil[self.rndNum - 1]
            self.diluteInPlace(tgt=rxs, dil=self.rtpostdil[self.rndNum - 1])
            needDil = needDil / self.rtpostdil[self.rndNum - 1]

        if self.rtSave:
            rtsv = self.saveSamps(
                src=rxs,
                vol=self.rtSaveVol,
                dil=self.rtSaveDil,
                plate=decklayout.DILPLATE,
                dilutant=reagents.getsample("TE8"),
                mix=(False, False))  # Save to check RT product on gel (2x dil)

            if "rt" in self.qpcrStages:
                for i in range(len(rxs)):
                    q.addSamples(src=rtsv[i:i + 1],
                                 needDil=needDil / 2,
                                 primers=self.rtprimers[self.rndNum - 1] if
                                 hasattr(self, 'rtprimers') else primerSet[i],
                                 names=["%s.rt" % names[i]])
        else:
            if "rt" in self.qpcrStages:
                for i in range(len(rxs)):
                    q.addSamples(src=rxs[i:i + 1],
                                 needDil=needDil,
                                 primers=self.rtprimers[self.rndNum - 1] if
                                 hasattr(self, 'rtprimers') else primerSet[i],
                                 names=["%s.rt" % names[i]])

        rtCarryForwardDil = 10
        rtCarryForwardVol = 3.5

        if self.rtCarryForward and not keepCleaved:
            # Also include RT from a prior round from here on
            for r in self.lastSaved:
                newsamp = Sample("%s.samp" % r.name, decklayout.SAMPLEPLATE)
                self.e.transfer(rxs[0].volume, r, newsamp, (False, False))
                rxs.append(newsamp)

        if dolig:
            print "######## Ligation setup  ########### %.0f min" % (
                clock.elapsed() / 60)
            extdil = 5.0 / 4
            reagents.getsample("MLigase").conc = Concentration(5)
            if self.ligInPlace:
                rxs = self.runLig(rxs,
                                  inPlace=True,
                                  srcdil=extdil,
                                  incTime=self.ligdur)
            else:
                rxs = self.runLig(rxs,
                                  inPlace=False,
                                  srcdil=extdil,
                                  vol=20,
                                  incTime=self.ligdur)

            print "Ligation volume= ", [x.volume for x in rxs]
            needDil = needDil / extdil
            if self.extpostdil[self.rndNum - 1] > 1:
                print "Dilution after extension: %.2f" % self.extpostdil[
                    self.rndNum - 1]
                self.diluteInPlace(tgt=rxs,
                                   dil=self.extpostdil[self.rndNum - 1])
                needDil = needDil / self.extpostdil[self.rndNum - 1]
                pcrdil = pcrdil * 1.0 / self.extpostdil[self.rndNum - 1]

            if self.saveDil is not None:
                ext = self.saveSamps(
                    src=rxs,
                    vol=3,
                    dil=self.saveDil,
                    dilutant=reagents.getsample("TE8"),
                    tgt=[
                        Sample("%s.ext" % n, decklayout.DILPLATE)
                        for n in names
                    ],
                    mix=(False, True))  # Save cDNA product for subsequent NGS
                if "ext" in self.qpcrStages:
                    for i in range(len(ext)):
                        # Make sure we don't take more than 2 more steps
                        maxdil = q.MAXDIL * q.MAXDIL
                        if needDil / self.saveDil > maxdil:
                            logging.notice(
                                "Diluting ext by %.0fx instead of needed %.0f to save steps"
                                % (maxdil, needDil / self.saveDil))
                        q.addSamples(src=[ext[i]],
                                     needDil=min(maxdil,
                                                 needDil / self.saveDil),
                                     primers=primerSet[i],
                                     names=["%s.ext" % names[i]],
                                     save=False)
            else:
                if "ext" in self.qpcrStages:
                    print "needDil=", needDil
                    for i in range(len(names)):
                        q.addSamples(src=[rxs[i]],
                                     needDil=needDil,
                                     primers=primerSet[i],
                                     names=["%s.ext" % names[i]])
                        isave = i + len(names)
                        if isave < len(rxs):
                            # samples restored
                            q.addSamples(src=[rxs[isave]],
                                         needDil=needDil / rtCarryForwardDil,
                                         primers=primerSet[isave])
        else:
            extdil = 1
            self.extpostdil[self.rndNum - 1] = 1
            if self.rtpostdil[self.rndNum - 1] > 1:
                pcrdil = pcrdil * 1.0 / self.rtpostdil[self.rndNum - 1]

        totalDil = stopDil * self.rtDil * self.rtpostdil[
            self.rndNum - 1] * extdil * self.extpostdil[self.rndNum - 1]
        fracRetained = rxs[0].volume / (t7vol * totalDil)
        print "Total dilution from T7 to Pre-pcr Product = %.2f*%.2f*%.2f*%.2f*%.2f = %.2f, fraction retained=%.0f%%" % (
            stopDil, self.rtDil, self.rtpostdil[self.rndNum - 1], extdil,
            self.extpostdil[self.rndNum - 1], totalDil, fracRetained * 100)

        if self.rtCarryForward and not keepCleaved:
            # Remove the extra samples
            assert (len(self.lastSaved) > 0)
            rxs = rxs[:len(rxs) - len(self.lastSaved)]
            self.lastSaved = []

        if len(rxs) > len(input):
            # Have extra samples due when self.finalPlus is True
            rxs = rxs[0:len(input)]  # Only keep -target products
            prefixOut = prefixOut[0:len(input)]
            prefixIn = prefixIn[0:len(input)]
            stop = stop[0:len(input)]

        if self.dopcr and not (keepCleaved and self.noPCRCleave):
            print "######### PCR ############# %.0f min" % (clock.elapsed() /
                                                            60)
            maxvol = max([r.volume for r in rxs])
            print "PCR Volume: %.1f, Dilution: %.1f, volumes available for PCR: [%s]" % (
                pcrvol, pcrdil, ",".join(["%.1f" % r.volume for r in rxs]))

            initConc = needDil * self.qConc / pcrdil
            if keepCleaved:
                initConc = initConc * self.cleavage  # Only use cleaved as input conc
            else:
                initConc = initConc * (1 - self.cleavage)

            gain = pcrgain(initConc, 400, cycles)
            finalConc = min(200, initConc * gain)
            print "Estimated starting concentration in PCR = %.1f nM, running %d cycles -> %.0f nM\n" % (
                needDil * self.qConc / pcrdil, cycles, finalConc)
            nsplit = int(math.ceil(pcrvol * 1.0 / self.maxPCRVolume))
            print "Split each PCR into %d reactions" % nsplit
            minsrcdil = 1 / (1 - 1.0 / 3 - 1.0 / 4)
            sampNeeded = pcrvol / pcrdil
            if self.rtCarryForward and keepCleaved:
                sampNeeded += rtCarryForwardVol
            maxvol = max([r.volume for r in rxs])
            minvol = min([r.volume for r in rxs])
            if keepCleaved and self.rtCarryForward:
                assert (len(rxs) == len(rtCarryForward))
                print "Saving %.1f ul of each pre-PCR sample" % (
                    rtCarryForwardVol)
                self.lastSaved = [
                    Sample("%s.sv" % x.name, decklayout.DILPLATE) for x in rxs
                ]
                for i in range(len(rxs)):
                    # Save with rtCarryForwardDil dilution to reduce amount of RT consumed (will have Ct's 2-3 lower than others)
                    self.e.transfer(rtCarryForwardVol, rxs[i],
                                    self.lastSaved[i], (False, False))
                    self.e.transfer(
                        rtCarryForwardVol * (rtCarryForwardDil - 1),
                        decklayout.WATER, self.lastSaved[i], (False, True)
                    )  # Use pipette mixing -- shaker mixing will be too slow

            #print "NSplit=",nsplit,", PCR vol=",pcrvol/nsplit,", srcdil=",pcrdil,", input vol=",pcrvol/nsplit/pcrdil
            minvol = min([r.volume for r in rxs])
            maxpcrvol = (minvol - 15 - 1.4 * nsplit) * pcrdil
            if maxpcrvol < pcrvol:
                print "Reducing PCR volume from %.1ful to %.1ful due to limited input" % (
                    pcrvol, maxpcrvol)
                pcrvol = maxpcrvol

            if keepCleaved:
                master = "MTaqC"
            else:
                master = "MTaqU"

            if self.barcoding:
                primers = self.bcprimers[self.rndNum - 1]
                if primers is not None and nsplit > 1:
                    primers = primers * nsplit
            else:
                primers = None

            if primers is None:
                primers = [("T7%sX" % x).replace("T7T7", "T7")
                           for x in prefixOut] * nsplit

            print "Running PCR with master=", master, ", primers=", primers
            pcr = self.runPCR(src=rxs * nsplit,
                              vol=pcrvol / nsplit,
                              srcdil=pcrdil,
                              ncycles=cycles,
                              primers=primers,
                              usertime=self.usertime if keepCleaved else None,
                              fastCycling=False,
                              inPlace=False,
                              master=master,
                              lowhi=self.lowhi,
                              annealTemp=57)
            if keepCleaved and self.regenPCRCycles is not None:
                # Regenerate prefix
                pcr2 = self.runPCR(src=pcr,
                                   vol=self.regenPCRVolume,
                                   srcdil=self.regenPCRDilution,
                                   ncycles=self.regenPCRCycles,
                                   primers=None,
                                   usertime=None,
                                   fastCycling=False,
                                   inPlace=False,
                                   master="MTaqR",
                                   lowhi=self.lowhi,
                                   annealTemp=55)
                # Add BT575p for 1 more cycle
                for p in pcr2:
                    self.e.transfer(p.volume * 0.5 / 10,
                                    reagents.getsample("Unclvd-Stop"), p,
                                    (False, False))
                # One more cycle
                cycling = ' TEMP@95,30 TEMP@55,30 TEMP@68,30 TEMP@25,2'
                worklist.pyrun('PTC\\ptcsetpgm.py rfin %s' % (cycling))
                self.e.runpgm("rfin",
                              5.0,
                              False,
                              max([p.volume for p in pcr2]),
                              hotlidmode="CONSTANT",
                              hotlidtemp=100)
                pcr = pcr2  # Use 2nd PCR as actual output

            if len(pcr) <= len(names):
                # Don't relabel if we've split
                for i in range(len(pcr)):
                    pcr[i].name = names[i] + ".pcr"

            #print "Volume remaining in PCR input source: [",",".join(["%.1f"%r.volume for r in rxs]),"]"
            needDil = finalConc / self.qConc
            print "Projected final concentration = %.0f nM" % (needDil *
                                                               self.qConc)
            for i in range(len(pcr)):
                pcr[i].conc = Concentration(stock=finalConc,
                                            final=None,
                                            units='nM')

            if self.pcrSave:
                # Save samples at 1x (move all contents -- can ignore warnings)
                maxSaveVol = (100
                              if self.savedilplate else 1500) * 1.0 / nsplit

                if self.finalRound and nsplit == 1 and self.savedilplate:
                    print "Skipping save of final PCR"
                    sv = pcr
                else:
                    sv = self.saveSamps(
                        src=pcr[:len(rxs)],
                        vol=[
                            min([maxSaveVol, x.volume]) for x in pcr[:len(rxs)]
                        ],
                        dil=1,
                        plate=(decklayout.DILPLATE if self.savedilplate else
                               decklayout.EPPENDORFS),
                        atEnd=self.savePCRAtEnd)
                    if nsplit > 1:
                        # Combine split
                        for i in range(len(rxs), len(rxs) * nsplit):
                            self.e.transfer(min([maxSaveVol, pcr[i].volume]),
                                            pcr[i],
                                            sv[i % len(sv)],
                                            mix=(False,
                                                 i >= len(rxs) * (nsplit - 1)))
                        # Correct concentration (above would've assumed it was diluted)
                        for i in range(len(sv)):
                            sv[i].conc = pcr[i].conc

                if "pcr" in self.qpcrStages:
                    for i in range(len(sv)):
                        q.addSamples(sv[i],
                                     needDil,
                                     primers=primerSet[i],
                                     names=["%s.pcr" % names[i]])

                processEff = 0.5  # Estimate of overall efficiency of process
                print "Have %.2f pmoles of product (%.0f ul @ %.1f nM)" % (
                    sv[0].volume * sv[0].conc.stock / 1000, sv[0].volume,
                    sv[0].conc.stock)
                return sv
            else:
                assert "pcr" not in self.qpcrStages  ## Not implemented
                return pcr[:len(rxs)]
        elif self.noPCRCleave:
            print "Dilution instead of PCR: %.2f" % self.nopcrdil
            # Need to add enough t7prefix to compensate for all of the Stop primer currently present, regardless of whether it is for cleaved or uncleaved
            # Will result in some short transcripts corresponding to the stop primers that are not used for cleaved product, producing just GGG_W_GTCTGC in the next round.  These would be reverse-trancribed, but may compete for T7 yield
            t7prefix = reagents.getsample("BT88")
            dil = self.extpostdil[self.rndNum - 1] * userDil
            stopconc = 1000.0 / dil
            bt88conc = t7prefix.conc.stock
            relbt88 = stopconc / bt88conc
            print "Using EXT with %.0fnM of stop oligo as input to next T7, need %.2ful of BT88@%.0fnM per ul of sample" % (
                stopconc, relbt88, bt88conc)
            for r in rxs:
                vol = r.volume * relbt88
                t7prefix.conc.final = t7prefix.conc.stock * vol / (r.volume +
                                                                   vol)
                r.conc.final = r.conc.stock * r.volume / (r.volume + vol)
                self.e.transfer(vol, t7prefix, r, mix=(False, False))

            if self.nopcrdil > (1 + relbt88):
                self.diluteInPlace(tgt=rxs,
                                   dil=self.nopcrdil / (1.0 + relbt88))
                needDil = needDil / self.nopcrdil
                print "Dilution of EXT product: %.2fx * %.2fx = %2.fx\n" % (
                    1 + relbt88, self.nopcrdil / (1 + relbt88), self.nopcrdil)
            else:
                print "Dilution of EXT product: %.2fx\n" % (1 + relbt88)

            return rxs
        else:
            return rxs
Пример #8
0
    def addSamples(self,
                   src,
                   needDil,
                   primers,
                   nreplicates=1,
                   names=None,
                   saveVol=None,
                   saveDil=None,
                   save=True):
        'Add sample(s) to list of qPCRs to do'
        #print "addSamples(%s)"%src
        if not isinstance(src, list):
            src = [src]
        if save:
            # saveVol is total amount (after dilution) to be immediately saved
            if saveDil is None:
                saveDil = min(needDil, self.MAXDIL)
                if needDil / saveDil > 1 and needDil / saveDil < 2:
                    saveDil = math.sqrt(needDil)
            elif saveDil > needDil:
                logging.warning("addSamples: saveDil=", saveDil,
                                ", but needDil is only ", needDil)
                saveDil = needDil

            if saveVol is None:
                saveVol = max(self.MINDILVOL * 1.0 / saveDil, self.TGTINVOL)

            if names is None:
                tgt = [
                    Sample(diluteName(src[i].name, saveDil),
                           decklayout.DILPLATE) for i in range(len(src))
                ]
            else:
                tgt = [
                    Sample(diluteName(names[i], saveDil), decklayout.DILPLATE)
                    for i in range(len(src))
                ]
            sv = tgt

            for i in range(len(sv)):
                #print "Save ",src[i]
                svtmp = self.trp.runQPCRDIL(src=[src[i]],
                                            vol=saveVol * saveDil,
                                            srcdil=saveDil,
                                            tgt=[tgt[i]],
                                            dilPlate=True,
                                            dilutant=self.dilutant)
                sv[i] = svtmp[0]
        else:
            saveDil = 1
            sv = src

        needDil = needDil / saveDil
        nstages = int(math.ceil(math.log(needDil) / math.log(self.MAXDIL)))
        ndil = len(src) * (nstages + (1 if save else 0))
        logging.notice(
            "QPCR: %dQ/%dD [%s], dilution:%.1fx, primers: [%s]" %
            (len(src) * len(primers) * nreplicates, ndil,
             ",".join([s.name
                       for s in src]) if names is None else ",".join(names),
             needDil, ",".join(primers)))

        for svi in range(len(sv)):
            s = sv[svi]
            if s.hasBeads:
                prereqs = []
            else:
                j0 = self.jobq.addShake(sample=s, prereqs=[])
                prereqs = [j0]
            intermed = s

            for i in range(nstages):
                dil = math.pow(needDil, 1.0 / nstages)
                #print "stage ",i,", needDil=",needDil,", dil=",dil
                if i > 0:
                    vol = self.MAXDILVOL
                else:
                    vol = min(self.MAXDILVOL,
                              max(self.MINDILVOL, dil * self.TGTINVOL))
                if intermed.plate == decklayout.DILPLATE:
                    firstWell = intermed.well + 4  # Skip by 4 wells at a time to optimize multi-tip movements
                else:
                    firstWell = 0
                if not save and i == 0 and names is not None:
                    # Need to replace the name in this condition
                    dest = Sample(diluteName(names[svi], dil),
                                  decklayout.DILPLATE,
                                  firstWell=firstWell)
                else:
                    dest = Sample(diluteName(intermed.name, dil),
                                  decklayout.DILPLATE,
                                  firstWell=firstWell)
                #print "dest=",dest
                j1 = self.jobq.addMultiTransfer(volume=vol * (dil - 1) / dil,
                                                src=self.dilutant,
                                                dest=dest,
                                                prereqs=[])
                prereqs.append(j1)
                j2 = self.jobq.addTransfer(volume=vol / dil,
                                           src=intermed,
                                           dest=dest,
                                           prereqs=prereqs)
                #print "Dilution of %s was %.2f instead of %.2f (error=%.0f%%)"%(dest.name,(dil/(1+dil))/(1/dil),dil,((dil/(1+dil))/(1/dil)/dil-1)*100)
                if dest.hasBeads:
                    prereqs = [j2]
                else:
                    j3 = self.jobq.addShake(sample=dest, prereqs=[j2])
                    prereqs = [j3]
                intermed = dest
            self.dilProds = self.dilProds + [intermed]
            self.primers = self.primers + [primers]
            self.nreplicates = self.nreplicates + [nreplicates]
Пример #9
0
    def idbarcoding(self, rsrc, left, right):
        """Perform barcoding of the given inputs;  rsrsc,left,right should all be equal length"""
        pcrcycles = [4]   # Don't need 2nd PCR since this will go directly into constriction
        #pcr1inputconc = 0.05  # PCR1 concentration final in reaction
        pcr1inputdil = 10
        pcr1vol = 30
        pcr1postdil = 100.0 / pcr1vol

        pcr2dil = 50
        pcr2minvol = 50.0

        samps = [s.getsample() for s in rsrc]
        print("Inputs:")
        for i in range(len(samps)):
            print("%2s %-10s %8s-%-8s  %.1f%s" % (
                samps[i].plate.wellname(samps[i].well), self.inputs[i]['name'], left[i], right[i], samps[i].conc.stock,samps[i].conc.units))
        # Compute pcr1inputconc such that lowest concentration input ends up with at least 30ul after dilution
        pcr1inputconc=min([s.conc.stock*s.volume/30.0/pcr1inputdil for s in samps])
        print("Diluting inputs so PCR1 final template conc = %.0f pM"%(pcr1inputconc*1000))
        wellnum = 5
        for s in left + right:
            primer = "P-" + s
            if not reagents.isReagent(primer):
                reagents.add(primer, conc=Concentration(2.67, 0.4, 'uM'), extraVol=30, plate=decklayout.REAGENTPLATE,
                             well=decklayout.REAGENTPLATE.wellname(wellnum))
                wellnum += 1
        # Run first pass dilution where needed
        for i in range(len(samps)):
            # Dilute down to desired conc
            dil = samps[i].conc.stock / pcr1inputconc / pcr1inputdil
            dilvol = samps[i].volume * dil
            if dilvol > 100.0:
                logging.notice("Dilution of input %s (%.1f ul) by %.2f would require %.1f ul" % (
                    samps[i].name, samps[i].volume, dil, dilvol))
                # Do a first pass dilution into 150ul, then remove enough so second dilution can go into 100ul
                dil1 = 100.0 / samps[i].volume
                self.diluteInPlace(tgt=[samps[i]], dil=dil1)
                print("First pass dilution of %s by %.1f/%.1f (conc now %.3f nM)" % (samps[i].name, dil1, dil, samps[i].conc.stock))
                dil /=  dil1

        # Make sure they are all mixed
        self.e.shakeSamples(samps)

        # Final dilution
        for s in samps:
            # Dilute down to desired conc
            dil = s.conc.stock / pcr1inputconc / pcr1inputdil
            if dil < 1.0:
                logging.error("Input %s requires dilution of %.2f" % (s.name, dil))
            elif dil > 1.0:
                dilvol = s.volume * dil
                if dilvol>100:
                    toremove=s.volume-100.0/dil
                    print("Removing %.1f ul from %s to allow enough room for dilution"%(toremove,s.name))
                    self.e.dispose(toremove, s)
                self.diluteInPlace(tgt=[s], dil=dil)
                print("Diluting %s by %.1f" % (s.name, dil))

        pcr1 = self.runPCR(src=samps, srcdil=pcr1inputdil, ncycles=pcrcycles[0], vol=pcr1vol,
                           primers=[[left[i], right[i]] for i in range(len(left))], usertime=0, fastCycling=False,
                           inPlace=False, master="MKapa", kapa=True)

        pcr1finalconc = pcr1inputconc * self.pcreff ** pcrcycles[0]
        print("PCR1 output concentration = %.3f nM" % pcr1finalconc)

        if pcr1postdil > 1:
            pcr1finalconc /= pcr1postdil
            print("Post dilute PCR1 by %.2fx to %.3f nM " % (pcr1postdil, pcr1finalconc))
            self.diluteInPlace(tgt=pcr1, dil=pcr1postdil)

        for x in pcr1:
            x.conc = Concentration(stock=pcr1finalconc, units='nM')

        self.q.addSamples(src=pcr1, needDil=pcr1finalconc / self.qconc, primers=self.qprimers, save=True,
                          nreplicates=1)

        if len(pcrcycles) > 1:
            # Second PCR with 235p/236p on mixture (use at least 4ul of prior)
            pcr2 = self.runPCR(src=pcr1, srcdil=pcr2dil / pcr1postdil, vol=max(pcr2minvol, pcr2dil / pcr1postdil * 4),
                               ncycles=pcrcycles[1],
                               primers="End", fastCycling=False, master="MKapa", kapa=True)

            pcr2finalconc = min(200, pcr1finalconc / (pcr2dil / pcr1postdil) * self.pcreff ** pcrcycles[1])
            print("PCR2 final conc = %.1f nM" % pcr2finalconc)

            d2 = min(4.0, 150.0 / max([p.volume for p in pcr2]))
            if d2 > 1:
                pcr2finalconc /= d2
                print("Post-dilute PCR2 by %.1fx to %.3fnM" % (d2, pcr2finalconc))
                self.diluteInPlace(tgt=pcr2, dil=d2)
                self.e.shakeSamples(pcr2)

            for x in pcr2:
                x.conc = Concentration(stock=pcr2finalconc, units='nM')

            self.q.addSamples(src=pcr2, needDil=pcr2finalconc / self.qconc, primers=self.qprimers, save=True,
                              nreplicates=2)
            res = pcr2
        else:
            res = pcr1

        return res
Пример #10
0
    def runPCR(self,primers,src,srcdil,vol=None,tgt=None,ncycles=20,usertime=None,fastCycling=False,inPlace=False,master="MTaq",annealTemp=None,kapa=False):
        ## PCR
        if inPlace:
            if vol!=None:
                print "runPCR: cannot specify volume when using inPlace=True, srcdil and input volume determine reaction volume"
                assert(False)
            if tgt!=None:
                print "runPCR: cannot specify tgt when using inPlace=True"
                assert(False)
            [primers,src,vol,srcdil]=listify([primers,src,vol,srcdil])
            vol=[src[i].volume*srcdil[i] for i in range(len(src))]
            tgt=src
        else: 
            [primers,src,tgt,vol,srcdil]=listify([primers,src,tgt,vol,srcdil])
            for i in range(len(tgt)):
                if tgt[i] is None:
                    if isinstance(primers[i],list):
                        tgt[i]=Sample("%s.P%s"%(src[i].name,"+".join(primers[i])),src[i].plate)
                    else:
                        tgt[i]=Sample("%s.P%s"%(src[i].name,primers[i]),src[i].plate)

        # Adjust source dilution
        for i in range(len(src)):
            src[i].conc=Concentration(srcdil[i],1)
        
        logging.notice( "primer="+str(primers))

        # Add reagent entries for any missing primers
        if isinstance(primers[0],list):
            allprimers=[x for y in primers for x in y]
        else:
            allprimers=primers
        for up in set(allprimers):
            s="P-%s"%up
            if not reagents.isReagent(s):
                reagents.add(name=s,conc=4,extraVol=30)

        if isinstance(primers[0],list):
            # Multiple primers
            if inPlace:
                assert len(primers[0])==2
                self.runRxInPlace(src,vol,reagents.getsample(master),master2=[reagents.getsample("P-%s"%p[0]) for p in primers],master3=[reagents.getsample("P-%s"%p[1]) for p in primers],returnPlate=False)
            else:
                for i in range(len(primers)):
                    self.e.stage('PCR%d'%i,[reagents.getsample(master)]+[reagents.getsample("P-%s"%s) for s in primers[i]],src[i:i+1] ,tgt[i:i+1],vol[i:i+1],destMix=False)
                #self.e.shakeSamples(tgt,returnPlate=False)
        else:
            # Single primer
            if inPlace:
                self.runRxInPlace(src,vol,reagents.getsample(master),master2=[reagents.getsample("P-%s"%p) for p in primers],returnPlate=False)
            else:
                for up in set(primers):
                    self.e.stage('PCR%s'%up,[reagents.getsample(master),reagents.getsample("P-%s"%up)],[src[i] for i in range(len(src)) if primers[i]==up],[tgt[i] for i in range(len(tgt)) if primers[i]==up],[vol[i] for i in range(len(vol)) if primers[i]==up],destMix=False)
                #self.e.shakeSamples(tgt,returnPlate=False)

        pgm="PCR%d"%ncycles

        if usertime is None:
            runTime=0
        else:
            runTime=usertime

        if annealTemp is None:
            annealTemp=60 if kapa else 57

        meltTemp=98 if kapa else 95
        hotTime=180 if kapa else 30
        extTemp=72 if kapa else 68
        
        if fastCycling:
            cycling='TEMP@37,%d TEMP@95,%d TEMP@%.1f,10 TEMP@%.1f,10 TEMP @%.1f,1 GOTO@3,%d TEMP@%.1f,60 TEMP@25,2'%(1 if usertime is None else usertime*60,hotTime,meltTemp,annealTemp,extTemp,ncycles-1,extTemp)
            runTime+=hotTime/60+2.8+1.65*ncycles
        else:
            cycling='TEMP@37,%d TEMP@95,%d TEMP@%.1f,30 TEMP@%.1f,30 TEMP@%.1f,30 GOTO@3,%d TEMP@%.1f,60 TEMP@25,2'%(1 if usertime is None else usertime*60,hotTime,meltTemp,annealTemp,extTemp,ncycles-1,extTemp)
            runTime+=hotTime/60+2.8+3.0*ncycles
            
        print "PCR volume=[",",".join(["%.1f"%t.volume for t in tgt]), "], srcdil=[",",".join(["%.1fx"%s for s in srcdil]),"], program: %s"%cycling

        worklist.pyrun('PTC\\ptcsetpgm.py %s %s'%(pgm,cycling))
        self.e.runpgm(pgm,runTime,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100)
        # Mark samples as mixed (by thermal convection)
        print "Marking samples as mixed (by thermal convection)"
        for t in tgt:
            t.wellMixed=True
            t.lastMixed=clock.elapsed()
        #self.e.shakeSamples(tgt,returnPlate=True)
        return tgt
Пример #11
0
    def beadWash(self,src,washTgt=None,sepTime=None,residualVolume=0.1,keepWash=False,numWashes=2,wash=None,washVol=50,keepFinal=False,finalTgt=None,keepVol=4.2,keepDil=5,shakeWashes=False):
        # Perform washes
        # If keepWash is true, retain all washes (combined)
        # If keepFinal is true, take a sample of the final wash (diluted by keepDil)
        if wash is None:
            wash=decklayout.WATER
        [src,wash]=listify([src,wash])
        # Do all washes while on magnet
        assert(len(set([s.plate for s in src]))==1)	# All on same plate
        if keepWash:
            if washTgt is None:
                washTgt=[]
                for i in range(len(src)):
                    if s[i].volume-residualVolume+numWashes*(washVol-residualVolume) > decklayout.DILPLATE.maxVolume-20:
                        logging.notice("Saving %.1f ul of wash in eppendorfs"%(numWashes*washVol))
                        washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.EPPENDORFS))
                    else:
                        washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.DILPLATE))

        if keepFinal:
            if finalTgt is None:
                finalTgt=[]
                for i in range(len(src)):
                    finalTgt.append(Sample("%s.Final"%src[i].name,decklayout.DILPLATE))

        if any([s.volume>residualVolume for s in src]):
            # Separate and remove supernatant
            self.e.moveplate(src[0].plate,"Magnet")	# Move to magnet
            self.sepWait(src,sepTime)

            # Remove the supernatant
            for i in range(len(src)):
                if src[i].volume > residualVolume:
                    amt=src[i].amountToRemove(residualVolume)
                    if keepWash:
                        self.e.transfer(amt,src[i],washTgt[i])	# Keep supernatants
                        washTgt[i].conc=None	# Allow it to be reused
                    else:
                        self.e.dispose(amt,src[i])	# Discard supernatant
                
        # Wash

        for washnum in range(numWashes):
            if src[0].plate.curloc!="Home" and src[0].plate.curloc!="Magnet":
                self.e.moveplate(src[0].plate,"Home")
            if keepFinal and washnum==numWashes-1:
                'Retain sample of final'
                for i in range(len(src)):
                    src[i].conc=None
                    self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,True))	# Add wash
                self.e.shakeSamples(src,returnPlate=True)
                self.saveSamps(src=src,tgt=finalTgt,vol=keepVol,dil=keepDil,plate=decklayout.DILPLATE)
            else:
                for i in range(len(src)):
                    src[i].conc=None
                    self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,False))	# Add wash, no need to pipette mix since some heterogenity won't hurt here
                if shakeWashes:
                    self.e.shakeSamples(src,returnPlate=False)

            self.e.moveplate(src[0].plate,"Magnet")	# Move to magnet
                
            self.sepWait(src,sepTime)
                
            for i in range(len(src)):
                amt=src[i].amountToRemove(residualVolume)
                if keepWash:
                    self.e.transfer(amt,src[i],washTgt[i],mix=(False,False))	# Remove wash
                    washTgt[i].conc=None	# Allow it to be reused
                else:
                    self.e.dispose(amt,src[i])	# Remove wash

        #self.e.moveplate(src[0].plate,"Home")

        # Should only be residualVolume left with beads now
        result=[]
        if keepWash:
            result=result+washTgt
        if keepFinal:
            result=result+finalTgt

        return result
Пример #12
0
    def oneround(self, q, inputs, prefixOut, stop, prefixIn, keepCleaved, t7vol, rtvol, pcrdil, cycles, pcrvol, dolig,pcrtgt=None):
        primerSet=[set(["REF","T7X",prefixIn[i]+"X",prefixOut[i]+"X"]+(["MX"] if self.useMX else [])) for i in range(len(prefixIn))]
        if self.extraQPCRPrimers is not None:
            primerSet=[set(list(p) + self.extraQPCRPrimers) for p in primerSet]
            print("primerSet=",primerSet)
            
        if keepCleaved:
            print("Starting new cleavage round, will add prefix: ",prefixOut)
            assert dolig
        else:
            print("Starting new uncleaved round, will retain prefix: ",prefixIn)
        print("stop=",stop,"prefixOut=",prefixOut,", prefixIn=",prefixIn,",t7vol=",round(t7vol,ndigits=2),",rtvol=",rtvol,",pcrdil=",pcrdil,",cycles=",cycles,",dolig=",dolig)
        if self.rtCarryForward:
            assert dolig
            
        names=[i.name for i in inputs]
            
        if self.rnaInput:
            rxs=inputs
            stopDil=1
        else:
            print("######## T7 ########### %.0f min"%(clock.elapsed()/60))
            db.pushStatus("T7")
            print("Inputs:  (t7vol=%.2f)"%t7vol)
            for inp in inputs:
                if inp.conc.units=='nM':
                    print("    %s:  %.1ful@%.1f %s, use %.1f ul (%.3f pmoles)"%(inp.name,inp.volume,inp.conc.stock,inp.conc.units,t7vol/inp.conc.dilutionneeded(), t7vol*inp.conc.final/1000))
                else:
                    print("    %s:  %.1ful@%.1f %s, use %.1f ul"%(inp.name,inp.volume,inp.conc.stock,inp.conc.units,t7vol/inp.conc.dilutionneeded()))
                # inp.conc.final=inp.conc.stock*self.templateDilution
            units=list(set([inp.conc.units for inp in inputs]))
            if len(units)>1:
                print("Inputs have inconsistent concentration units: ",units)
                assert False
            if units[0]=='nM':
                needDil = max([inp.conc.stock for inp in inputs]) * 1.0 / self.qConc
            else:
                needDil = 100 / self.qConc  # Assume 100nM

            if self.directT7 and  self.rndNum==1:
                # Just add ligands and MT7 to each well
                mconc=reagents.getsample("MT7").conc.dilutionneeded()
                for i in range(len(inputs)):
                    watervol=t7vol*(1-1/mconc) - inputs[i].volume
                    if watervol<-0.1:
                        print("Negative amount of water (%.1f ul) needed for T7 setup"%watervol)
                        assert False
                    elif watervol>0.1:
                        self.e.transfer(watervol, decklayout.WATER, inputs[i], mix=(False, False))
                    self.e.transfer(t7vol / mconc, reagents.getsample("MT7"), inputs[i], mix=(False, False))
                    assert(abs(inputs[i].volume - t7vol) < 0.1)
                # Add ligands last in case they crash out when they hit aqueous;  this way, they'll be as dilute as possible
                if keepCleaved:
                    for i in range(len(inputs)):
                        if self.inputs[i]['negligand'] is not None:
                            negligand=reagents.getsample(self.inputs[i]['negligand'])
                            self.e.transfer(t7vol / negligand.conc.dilutionneeded(), negligand, inputs[i], mix=(False, False))
                            names[i]+="+"
                else:
                    for i in range(len(inputs)):
                        if self.inputs[i]['ligand'] is not None:
                            ligand=reagents.getsample(self.inputs[i]['ligand'])
                            self.e.transfer(t7vol / ligand.conc.dilutionneeded(), ligand, inputs[i], mix=(False, False))
                            names[i]+="+"
                rxs=inputs
                self.e.shakeSamples(inputs,returnPlate=True)
            elif self.rndNum==len(self.rounds) and self.finalPlus and keepCleaved:
                rxs = self.runT7Setup(ligands=[reagents.getsample(inp['ligand']) for inp in self.inputs],src=inputs, vol=t7vol, srcdil=[inp.conc.dilutionneeded() for inp in inputs])
                for i in range(len(inputs)):
                    inp=inputs[i]
                    if self.inputs[i]['ligand'] is not None:
                        rxs += self.runT7Setup(ligands=[reagents.getsample(self.inputs[i]['ligand'])],src=[inp],vol=t7vol,srcdil=[inp.conc.dilutionneeded()])
                        prefixIn+=[prefixIn[i]]
                        prefixOut+=[prefixOut[i]]
                        stop+=[stop[i]]
                        primerSet+=[primerSet[i]]
                        names+=["%s+"%names[i]]
            elif keepCleaved:
                rxs = self.runT7Setup(ligands=[reagents.getsample(inp['negligand']) for inp in self.inputs], src=inputs, vol=t7vol, srcdil=[inp.conc.dilutionneeded() for inp in inputs])
            else:
                rxs = self.runT7Setup(ligands=[reagents.getsample(inp['ligand']) for inp in self.inputs], src=inputs, vol=t7vol, srcdil=[inp.conc.dilutionneeded() for inp in inputs])

            if self.rndNum==1 and "template" in self.qpcrStages:
                # Initial input 
                for i in range(len(rxs)):
                    q.addSamples(src=rxs[i],needDil=needDil,primers=primerSet[i],names=["%s.T"%names[i]])

            self.runT7Pgm(dur=self.t7dur,vol=t7vol)
            for i in range(len(rxs)):
                rxs[i].name="%s.t7"%names[i]

            self.e.lihahome()
            print("Estimate usable RNA concentration in T7 reaction at %.0f nM"%self.rnaConc)

            if self.rndNum==1:
                worklist.userprompt("T7 Incubation Started",120)
            
            self.e.waitpgm()   # So elapsed time will be updated
            db.popStatus()
            if self.edtastop:
                print("######## Stop ########### %.0f min"%(clock.elapsed()/60))
                db.pushStatus("Stop")
                print("Have %.1f ul before stop"%rxs[0].volume)
                preStopVolume=rxs[0].volume
                self.addEDTA(tgt=rxs,finalconc=2)	# Stop to 2mM EDTA final
                db.popStatus("Stop")

                stopDil=rxs[0].volume/preStopVolume
            else:
                stopDil=1

            if self.pauseAfterStop:
                worklist.userprompt("Post EDTA pause")
                
            if self.saveRNA:
                self.saveSamps(src=rxs,vol=self.saveRNAVolume,dil=self.saveRNADilution,plate=self.savePlate,dilutant=reagents.getsample("TE8"),mix=(False,False))   # Save to check [RNA] on Qubit, bioanalyzer

        needDil = self.rnaConc/self.qConc/stopDil

        if "stopped" in self.qpcrStages:
            for i in range(len(rxs)):
                q.addSamples(src=rxs[i:i+1],needDil=needDil,primers=primerSet[i],names=["%s.stopped"%names[i]])
        
        print("######## RT  Setup ########### %.0f min"%(clock.elapsed()/60))
        db.pushStatus("RT")
        hiTemp=95

        stop=["%s-Stop"%n for n in stop]
        rt=self.runRT(src=rxs,vol=rtvol,srcdil=self.rtDil,heatInactivate=self.rtHI,hiTemp=hiTemp,dur=self.rtdur,incTemp=50,stop=[reagents.getsample(s) for s in stop],stopConc=self.stopConc)    # Heat inactivate also allows splint to fold
        
        rxs=rt
        for i in range(len(rxs)):
            if dolig and not self.singlePrefix:
                rxs[i].name=names[i]+"."+prefixOut[i]+".rt"
            else:
                rxs[i].name=names[i]+".rt"

        print("RT volume= [",",".join(["%.1f "%x.volume for x in rxs]),"]")
        
        needDil /=self.rtDil
        if self.rtpostdil[self.rndNum-1]>1:
            print("Dilution after RT: %.2f"%self.rtpostdil[self.rndNum-1])
            self.diluteInPlace(tgt=rxs,dil=self.rtpostdil[self.rndNum-1])
            needDil=needDil/self.rtpostdil[self.rndNum-1]

        # Discard extra volume of any sample that has more than current rt volume so that we can shake at high speed
        for r in Sample.getAllOnPlate(rxs[0].plate):
            if r not in rxs and r.volume>max(15+1.4,rxs[0].volume)+4:
                remove=r.volume-(15+1.4)
                oldvol=r.volume
                if r.lastMixed is None:
                    r.lastMixed=clock.elapsed  # Override since we don't care about mixing for disposal
                self.e.dispose(remove,r)
                print("Discarding some of %s to reduce volume from %.1f to %.1f to allow faster shaking"%(r.name,oldvol,r.volume))

        print("RT volume= ",[x.volume for x in rxs])
        self.e.shakeSamples(rxs)
        
        if self.rtSave:
            rtsv=self.saveSamps(src=rxs,vol=self.rtSaveVol,dil=self.rtSaveDil,plate=self.savePlate,dilutant=reagents.getsample("TE8"),mix=(False,False))   # Save to check RT product on gel (2x dil)

            if "rt" in self.qpcrStages:
                for i in range(len(rxs)):
                    q.addSamples(src=rtsv[i:i+1],needDil=needDil/2,primers=self.rtprimers[self.rndNum-1] if hasattr(self,'rtprimers') else primerSet[i],names=["%s.rt"%names[i]])
        else:
            if "rt" in self.qpcrStages:
                for i in range(len(rxs)):
                    q.addSamples(src=rxs[i:i+1],needDil=needDil,primers=self.rtprimers[self.rndNum-1] if hasattr(self,'rtprimers') else primerSet[i],names=["%s.rt"%names[i]])

        rtCarryForwardDil=10
        rtCarryForwardVol=3.5

        if self.rtCarryForward and not keepCleaved:
            # Also include RT from a prior round from here on
            for r in self.lastSaved:
                newsamp=Sample("%s.samp"%r.name,decklayout.SAMPLEPLATE)
                self.e.transfer(rxs[0].volume,r,newsamp,(False,False))
                rxs.append(newsamp)
        db.popStatus()

        if dolig:
            print("######## Ligation setup  ########### %.0f min"%(clock.elapsed()/60))
            db.pushStatus("Ligation")
            extdil=5.0/4
            reagents.getsample("MLigase").conc=Concentration(5)
            if self.ligInPlace:
                rxs=self.runLig(rxs,inPlace=True,srcdil=extdil,incTime=self.ligdur)
            else:
                rxs=self.runLig(rxs,inPlace=False,srcdil=extdil,vol=20,incTime=self.ligdur)

            print("Ligation volume= ",[x.volume for x in rxs])
            needDil=needDil/extdil
            if self.extpostdil[self.rndNum-1]>1:
                print("Dilution after extension: %.2f"%self.extpostdil[self.rndNum-1])
                self.diluteInPlace(tgt=rxs,dil=self.extpostdil[self.rndNum-1])
                needDil=needDil/self.extpostdil[self.rndNum-1]
                pcrdil=pcrdil*1.0/self.extpostdil[self.rndNum-1]
                
            if self.saveDil is not None:
                ext=self.saveSamps(src=rxs,vol=3,dil=self.saveDil,dilutant=reagents.getsample("TE8"),tgt=[Sample("%s.ext"%n,self.savePlate) for n in names],mix=(False,True))   # Save cDNA product for subsequent NGS
                if "ext" in self.qpcrStages:
                    for i in range(len(ext)):
                        # Make sure we don't take more than 2 more steps
                        maxdil=q.MAXDIL*q.MAXDIL
                        if needDil/self.saveDil>maxdil:
                            logging.notice( "Diluting ext by %.0fx instead of needed %.0f to save steps"%(maxdil,needDil/self.saveDil))
                        pset=primerSet[i]
                        if "extraQPCR" in self.inputs[i]:
                            pset.udpate(self.inputs[i]["extraQPCR"])
                        q.addSamples(src=[ext[i]],needDil=min(maxdil,needDil/self.saveDil),primers=pset,names=["%s.ext"%names[i]],save=False)
            else:
                if "ext" in self.qpcrStages:
                    print("needDil=",needDil)
                    for i in range(len(names)):
                        pset=primerSet[i]
                        if "extraQPCR" in self.inputs[i]:
                            pset.update(self.inputs[i]["extraQPCR"])
                        q.addSamples(src=[rxs[i]],needDil=needDil,primers=pset,names=["%s.ext"%names[i]])
                        isave=i+len(names)
                        if isave<len(rxs):
                            # samples restored
                            q.addSamples(src=[rxs[isave]],needDil=needDil/rtCarryForwardDil,primers=primerSet[isave])
            db.popStatus()
        else:
            extdil=1
            self.extpostdil[self.rndNum-1]=1
            if self.rtpostdil[self.rndNum-1]>1:
                pcrdil=pcrdil*1.0/self.rtpostdil[self.rndNum-1]

        totalDil=stopDil*self.rtDil*self.rtpostdil[self.rndNum-1]*extdil*self.extpostdil[self.rndNum-1]
        fracRetained=rxs[0].volume/(t7vol*totalDil)
        print("Total dilution from T7 to Pre-pcr Product = %.2f*%.2f*%.2f*%.2f*%.2f = %.2f, fraction retained=%.0f%%"%(stopDil,self.rtDil,self.rtpostdil[self.rndNum-1],extdil,self.extpostdil[self.rndNum-1],totalDil,fracRetained*100))

        if self.rtCarryForward and not keepCleaved:
            # Remove the extra samples
            assert(len(self.lastSaved)>0)
            rxs=rxs[:len(rxs)-len(self.lastSaved)]
            self.lastSaved=[]

        if len(rxs)>len(inputs):
            # Have extra samples due when self.finalPlus is True
            rxs= rxs[0:len(inputs)]    # Only keep -target products
            prefixOut= prefixOut[0:len(inputs)]
            prefixIn= prefixIn[0:len(inputs)]
            stop= stop[0:len(inputs)]
            
        if self.dopcr and not (keepCleaved and self.noPCRCleave):
            print("######### PCR ############# %.0f min"%(clock.elapsed()/60))
            db.pushStatus("PCR")
            print("PCR Volume: %.1f, Dilution: %.1f, volumes available for PCR: [%s]"%(pcrvol, pcrdil,",".join(["%.1f"%r.volume for r in rxs])))

            initConc=needDil*self.qConc/pcrdil
            if keepCleaved:
                initConc=initConc*self.cleavage		# Only use cleaved as input conc
            else:
                initConc=initConc*(1-self.cleavage)
                
            gain=pcrgain(initConc,400,cycles)
            finalConc=min(200,initConc*gain)
            print("Estimated starting concentration in PCR = %.1f nM, running %d cycles -> %.0f nM\n"%(needDil*self.qConc/pcrdil,cycles,finalConc))
            nsplit=int(math.ceil(pcrvol*1.0/self.maxPCRVolume))
            print("Split each PCR into %d reactions"%nsplit)
            sampNeeded=pcrvol/pcrdil
            if self.rtCarryForward and keepCleaved:
                sampNeeded+=rtCarryForwardVol
            if keepCleaved and self.rtCarryForward:
                print("Saving %.1f ul of each pre-PCR sample" % rtCarryForwardVol)
                self.lastSaved=[Sample("%s.sv"%x.name,self.savePlate) for x in rxs]
                for i in range(len(rxs)):
                    # Save with rtCarryForwardDil dilution to reduce amount of RT consumed (will have Ct's 2-3 lower than others)
                    self.e.transfer(rtCarryForwardVol,rxs[i],self.lastSaved[i],(False,False))
                    self.e.transfer(rtCarryForwardVol*(rtCarryForwardDil-1),decklayout.WATER,self.lastSaved[i],(False,True))  # Use pipette mixing -- shaker mixing will be too slow

            #print "NSplit=",nsplit,", PCR vol=",pcrvol/nsplit,", srcdil=",pcrdil,", input vol=",pcrvol/nsplit/pcrdil
            minvol=min([r.volume for r in rxs])
            maxpcrvol=(minvol-15-1.4*nsplit)*pcrdil
            if maxpcrvol<pcrvol:
                print("Reducing PCR volume from %.1ful to %.1ful due to limited input"%(pcrvol, maxpcrvol))
                pcrvol=maxpcrvol

            if keepCleaved:
                master="MTaqC"
            else:
                master="MTaqU"

            reagents.getsample(master)    # Allocate for this before primers
            
            if self.barcoding:
                primers=self.bcprimers[self.rndNum-1]
                if primers is not None and nsplit>1:
                    primers=primers*nsplit
            else:
                primers=None

            if primers is None:
                primers=[("T7%sX"%x).replace("T7T7","T7") for x in prefixOut]*nsplit

            rnddef = self.rnddef[self.rndNum-1]
            bcout=[]
            if 'barcode' in rnddef:
                # Add barcoding primers 
                assert len(rnddef['barcode'])==len(rxs)
                dil=self.saveSamps(rxs,dil=50,vol=2,plate=decklayout.SAMPLEPLATE)
                for i in range(len(rxs)):
                    dil[i].conc=Concentration(25,1)
                    for bc in rnddef['barcode'][i]:
                        tgt=Sample("%s.%s"%(rxs[i].name,bc),decklayout.SAMPLEPLATE)
                        bparts=bc.split("/")
                        for b in bparts:
                            if not reagents.isReagent("P-%s"%b):
                                reagents.add(name="P-%s"%b,conc=Concentration(2.67,0.4,'uM'),extraVol=30)
                        print("PCR-%s"%bc)
                        self.e.stage("PCR-%s"%bc,reagents=[reagents.getsample("MTaqBar"),reagents.getsample("P-%s"%bparts[0]),reagents.getsample("P-%s"%bparts[1])],samples=[tgt],sources=[dil[i] ],volume=50,destMix=False)
                        bcout.append(tgt)
                        print(tgt.name,"wellMixed=",tgt.wellMixed)
                        
            print("Running PCR with master=",master,", primers=",primers)
            pcr=self.runPCR(src=rxs*nsplit,vol=pcrvol/nsplit,srcdil=pcrdil,ncycles=cycles,primers=primers,usertime=self.usertime if keepCleaved else None,fastCycling=False,inPlace=False,master=master,lowhi=self.lowhi,annealTemp=57)
            if keepCleaved and self.regenPCRCycles is not None:
                # Regenerate prefix
                pcr2=self.runPCR(src=pcr,vol=self.regenPCRVolume,srcdil=self.regenPCRDilution,ncycles=self.regenPCRCycles,primers=None,usertime=None,fastCycling=False,inPlace=False,master="MTaqR",lowhi=self.lowhi,annealTemp=55)
                # Add BT575p for 1 more cycle
                for p in pcr2:
                    self.e.transfer(p.volume*0.5/10,reagents.getsample("Unclvd-Stop"),p,(False,False))
                # One more cycle
                cycling=' TEMP@95,30 TEMP@55,30 TEMP@68,30 TEMP@25,2'
                thermocycler.setpgm('rfin',100,cycling)
                self.e.runpgm("rfin",5.0,False,max([p.volume for p in pcr2]))
                pcr=pcr2	# Use 2nd PCR as actual output

            if len(pcr)<=len(names):
                # Don't relabel if we've split
                for i in range(len(pcr)):
                    pcr[i].name=names[i]+".pcr"
                
            #print "Volume remaining in PCR input source: [",",".join(["%.1f"%r.volume for r in rxs]),"]"
            needDil=finalConc/self.qConc
            print("Projected final concentration = %.0f nM"%(needDil*self.qConc))
            for i in range(len(pcr)):
                pcr[i].conc=Concentration(stock=finalConc,final=None,units='nM')
            db.popStatus()

            if self.pcrSave:
                # Save samples at 1x (move all contents -- can ignore warnings)
                maxSaveVol=(100 if self.savedilplate else 1500)*1.0/nsplit

                if self.finalRound and nsplit==1 and self.savedilplate and pcrtgt is None:
                    print("Skipping save of final PCR")
                    sv=pcr
                else:
                    residual=2.4   # Amount to leave behind to avoid aspirating air
                    sv=self.saveSamps(src=pcr[:len(rxs)],vol=[min([maxSaveVol,x.volume-residual]) for x in pcr[:len(rxs)]],dil=1,plate=(self.savePlate if self.savedilplate else decklayout.EPPENDORFS),tgt=pcrtgt)
                    if nsplit>1:
                        # Combine split
                        for i in range(len(rxs),len(rxs)*nsplit):
                            self.e.transfer(min([maxSaveVol,pcr[i].volume-residual]),pcr[i],sv[i%len(sv)],mix=(False,False))
                        # Correct concentration (above would've assumed it was diluted)
                        for i in range(len(sv)):
                            sv[i].conc=pcr[i].conc
                        # Shake
                        self.e.shakeSamples(sv)

                if "pcr" in self.qpcrStages:
                    for i in range(len(sv)):
                        q.addSamples(sv[i],needDil,primers=primerSet[i],names=["%s.pcr"%names[i]])

                print("Have %.2f pmoles of product (%.0f ul @ %.1f nM)"%(sv[0].volume*sv[0].conc.stock/1000,sv[0].volume,sv[0].conc.stock))

                # Save barcoded products too
                if len(bcout)>0:
                    print("bcout=",",".join(str(b) for b in bcout))
                    print("mixed=",bcout[0].isMixed(),", wellMixed=",bcout[0].wellMixed)
                    bcsave=self.saveSamps(src=bcout,vol=[b.volume for b in bcout],dil=1,plate=self.savePlate,mix=(False,False))
                    if "bc" in self.qpcrStages:
                        print("Doing qPCR of barcoding: ",bcsave)
                        for i in range(len(bcsave)):
                            needDil=640
                            q.addSamples(src=bcsave[i],needDil=needDil,primers=["T7X","WX","ZX"]+(["MX"] if self.useMX else []),save=False)
                else:
                    bcsave=[]
                    
                return sv, bcsave
            else:
                assert "pcr" not in self.qpcrStages   ## Not implemented
                return pcr[:len(rxs)], bcout

        elif self.noPCRCleave:
            print("Dilution instead of PCR: %.2f"%self.nopcrdil)
            # Need to add enough t7prefix to compensate for all of the Stop primer currently present, regardless of whether it is for cleaved or uncleaved
            # Will result in some short transcripts corresponding to the stop primers that are not used for cleaved product, producing just GGG_W_GTCTGC in the next round.  These would be reverse-trancribed, but may compete for T7 yield
            t7prefix=reagents.getsample("BT88")
            dil=self.extpostdil[self.rndNum-1]  # FIXME: Is this correct?  Used to have a 'userDil' term
            stopconc=1000.0/dil
            bt88conc=t7prefix.conc.stock
            relbt88=stopconc/bt88conc
            print("Using EXT with %.0fnM of stop oligo as input to next T7, need %.2ful of BT88@%.0fnM per ul of sample"%(stopconc,relbt88,bt88conc))
            for r in rxs:
                vol=r.volume*relbt88
                t7prefix.conc.final=t7prefix.conc.stock*vol/(r.volume+vol)
                r.conc.final=r.conc.stock*r.volume/(r.volume+vol)
                self.e.transfer(vol,t7prefix,r,mix=(False,False))

            if self.nopcrdil>(1+relbt88):
                self.diluteInPlace(tgt=rxs,dil=self.nopcrdil/(1.0+relbt88))
                #needDil=needDil/self.nopcrdil  # needDil not used subsequently
                print("Dilution of EXT product: %.2fx * %.2fx = %2.fx\n"%(1+relbt88,self.nopcrdil/(1+relbt88),self.nopcrdil))
            else:
                print("Dilution of EXT product: %.2fx\n"%(1+relbt88))

            return rxs, []
        else:
            return rxs, []
Пример #13
0
    def oneround(self,q,input,prefixOut,prefixIn,keepCleaved,t7vol,rtvol,pcrdil,cycles,pcrvol,dolig):
        if keepCleaved:
            print "Starting new cleavage round, will add prefix: ",prefixOut
            assert(dolig)
        else:
            print "Starting new uncleaved round, will retain prefix: ",prefixIn

        if self.rtSave:
            assert(dolig)
            
        names=[i.name for i in input]
            
        print "######## T7 ###########"
        print "Inputs:  (t7vol=%.2f)"%t7vol
        inconc=[inp.conc.final for inp in input]
        for inp in input:
            print "    %s:  %.1ful@%.1f nM, use %.1f ul (%.3f pmoles)"%(inp.name,inp.volume,inp.conc.stock,t7vol/inp.conc.dilutionneeded(), t7vol*inp.conc.final/1000)
            # inp.conc.final=inp.conc.stock*self.templateDilution
        needDil = max([inp.conc.stock for inp in input])*1.0/self.qConc
        if self.directT7 and  self.rndNum==1:
            # Just add ligands and MT7 to each well
            for i in range(len(input)):
                ligand=reagents.getsample(self.inputs[i]['ligand'])
                self.e.transfer(t7vol/ligand.conc.dilutionneeded(),ligand,input[i],mix=(False,False))
            mconc=reagents.getsample("MT7").conc.dilutionneeded()
            for i in range(len(input)):
                watervol=t7vol*(1-1/mconc)-input[i].volume
                if watervol>0.1:
                    self.e.transfer(watervol,decklayout.WATER,input[i],mix=(False,False))
                self.e.transfer(t7vol/mconc,reagents.getsample("MT7"),input[i],mix=(False,False))
                assert(abs(input[i].volume-t7vol)<0.1)
            rxs=input
        elif self.rndNum==self.nrounds and self.finalPlus:
            rxs = self.runT7Setup(src=input,vol=t7vol,srcdil=[inp.conc.dilutionneeded() for inp in input])
            rxs += self.runT7Setup(ligands=[reagents.getsample(inp['ligand']) for inp in self.inputs],src=input,vol=t7vol,srcdil=[inp.conc.dilutionneeded() for inp in input])
            prefixIn+=prefixIn
            prefixOut+=prefixOut
            names+=["%s+"%n for n in names]
        elif keepCleaved:
            rxs = self.runT7Setup(src=input,vol=t7vol,srcdil=[inp.conc.dilutionneeded() for inp in input])
        else:
            rxs = self.runT7Setup(ligands=[reagents.getsample(inp['ligand']) for inp in self.inputs],src=input,vol=t7vol,srcdil=[inp.conc.dilutionneeded() for inp in input])
            
        for i in range(len(rxs)):
            rxs[i].name="%s.rx"%names[i]

        if self.rndNum==1 and "template" in self.qpcrStages:
            # Initial input 
            for i in range(len(rxs)):
                q.addSamples(src=rxs[i],needDil=needDil,primers=["T7X","REF","T7"+prefixIn[i]+"X"],names=["%s.T-"%names[i]])
        
        needDil = needDil*max([inp.conc.dilutionneeded() for inp in input])
        t7dur=30
        self.runT7Pgm(dur=t7dur,vol=t7vol)
        print "Estimate RNA concentration in T7 reaction at %.0f nM"%self.rnaConc
        self.rnaConc=min(40,inconc)*t7dur*65/30

        print "######## Stop ###########"
        #self.saveSamps(src=rxs,vol=5,dil=10,plate=decklayout.EPPENDORFS,dilutant=reagents.getsample("TE8"),mix=(False,False))   # Save to check [RNA] on Qubit, bioanalyzer

        self.e.lihahome()

        print "Have %.1f ul before stop"%rxs[0].volume
        preStopVolume=rxs[0].volume
        self.addEDTA(tgt=rxs,finalconc=2)	# Stop to 2mM EDTA final
        
        stop=["Unclvd-Stop" if (not dolig) else "A-Stop" if n=="A" else "B-Stop" if n=="B" else "W-Stop" if n=="W" else "BADPREFIX" for n in prefixOut]

        stopDil=rxs[0].volume/preStopVolume
        needDil = self.rnaConc/self.qConc/stopDil
        if "stopped" in self.qpcrStages:
            q.addSamples(src=rxs,needDil=needDil,primers=["T7AX","MX","T7X","REF"],names=["%s.stopped"%r.name for r in rxs])
        
        print "######## RT  Setup ###########"
        rtDil=4
        hiTemp=95
        rtDur=20

        rxs=self.runRT(src=rxs,vol=rtvol,srcdil=rtDil,heatInactivate=True,hiTemp=hiTemp,dur=rtDur,incTemp=50,stop=[reagents.getsample(s) for s in stop])    # Heat inactivate also allows splint to fold
        print "RT volume= ",[x.volume for x in rxs]
        needDil /= rtDil
        if "rt" in self.qpcrStages:
            q.addSamples(src=rxs,needDil=needDil,primers=["T7AX","MX","REF"],names=["%s.rt"%r.name for r in rxs])

        rtSaveDil=10
        rtSaveVol=3.5

        if self.rtSave and not keepCleaved:
            # Also include RT from a prior round from here on
            for r in self.lastSaved:
                newsamp=Sample("%s.samp"%r.name,decklayout.SAMPLEPLATE)
                self.e.transfer(rxs[0].volume,r,newsamp,(False,False))
                rxs.append(newsamp)
            
        if dolig:
            print "######## Ligation setup  ###########"
            extdil=5.0/4
            reagents.getsample("MLigase").conc=Concentration(5)
            rxs=self.runLig(rxs,inPlace=True)

            print "Ligation volume= ",[x.volume for x in rxs]
            needDil=needDil/extdil
            extpostdil=2
            if extpostdil>1:
                print "Dilution after extension: %.2f"%extpostdil
                self.diluteInPlace(tgt=rxs,dil=extpostdil)
                needDil=needDil/extpostdil
                if not self.doexo:
                    pcrdil=pcrdil/extpostdil
                    
            if self.saveDil is not None:
                ext=self.saveSamps(src=rxs,vol=3,dil=self.saveDil,dilutant=reagents.getsample("TE8"),tgt=[Sample("%s.ext"%n,decklayout.DILPLATE) for n in names],mix=(False,True))   # Save cDNA product for subsequent NGS
                if "ext" in self.qpcrStages:
                    for i in range(len(ext)):
                        # Make sure we don't take more than 2 more steps
                        maxdil=q.MAXDIL*q.MAXDIL
                        if needDil/self.saveDil>maxdil:
                            logging.notice( "Diluting ext by %.0fx instead of needed %.0f to save steps"%(maxdil,needDil/self.saveDil))
                        q.addSamples(src=[ext[i]],needDil=min(maxdil,needDil/self.saveDil),primers=["T7"+prefixIn[i]+"X","T7"+prefixOut[i]+"X","MX","T7X","REF"],names=["%s.ext"%names[i]],save=False)
            else:
                if "ext" in self.qpcrStages:
                    for i in range(len(input)):
                        q.addSamples(src=[rxs[i]],needDil=needDil,primers=["T7"+prefixIn[i]+"X","T7"+prefixOut[i]+"X","MX","T7X","REF"],names=["%s.ext"%names[i]])
                        isave=i+len(input)
                        if isave<len(rxs):
                            # samples restored
                            q.addSamples(src=[rxs[isave]],needDil=needDil/rtSaveDil,primers=["T7"+rxs[isave].name[0]+"X","T7"+("B" if rxs[isave].name[0]=="A" else "W" if rxs[isave].name[0]=="B" else "A")+"X","MX","T7X","REF"])

            if self.doexo:
                print "######## Exo ###########"
                prevvol=rxs[0].volume
                rxs=self.runExo(rxs,incTime=30,inPlace=True)
                exoDil=rxs[0].volume/prevvol
                needDil/=exoDil
                needDil/=7   #  Anecdotal based on Ct's -- large components (MX) reduced by exo digestion
                if "exo" in self.qpcrStages:
                    q.addSamples(src=[rxs[i] for i in self.trackIndices],needDil=needDil,primers=["T7AX","T7BX","MX","T7X","REF"],names=["%s.exo"%names[i] for i in self.trackIndices])
                exo=self.saveSamps(src=rxs,vol=10*exoDil,dil=2/exoDil,dilutant=reagents.getsample("TE8"),tgt=[Sample("%s.exo"%n,decklayout.SAMPLEPLATE) for n in names])   # Save cDNA product
            else:
                exoDil=1
                exo=[]
        else:
            extdil=1
            extpostdil=1
            exoDil=1
            
        if self.doampure:
            print "######## Ampure Cleanup ###########"
            ratio=1.5
            elutionVol=30
            cleanIn=ext+exo+user
            needDil=needDil*cleanIn[0].volume/elutionVol
            clean=self.runAmpure(src=cleanIn,ratio=ratio,elutionVol=elutionVol)
            if "ampure" in self.qpcrStages:
                q.addSamples(src=[clean[i] for i in self.trackIndices],needDil=needDil,primers=["T7AX","MX","T7X","REF"])
            rxs=rxs+clean   # Use the cleaned products for PCR
            
        totalDil=stopDil*rtDil*extdil*extpostdil*exoDil
        fracRetained=rxs[0].volume/(t7vol*totalDil)
        print "Total dilution from T7 to Pre-pcr Product = %.2f*%.2f*%.2f*%.2f*%.2f = %.2f, fraction retained=%.0f%%"%(stopDil,rtDil,extdil,extpostdil,exoDil,totalDil,fracRetained*100)

        if self.rtSave and not keepCleaved:
            # Remove the extra samples
            assert(len(self.lastSaved)>0)
            rxs=rxs[:len(rxs)-len(self.lastSaved)]
            self.lastSaved=[]

        if len(rxs)>len(input):
            rxs=rxs[0:len(input)]    # Only keep -target products
            prefixOut=prefixOut[0:len(input)]
            prefixIn=prefixIn[0:len(input)]
            
        if self.dopcr:
            print "######### PCR #############"
            print "PCR Volume: %.1f, Dilution: %.1f, volumes available for PCR: [%s]"%(pcrvol, pcrdil,",".join(["%.1f"%r.volume for r in rxs]))
            maxSampleVolume=100  # Maximum sample volume of each PCR reaction (thermocycler limit, and mixing limit)

            initConc=needDil*self.qConc/pcrdil
            if keepCleaved:
                if self.doexo:
                    initConc=initConc*7*self.cleavage		# Back out 7x dilution in exo step, but only use cleaved as input conc
                else:
                    initConc=initConc*self.cleavage		# Only use cleaved as input conc
            else:
                initConc=initConc*(1-self.cleavage)
                
            gain=pcrgain(initConc,400,cycles)
            finalConc=initConc*gain
            print "Estimated starting concentration in PCR = %.1f nM, running %d cycles -> %.0f nM\n"%(needDil*self.qConc,cycles,finalConc)
            nsplit=int(math.ceil(pcrvol*1.0/maxSampleVolume))
            print "Split each PCR into %d reactions"%nsplit
            srcdil=(1-1.0/3-1.0/4)
            sampNeeded=pcrvol/pcrdil
            if self.rtSave and keepCleaved:
                sampNeeded+=rtSaveVol
            maxvol=max([r.volume for r in rxs]);
            minvol=min([r.volume for r in rxs]);
            predil=min(75/maxvol,(40+1.4*nsplit)/(minvol-sampNeeded))  # Dilute to have 40ul left -- keeps enough sample to allow good mixing
            if keepCleaved and self.rtSave and predil>rtSaveDil:
                print "Reducing predil from %.1f to %.1f (rtSaveDil)"%(predil, rtSaveDil)
                predil=rtSaveDil
            if predil>1:
                self.diluteInPlace(rxs,predil)
                self.e.shakeSamples(rxs)
                print "Pre-diluting by %.1fx into [%s] ul"%(predil,",".join(["%.1f"%r.volume for r in rxs]))
            if keepCleaved and self.rtSave:
                assert(len(rxs)==len(rtSave))
                print "Saving %.1f ul of each pre-PCR sample (@%.1f*%.1f dilution)"%(rtSaveVol ,predil, rtSaveDil/predil)
                self.lastSaved=[Sample("%s.sv"%x.name,decklayout.DILPLATE) for x in rxs]
                for i in range(len(rxs)):
                    # Save with rtSaveDil dilution to reduce amount of RT consumed (will have Ct's 2-3 lower than others)
                    self.e.transfer(rtSaveVol*predil,rxs[i],self.lastSaved[i],(False,False))
                    self.e.transfer(rtSaveVol*(rtSaveDil/predil-1),decklayout.WATER,self.lastSaved[i],(False,True))  # Use pipette mixing -- shaker mixing will be too slow

            pcr=self.runPCR(src=rxs*nsplit,vol=pcrvol/nsplit,srcdil=pcrdil*1.0/predil,ncycles=cycles,primers=["T7%sX"%x for x in (prefixOut if keepCleaved else prefixIn)]*nsplit,usertime=self.usertime if keepCleaved else None,fastCycling=True,inPlace=False)
                
            needDil=finalConc/self.qConc
            print "Projected final concentration = %.0f nM"%(needDil*self.qConc)
            for i in range(len(pcr)):
                pcr[i].conc=Concentration(stock=finalConc,final=None,units='nM')

            if self.pcrSave:
                # Save samples at 1x (move all contents -- can ignore warnings)
                if self.savedilplate:
                    sv=self.saveSamps(src=pcr[:len(rxs)],vol=[x.volume for x in pcr[:len(rxs)]],dil=1,plate=decklayout.DILPLATE,atEnd=True)
                else:
                    sv=self.saveSamps(src=pcr[:len(rxs)],vol=[x.volume for x in pcr[:len(rxs)]],dil=1,plate=decklayout.EPPENDORFS)
                if nsplit>1:
                    # Combine split
                    for i in range(len(rxs),len(rxs)*nsplit):
                        self.e.transfer(pcr[i].volume-16.4,pcr[i],sv[i%len(sv)],mix=(False,i>=len(rxs)*(nsplit-1)))
                    # Correct concentration (above would've assumed it was diluted)
                    for i in range(len(sv)):
                        sv[i].conc=pcr[i].conc

                if "pcr" in self.qpcrStages:
                    for i in range(len(pcr)):
                        q.addSamples(pcr,needDil,["T7%sX"%prefixOut[i]])

                processEff=0.5   # Estimate of overall efficiency of process
                print "Saved %.2f pmoles of product (%.0f ul @ %.1f nM)"%(sv[0].volume*sv[0].conc.stock/1000,sv[0].volume,sv[0].conc.stock)
                return sv
            else:
                return pcr[:len(rxs)]
        else:
            return rxs
Пример #14
0
def parselog(filename: str, outfile:str=None, follow=False):
    global logdb, lnum

    if filename is not None:
          fd=open(filename,'rb')
    else:
          fd=sys.stdin

    if outfile is not None:
        outfd=codecs.open(outfile,'w','latin-1')
    else:
        outfd=sys.stdout

    csum=fd.readline()
    hdr=fd.readline()
    version=fd.readline()
    prevcode='?'
    prevtime='?'
    send={}
    error=False
    lastgeminicmd=None
    geminicmdtimes={}
    geminicmdcnt={}
    tipcmd=""
    lasttime=datetime.datetime.strptime(hdr[:15].decode('latin-1'),'%Y%m%d_%H%M%S')
    print("Header time: %s"%str(lasttime),file=outfd)
    shakePlate=None   # Plate on shaker
    logdb=LogDB(filename)
    # Handle high-bit characters in stdout (since .log contains 0xb5 (\micro) charactures
    sleeping=False

    while True:
        bline=fd.readline()
        if not bline:
            if follow:
                if not sleeping:
                    logdb.flush()
                    print("sleeping at line %d of %s..."%(lnum,filename),end='',flush=True)
                    sleeping=True
                time.sleep(10)
                continue
            else:
                break
        if sleeping:
            print("done")
            sleeping=False
        while len(bline)>0 and (bline[-1]==13 or bline[-1]==10):
            bline=bline[:-1]
        #line=line.rstrip('\r\n')
        if len(bline)==0:
            continue

        line=bline.decode('latin-1')
        code=line[0]
        gtime=line[2:10]
        cmd=line[11:]
        if debug:
            print("\tcode=%s(%d),time=%s,cmd=%s"%(code,ord(code[0]),gtime,cmd),file=outfd)
        if code[0]==' ':
              if prevcode[0]!='D':
                    # print "Copying previous code: %c"%prevcode
                    code=prevcode
              else:
                    print("Blank code, previous=D, assuming new one is F",file=outfd)
                    code='F'
        if len(gtime)<1 or gtime[0]==' ':
            gtime=prevtime
        prevcode=code
        prevtime=gtime
        if code[0]=='F':
            spcmd=cmd[1:].split(',')
            dev=spcmd[0][1:]
            spcmd=spcmd[1:]
            if len(cmd)<1:
                print("Empty cmd",file=outfd)
            elif cmd[0]=='>':
                if dev in send:
                    print("Double cmd to %s: %s AND %s"%(dev,send[dev],str(spcmd)),file=outfd)
                send[dev]=[spcmd[0][0:3],spcmd[0][3:]]+spcmd[1:]
            elif cmd[0]=='-' or cmd[0]=='*':
                if dev not in send:
                    print("Missing cmd when received reply from %s: %s"%(dev,str(spcmd)),file=outfd)
                    continue
                error=cmd[0]=='*'
                fwparse(dev,send[dev],spcmd,error,lasttime,outfd)
                send.pop(dev)
            else:
                print("Bad cmd: %s"%cmd)
        else:
              if cmd.find('detected_volume_')==-1 or cmd.find('= -1')==-1:
                    print("Gemini %s %s"%(gtime,cmd),file=outfd)
                    if cmd[0:3]=='tip':
                        tipcmd=cmd
                    else:
                        if  len(tipcmd)>0 and cmd[0:3]=='   ':
                            gemtip(tipcmd,cmd,outfd)
                        tipcmd=""

              if cmd.find("setShakeTargetSpeed")!=-1:
                    pos=cmd.find("setShakeTargetSpeed")
                    speed=int(cmd[pos+19:])
                    print("SPEED %d"%speed,file=outfd)
                    dl.logspeed(shakePlate,speed)

              if cmd.startswith("moveplate") and cmd.find("Shaker")!=-1:
                    pos=cmd.find("Shaker")
                    shakePlate=cmd[10:pos-1]
                    print("SHAKEPLATE %s"%shakePlate,file=outfd)

              if cmd.startswith("Starting program"):
                  logdb.logfileStart(cmd,lasttime)

              if cmd.startswith('Line'):
                    colon=cmd.find(':')
                    cname=cmd[(colon+2):]
                    lnum=int(cmd[4:(colon-1)])
                    logdb.setline(lnum)
                    #print "cname=",cname
                    t=datetime.datetime.combine(lasttime.date(),datetime.datetime.strptime(gtime,'%H:%M:%S').time())
                    if (t-lasttime).total_seconds()<0:
                        t=t+datetime.timedelta(1)   # Wrapped around
                        logging.notice("Gemini time wrapped from %s to %s"%(lasttime,t))

                    if lastgeminicmd is not None:
                        if (t-lasttime).total_seconds() > 30:
                            print("Skipping long pause of %s for %s"%(str(t-lasttime),lastgeminicmd),file=outfd)
                        elif t<lasttime:
                            assert False # Shouldn't happen
                            print("Skipping negative elapsed time of %d seconds for %s"%((t-lasttime).total_seconds(),lastgeminicmd),file=outfd)
                        elif lastgeminicmd in list(geminicmdtimes.keys()):
                            geminicmdtimes[lastgeminicmd]+=(t-lasttime).total_seconds()
                            geminicmdcnt[lastgeminicmd]+=1
                        else:
                            geminicmdtimes[lastgeminicmd]=(t-lasttime).total_seconds()
                            geminicmdcnt[lastgeminicmd]=1
                    lastgeminicmd=cname
                    lasttime=t
              if cmd.startswith('@log_'):
                  print("PYTHON: %s" % cmd[1:],file=outfd)
                  eval("logdb." + cmd[1:])
              if cmd.find('closing log-file') != -1:
                  # End of log (in case we're in -f mode)
                  print("Found closing log-file message; exiting")
                  logdb.logfileDone(lnum,lasttime)
                  break

    logdb.flush()
    #print "log=",dl
    dl.printallsamples(fd=outfd)  # This 'sys.stdout' (modified above) seems different from the default one that Samples.print* would use

    for cmd in list(geminicmdtimes.keys()):
          print("%s: %.0f seconds for %.0f occurrences:   %.2f second/call"%(cmd,geminicmdtimes[cmd],geminicmdcnt[cmd], geminicmdtimes[cmd]*1.0/geminicmdcnt[cmd]),file=outfd)