예제 #1
0
    def pgm(self):
        q = QSetup(self, maxdil=16, debug=False, mindilvol=60)
        self.e.addIdleProgram(q.idler)
        input = [s.getsample() for s in self.srcs]

        # Save RT product from first (uncleaved) round and then use it during 2nd (cleaved) round for ligation and qPCR measurements
        prefixIn = [inp['prefix'] for inp in self.inputs]
        prefixOut = [
            "A" if p == "W" else
            "B" if p == "A" else "W" if p == "B" else "BADPREFIX"
            for p in prefixIn
        ]

        qpcrPrimers = ["REF", "MX", "T7X"]
        if "W" in prefixIn + prefixOut:
            qpcrPrimers += ["T7WX"]
        if "A" in prefixIn + prefixOut:
            qpcrPrimers += ["T7AX"]
        if "B" in prefixIn + prefixOut:
            qpcrPrimers += ["T7BX"]
        q.addSamples(decklayout.SSDDIL, 1, qpcrPrimers,
                     save=False)  # Negative controls

        print "Starting new cleavage round, will add prefix: ", prefixOut

        names = [i.name for i in input]

        print "######## T7 ###########"
        print "Inputs:  (t7vol=%.2f)" % self.t7vol
        for inp in input:
            print "    %s:  %.1ful@%.1f nM, use %.1f ul (%.3f pmoles)" % (
                inp.name, inp.volume, inp.conc.stock, self.t7vol /
                inp.conc.dilutionneeded(), self.t7vol * inp.conc.final / 1000)

        print "input[0]=", input[0]
        needDil = max([inp.conc.final for inp in input]) * 1.0 / self.qConc
        if self.directT7:
            # Just add MT7 and possibly water to each well
            mconc = reagents.getsample("MT7").conc.dilutionneeded()
            for i in range(len(input)):
                watervol = self.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(self.t7vol / mconc,
                                reagents.getsample("MT7"),
                                input[i],
                                mix=(False, False))
                assert (input[i].volume == self.t7vol)
            rxs = input
        else:
            rxs = self.runT7Setup(
                src=input,
                vol=self.t7vol,
                srcdil=[inp.conc.dilutionneeded() for inp in input])
        print "input[0]=", input[0]

        #for i in range(len(rxs)):
        #   q.addSamples(src=rxs],needDil=needDil,primers=["T7"+prefixIn[i]+"X","MX","T7X","REF"],names=["%s.T-"%names[i]])

        self.runT7Pgm(dur=self.t7dur, vol=self.t7vol)
        print "Template conc=%.1f nM, estimated RNA concentration in T7 reaction at %.0f nM" % (
            self.tmplFinalConc, self.rnaConc)

        print "######## Stop ###########"
        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=2,
                plate=decklayout.DILPLATE,
                dilutant=reagents.getsample("TE8"),
                mix=(False,
                     False))  # Save to check [RNA] on Qubit, bioanalyzer

        stop = [
            "A-Stop" if n == "A" else
            "B-Stop" if n == "B" else "W-Stop" if n == "W" else "BADPREFIX"
            for n in prefixOut
        ]

        for i in range(len(rxs)):
            rxs[i].name = rxs[i].name + "." + stop[i]

        needDil = self.rnaConc / self.qConc / stopDil
        #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

        rxin = rxs
        rxs = self.runRT(src=rxs,
                         vol=self.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]
        for r in rxin:
            if r.volume > 20:
                print "Have more T7 reaction remaining than needed: %s has %.1f ul" % (
                    r.name, r.volume)

        needDil /= rtDil
        rtPostDil = 5
        if rtPostDil != 1:
            self.diluteInPlace(tgt=rxs, dil=rtPostDil)
            needDil /= rtPostDil
        #q.addSamples(src=rxs,needDil=needDil,primers=["T7AX","MX","REF"],names=["%s.rt"%r.name for r in rxs])

        print "######## Ligation setup  ###########"
        extdil = 5.0 / 4
        reagents.getsample("MLigase").conc = Concentration(5)
        extvol = 20
        print "Extension volume=", extvol
        rxs = self.runLig(rxs, vol=extvol)

        print "Ligation volume= ", [x.volume for x in rxs]
        needDil = needDil / extdil
        extpostdil = 4
        if extpostdil > 1:
            print "Dilution after extension: %.2f" % extpostdil
            self.diluteInPlace(tgt=rxs, dil=extpostdil)
            needDil = needDil / extpostdil
            if not self.doexo:
                self.pcrdil = self.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
            for i in range(len(rxs)):
                q.addSamples(src=[ext[i]],
                             needDil=needDil / self.saveDil,
                             primers=[
                                 "T7" + prefixIn[i] + "X",
                                 "T7" + prefixOut[i] + "X", "MX", "T7X", "REF"
                             ],
                             names=["%s.ext" % names[i]])
        else:
            for i in range(len(rxs)):
                q.addSamples(src=[rxs[i]],
                             needDil=needDil,
                             primers=[
                                 "T7" + prefixIn[i] + "X",
                                 "T7" + prefixOut[i] + "X", "MX", "T7X", "REF"
                             ],
                             names=["%s.ext" % names[i]])

        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
            q.addSamples(src=rxs,
                         needDil=needDil,
                         primers=["T7AX", "T7BX", "MX", "T7X", "REF"],
                         names=["%s.exo" % names[i] for i in range(len(rxs))])
            #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 = []

        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)
            q.addSamples(src=[clean[i] for i in range(len(rxs))],
                         needDil=needDil,
                         primers=["T7AX", "MX", "T7X", "REF"])
            rxs = rxs + clean  # Use the cleaned products for PCR

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

        if self.dopcr:
            print "######### PCR #############"
            print "PCR Volume: %.1f, Dilution: %.1f, volumes available for PCR: [%s]" % (
                self.pcrvol, self.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 / self.pcrdil
            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

            gain = pcrgain(initConc, 400, self.pcrcycles)
            finalConc = initConc * gain
            print "Estimated starting concentration in PCR = %.1f nM, running %d cycles -> %.0f nM\n" % (
                needDil * self.qConc, self.pcrcycles, finalConc)
            pcr = self.runPCR(src=rxs,
                              vol=self.pcrvol,
                              srcdil=self.pcrdil,
                              ncycles=self.pcrcycles,
                              primers=["T7%sX" % x for x in prefixOut],
                              usertime=self.usertime,
                              fastCycling=True)

            needDil = finalConc / self.qConc
            pcrpostdil = 2
            if pcrpostdil > 1:
                self.diluteInPlace(pcr, pcrpostdil)
                needDil = needDil / pcrpostdil
            print "Projected final concentration = %.0f nM (after %.1fx dilution)" % (
                needDil * self.qConc, pcrpostdil)
            for i in range(len(pcr)):
                pcr[i].conc = Concentration(stock=finalConc / pcrpostdil,
                                            final=None,
                                            units='nM')

            if self.pcrSave:
                # Save samples at 1x
                if self.savedilplate:
                    sv = self.saveSamps(
                        src=pcr[:len(rxs)],
                        vol=[x.volume - 16.4 for x in pcr[:len(rxs)]],
                        dil=1,
                        plate=decklayout.DILPLATE)
                else:
                    sv = self.saveSamps(
                        src=pcr[:len(rxs)],
                        vol=[x.volume - 16.4 for x in pcr[:len(rxs)]],
                        dil=1,
                        plate=decklayout.EPPENDORFS)

                # 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)

        print "######### qPCR ###########"
        #q.addReferences(mindil=4,nsteps=6,primers=["T7X","MX","T7AX"])
        q.run(confirm=False)
예제 #2
0
    def pgm(self):
        q = QSetup(self,maxdil=16,debug=False,mindilvol=60)
        self.e.addIdleProgram(q.idler)
        input = [s.getsample()  for s in self.srcs]

        qpcrPrimers=["REF","MX","T7X","T7AX","T7BX","T7WX"]
        q.addSamples(decklayout.SSDDIL,1,qpcrPrimers,save=False)   # Negative controls

        # Save RT product from first (uncleaved) round and then use it during 2nd (cleaved) round for ligation and qPCR measurements
        prefixIn=[inp['prefix'] for inp in self.inputs]
        prefixOut=["A" if p=="W" else "B" if p=="A" else "W" if p=="B" else "BADPREFIX" for p in prefixIn]
            
        print "Starting new cleavage round, will add prefix: ",prefixOut

        names=[i.name for i in input]
            
        print "######## T7 ###########"
        print "Inputs:  (t7vol=%.2f)"%self.t7vol
        for inp in input:
            print "    %s:  %.1ful@%.1f nM, use %.1f ul (%.3f pmoles)"%(inp.name,inp.volume,inp.conc.stock,self.t7vol/inp.conc.dilutionneeded(), self.t7vol*inp.conc.final/1000)

        print "input[0]=",input[0]
        needDil = max([inp.conc.final for inp in input])*1.0/self.qConc
        if self.directT7:
            # Just add MT7 and possibly water to each well
            mconc=reagents.getsample("MT7").conc.dilutionneeded()
            for i in range(len(input)):
                watervol=self.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(self.t7vol/mconc,reagents.getsample("MT7"),input[i],mix=(False,False))
                assert(input[i].volume==self.t7vol)
            rxs=input
        else:
            rxs = self.runT7Setup(src=input,vol=self.t7vol,srcdil=[inp.conc.dilutionneeded() for inp in input])
        print "input[0]=",input[0]
            
        #for i in range(len(rxs)):
        #   q.addSamples(src=rxs],needDil=needDil,primers=["T7"+prefixIn[i]+"X","MX","T7X","REF"],names=["%s.T-"%names[i]])
        
        self.runT7Pgm(dur=self.t7dur,vol=self.t7vol)
        print "Template conc=%.1f nM, estimated RNA concentration in T7 reaction at %.0f nM"%(self.tmplFinalConc,self.rnaConc)
        
        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=[ "A-Stop" if n=="A" else "B-Stop" if n=="B" else "W-Stop" if n=="W" else "BADPREFIX" for n in prefixOut]

        for i in range(len(rxs)):
            rxs[i].name=rxs[i].name+"."+stop[i]

        stopDil=rxs[0].volume/preStopVolume
        needDil = self.rnaConc/self.qConc/stopDil
        #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

        rxin=rxs
        rxs=self.runRT(src=rxs,vol=self.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]
        for r in rxin:
            if r.volume>20:
                print "Have more T7 reaction remaining than needed: %s has %.1f ul"%(r.name,r.volume)

        needDil /= rtDil
        rtPostDil=5
        if rtPostDil!=1:
            self.diluteInPlace(tgt=rxs,dil=rtPostDil)
            needDil /= rtPostDil
        #q.addSamples(src=rxs,needDil=needDil,primers=["T7AX","MX","REF"],names=["%s.rt"%r.name for r in rxs])

        print "######## Ligation setup  ###########"
        extdil=5.0/4
        reagents.getsample("MLigase").conc=Concentration(5)
        extvol=20;
        print "Extension volume=",extvol
        rxs=self.runLig(rxs,vol=extvol)

        print "Ligation volume= ",[x.volume for x in rxs]
        needDil=needDil/extdil
        extpostdil=4
        if extpostdil>1:
            print "Dilution after extension: %.2f"%extpostdil
            self.diluteInPlace(tgt=rxs,dil=extpostdil)
            needDil=needDil/extpostdil
            if not self.doexo:
                self.pcrdil=self.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
            for i in range(len(rxs)):
                q.addSamples(src=[ext[i]],needDil=needDil/self.saveDil,primers=["T7"+prefixIn[i]+"X","T7"+prefixOut[i]+"X","MX","T7X","REF"],names=["%s.ext"%names[i]])
        else:
            for i in range(len(rxs)):
                q.addSamples(src=[rxs[i]],needDil=needDil,primers=["T7"+prefixIn[i]+"X","T7"+prefixOut[i]+"X","MX","T7X","REF"],names=["%s.ext"%names[i]])

        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
            q.addSamples(src=rxs,needDil=needDil,primers=["T7AX","T7BX","MX","T7X","REF"],names=["%s.exo"%names[i] for i in range(len(rxs))])
            #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=[]
        
        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)
            q.addSamples(src=[clean[i] for i in range(len(rxs))],needDil=needDil,primers=["T7AX","MX","T7X","REF"])
            rxs=rxs+clean   # Use the cleaned products for PCR
            
        totalDil=stopDil*rtDil*rtPostDil*extdil*extpostdil*exoDil
        fracRetained=rxs[0].volume/(self.t7vol*totalDil)
        print "Total dilution from T7 to Pre-pcr Product = %.2f*%.2f*%.2f*%.2f*%.2f*%.2f = %.2f, fraction retained=%.0f%%"%(stopDil,rtDil,rtPostDil,extdil,extpostdil,exoDil,totalDil,fracRetained*100)

        if self.dopcr:
            print "######### PCR #############"
            print "PCR Volume: %.1f, Dilution: %.1f, volumes available for PCR: [%s]"%(self.pcrvol, self.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/self.pcrdil
            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

            gain=pcrgain(initConc,400,self.pcrcycles)
            finalConc=initConc*gain
            print "Estimated starting concentration in PCR = %.1f nM, running %d cycles -> %.0f nM\n"%(needDil*self.qConc,self.pcrcycles,finalConc)
            pcr=self.runPCR(src=rxs,vol=self.pcrvol,srcdil=self.pcrdil,ncycles=self.pcrcycles,primers=["T7%sX"%x for x in prefixOut],usertime=self.usertime,fastCycling=True)
                
            needDil=finalConc/self.qConc
            pcrpostdil=2
            if pcrpostdil>1:
                self.diluteInPlace(pcr,pcrpostdil)
                needDil=needDil/pcrpostdil
            print "Projected final concentration = %.0f nM (after %.1fx dilution)"%(needDil*self.qConc,pcrpostdil)
            for i in range(len(pcr)):
                pcr[i].conc=Concentration(stock=finalConc/pcrpostdil,final=None,units='nM')

            if self.pcrSave:
                # Save samples at 1x
                if self.savedilplate:
                    sv=self.saveSamps(src=pcr[:len(rxs)],vol=[x.volume-16.4 for x in pcr[:len(rxs)]],dil=1,plate=decklayout.DILPLATE)
                else:
                    sv=self.saveSamps(src=pcr[:len(rxs)],vol=[x.volume-16.4 for x in pcr[:len(rxs)]],dil=1,plate=decklayout.EPPENDORFS)

                # 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)

        print "######### qPCR ###########"
        #q.addReferences(mindil=4,nsteps=6,primers=["T7X","MX","T7AX"])
        #worklist.userprompt('Continue to setup qPCR')
        q.run()
예제 #3
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
예제 #4
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