예제 #1
0
파일: TRP.py 프로젝트: qPCR4vir/pyTecan
    def finish(self):
        self.e.lihahome()
        worklist.userprompt("Process complete. Continue to turn off reagent cooler")
        self.e.setreagenttemp(None)

        #Sample.printallsamples("At completion")
        hasError=False
        for s in Sample.getAllOnPlate():
            if s.volume<1.0 and s.conc is not None and not s.hasBeads:
                print "ERROR: Insufficient volume for ", s," need at least ",1.0-s.volume," ul additional"
                #hasError=True
            elif s.volume<2.5 and s.conc is not None:
                print "WARNING: Low final volume for ", s
            elif s.volume>s.plate.maxVolume:
                print "ERROR: Excess final volume  (",s.volume,") for ",s,", maximum is ",s.plate.maxVolume
                hasError=True
                
        if hasError:
            print "NO OUTPUT DUE TO ERRORS"
            assert(False)
            
        print "Wells used:  samples: %d, dilutions: %d, qPCR: %d"%(Sample.numSamplesOnPlate(decklayout.SAMPLEPLATE),Sample.numSamplesOnPlate(decklayout.DILPLATE),Sample.numSamplesOnPlate(decklayout.QPCRPLATE))
        # Save worklist to a file
        #e.saveworklist("trp1.gwl")
        (scriptname,ext)=os.path.splitext(sys.argv[0])
        self.e.savegem(scriptname+".gem")
        self.e.savesummary(scriptname+".txt")
        Sample.savematlab(scriptname+".m")
예제 #2
0
    def finish(self):
        self.e.lihahome()
        worklist.userprompt("Process complete. Continue to turn off reagent cooler")
        self.e.setreagenttemp(None)

        #Sample.printallsamples("At completion")
        hasError=False
        for s in Sample.getAllOnPlate():
            if s.volume<1.0 and s.conc is not None and not s.emptied:
                logging.error("Insufficient volume for %s: need at least %.1f ul additional"%(s.name,1.0-s.volume),fatal=False)
                #hasError=True
            elif s.volume<2.5 and s.conc is not None and not s.emptied:
                logging.warning("Low final volume for "+ s.name)
            elif s.volume>s.plate.maxVolume:
                logging.erorr("Excess final volume  (%.1f) for %s: maximum is %.1f ul"%(s.volume,s.name,s.plate.maxVolume),fatal=False)
                hasError=True
                
        if hasError:
            logging.error("NO OUTPUT DUE TO ERRORS")
            
        print "Wells used:  samples: %d, dilutions: %d, qPCR: %d"%(Sample.numSamplesOnPlate(decklayout.SAMPLEPLATE),Sample.numSamplesOnPlate(decklayout.DILPLATE),Sample.numSamplesOnPlate(decklayout.QPCRPLATE))
        # Save worklist to a file
        #e.saveworklist("trp1.gwl")
        (scriptname,ext)=os.path.splitext(sys.argv[0])
        self.e.savegem(scriptname+".gem")
        self.e.savesummary(scriptname+".txt")
        Sample.savematlab(scriptname+".m")
예제 #3
0
for pm in tmplqpcr:
    if Sample.lookup("MQ"+pm)==None:
        Sample("MQ"+pm,Experiment.REAGENTPLATE,None,10.0/6)
    
reagents=None


for iteration in range(2):
    print "Iteration ",iteration+1
    trp=TRP()

    if iteration==0:
        trp.addTemplates(input,stockconc=10.0/6.0,units="x",plate=Experiment.EPPENDORFS)   # Add a template
    else:   
        reagents=Sample.getAllOnPlate(Experiment.REAGENTPLATE)+Sample.getAllOnPlate(Experiment.EPPENDORFS)
        for r in reagents:
            if r.volume<=0:
                r.initvolume=-r.volume+r.plate.unusableVolume
        Sample.clearall()

    t71=trp.runT7(theo=False,src=srcs,tgt=[],vol=10,srcdil=10.0/6,dur=15,stopmaster=stop)
    #print t71
    t71=trp.diluteInPlace(tgt=t71,dil=5)
    # Dilute input samples enough to use in qPCR directly (should be 5000/(rnagain*2*5)  = 20)
    qpcrdil1=trp.runQPCRDIL(src=t71,tgt=[],vol=100,srcdil=20,dilPlate=False)
    
    rt1=trp.runRT(pos=True,src=t71,tgt=[],vol=30,srcdil=2)
    rt1=trp.diluteInPlace(tgt=rt1,dil=5)
    
    lig=trp.runLig(src=rt1*6,tgt=[],vol=20,srcdil=3,master=ligmaster1*3+ligmaster2*3)
예제 #4
0
from Experiment.experiment import Experiment
import math
from TRPLib.trp import TRP

reagents=None
input="BT409"
srcprefix="B"
prodprefix="A"

for iteration in range(2):
    print "Iteration ",iteration+1
    trp=TRP()
    if iteration==0:
        trp.addTemplates([input],200)   # Add a template with stock concentration 200nM
    else:   
        reagents=Sample.getAllOnPlate(Experiment.REAGENTPLATE)
        for r in reagents:
            if r.volume<0:
                r.initvolume=-r.volume+20
        Sample.clearall()


    # Round 1 (Keep uncleaved +theo)
    t71=trp.runT7(theo=[False,True],src=[input,input],tgt=[],vol=[16,18],srcdil=4)
    sv1t7=trp.saveSamps(src=t71,tgt=[],vol=10,dil=[4,4])
    rt1=trp.runRT(pos=[True,True],src=t71,tgt=[],vol=[15,22],srcdil=2)
    trp.diluteInPlace(tgt=rt1,dil=2)
    sv1rt=trp.saveSamps(src=rt1,tgt=[],vol=15,dil=2)
    pcr1=trp.runPCR(prefix=[srcprefix],src=rt1[1],tgt=[],vol=50,srcdil=4)
    trp.diluteInPlace(tgt=pcr1,dil=3)
    sv1pcr=trp.saveSamps(src=pcr1,tgt=["R1"],vol=125,dil=1)
예제 #5
0
    if Sample.lookup("MQ" + pm) == None:
        Sample("MQ" + pm, Experiment.REAGENTPLATE, None, 10.0 / 6)

reagents = None

for iteration in range(2):
    print "Iteration ", iteration + 1
    trp = TRP()

    if iteration == 0:
        trp.addTemplates(input,
                         stockconc=10.0 / 6.0,
                         units="x",
                         plate=Experiment.EPPENDORFS)  # Add a template
    else:
        reagents = Sample.getAllOnPlate(
            Experiment.REAGENTPLATE) + Sample.getAllOnPlate(
                Experiment.EPPENDORFS)
        for r in reagents:
            if r.volume <= 0:
                r.initvolume = -r.volume + r.plate.unusableVolume
        Sample.clearall()

    t71 = trp.runT7(theo=False,
                    src=srcs,
                    tgt=[],
                    vol=10,
                    srcdil=10.0 / 6,
                    dur=15,
                    stopmaster=stop)
    #print t71
    t71 = trp.diluteInPlace(tgt=t71, dil=5)
예제 #6
0
print "PCR1 input conc=%.3g pM, PCR cycles=%.1f, End Conc=%.0f nM" % (
    pcrinconc1 * 1e12, cycles1, pcrinconc1 * (math.pow(pcreff, cycles1)) * 1e9)
print "PCR2 input conc=%.3g pM, PCR cycles=%.1f, End Conc=%.0f nM" % (
    pcrinconc2 * 1e12, cycles2, pcrinconc2 * (math.pow(pcreff, cycles2)) * 1e9)

for iteration in range(2):
    print "Iteration ", iteration + 1
    trp = TRP()
    input = "IN-" + srcprefix
    if iteration == 0:
        #rnastore=Sample("RNA Storage",Experiment.REAGENTPLATE,None,None)
        trp.addTemplates(
            [input], tmplConc * 1e9
        )  # Add a template with stock concentration same as subsequent PCR products
    else:
        reagents = Sample.getAllOnPlate(Experiment.REAGENTPLATE)
        for r in reagents:
            if r.volume < 0:
                r.initvolume = -r.volume + 20
        Sample.clearall()

    currprefix = srcprefix
    if currprefix == 'A':
        altprefix = 'B'
    else:
        altprefix = 'A'
    sv = []
    svligtype = []
    svdil = []
    t7all = []
예제 #7
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, []