def runLig(self,prefix=None,src=None,vol=None,srcdil=None,tgt=None,master=None,anneal=True,ligtemp=25): if master is None: master=[reagents.getsample("MLigAN7") if p=='A' else reagents.getsample("MLigBN7") for p in prefix] #Extension [src,tgt,vol,srcdil,master]=listify([src,tgt,vol,srcdil,master]) if tgt is None: tgt=[Sample("%s.%s"%(src[i].name,master[i].name),decklayout.SAMPLEPLATE) for i in range(len(src))] # Need to check since an unused ligation master mix will not have a concentration minsrcdil=1/(1-1/master[0].conc.dilutionneeded()-1/reagents.getsample("MLigase").conc.dilutionneeded()) for i in srcdil: if i<minsrcdil: print "runLig: srcdil=%.2f, but must be at least %.2f based on concentrations of master mixes"%(i,minsrcdil) assert(False) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) i=0 while i<len(tgt): lasti=i+1 while lasti<len(tgt) and master[i]==master[lasti]: lasti=lasti+1 self.e.stage('LigAnneal',[master[i]],src[i:lasti],tgt[i:lasti],[vol[j]/1.5 for j in range(i,lasti)],1.5,destMix=False) i=lasti if anneal: self.e.shakeSamples(tgt,returnPlate=False) self.e.runpgm("TRPANN",5,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100) self.e.stage('Ligation',[reagents.getsample("MLigase")],[],tgt,vol,destMix=False) self.e.shakeSamples(tgt,returnPlate=False) self.runLigPgm(max(vol),ligtemp) return tgt
def runLigInPlace(self, src, vol, ligmaster, anneal=True, ligtemp=25): 'Run ligation on beads' [vol, src] = listify([vol, src]) annealvol = [ v * (1 - 1 / reagents.getsample("MLigase").conc.dilutionneeded()) for v in vol ] # Adjust source dilution for i in range(len(src)): src[i].conc = None self.runRxInPlace(src, annealvol, reagents.getsample(ligmaster), returnPlate=not anneal, finalx=1.5) if anneal: self.e.runpgm("TRPANN", 5, False, max([s.volume for s in src]), hotlidmode="CONSTANT", hotlidtemp=100) ## Add ligase self.runRxInPlace(src, vol, reagents.getsample("MLigase"), returnPlate=False) self.runLigPgm( max(vol), ligtemp, inactivate=False ) # Do not heat inactivate since it may denature the beads
def runAmpure(self,src,ratio,tgt=None,incTime=5*60,elutionVol=None,evapTime=2*60): if elutionVol is None: elutionVol=src[0].volume self.bindBeads(src=src,beads=reagents.getsample("Ampure"),beadDil=(ratio+1)/ratio,incTime=incTime) self.beadWash(src=src,wash=reagents.getsample("EtOH80"),washVol=100,numWashes=2) self.e.pause(evapTime) # Wait for evaporation self.beadAddElutant(src=src,elutant=reagents.getsample("TE8"),elutionVol=elutionVol) tgt=self.beadSupernatant(src=src,sepTime=120,tgt=[Sample("%s.ampure"%r.name,decklayout.SAMPLEPLATE) for r in src]) return tgt
def bindBeads(self, src, beads=None, beadConc=None, bbuffer=None, incTime=60, addBuffer=False): if beads is None: beads = reagents.getsample("Dynabeads") if bbuffer is None: bbuffer = reagents.getsample("BeadBuffer") [src, beads, bbuffer, beadConc] = listify([src, beads, bbuffer, beadConc]) for s in src: if s.plate != decklayout.SAMPLEPLATE: print "runBeadCleanup: src ", s, " is not in sample plate." assert (0) s.conc = None # Can't track concentration of beads self.e.moveplate(src[0].plate, "Home") # Make sure we do this off the magnet # Calculate volumes needed beadConc = [ beads[i].conc.final if beadConc[i] is None else beadConc[i] for i in range(len(beads)) ] beadDil = beads[i].conc.stock / beadConc[i] if addBuffer: totalvol = [ s.volume / (1 - 1.0 / beadDil - 1.0 / bbuffer[i].conc.dilutionneeded()) for s in src ] buffervol = [ totalvol[i] / bbuffer[i].conc.dilutionneeded() for i in range(len(src)) ] # Add binding buffer to bring to 1x (beads will already be in 1x, so don't need to provide for them) for i in range(len(src)): self.e.transfer(buffervol[i], bbuffer[i], src[i]) else: buffervol = [0.0 for i in range(len(src))] totalvol = [s.volume / (1 - 1.0 / beadDil) for s in src] beadvol = [t / beadDil for t in totalvol] # Transfer the beads for i in range(len(src)): self.e.transfer( beadvol[i], beads[i], src[i], (True, True) ) # Mix beads after (before mixing handled automatically by sample.py) self.e.shake(src[0].plate, dur=incTime, returnPlate=False)
def runQPCR(self,src,vol,primers,nreplicates=1,enzName="EvaUSER"): ## QPCR setup worklist.comment("runQPCR: primers=%s, source=%s"%([p for p in primers],[s.name for s in src])) [src,vol,nreplicates]=listify([src,vol,nreplicates]) self.e.shakeSamples(src,returnPlate=True) # Build a list of sets to be run torun=[] for repl in range(max(nreplicates)): for p in primers: for i in range(len(src)): if nreplicates[i]<=repl: continue if repl==0: sampname="%s.Q%s"%(src[i].name,p) else: sampname="%s.Q%s.%d"%(src[i].name,p,repl+1) s=Sample(sampname,decklayout.QPCRPLATE) torun=torun+[(src[i],s,p,vol[i])] # Add enzyme e=reagents.getsample(enzName) v=[a[3]/e.conc.dilutionneeded() for a in torun] t=[a[1] for a in torun] self.e.multitransfer(v,e,t) # Make the target have 'none' concentration so we can multiadd to it again for s in t: s.conc=None # Fill the master mixes dil={} for p in primers: mname="P-%s"%p if not reagents.isReagent(mname): reagents.add(name=mname,conc=4,extraVol=30) mq=reagents.getsample(mname) t=[a[1] for a in torun if a[2]==p] v=[a[3]/mq.conc.dilutionneeded() for a in torun if a[2]==p] assert(v>0) self.e.multitransfer(v,mq,t,(False,False)) dil[p]=1.0/(1-1/e.conc.dilutionneeded()-1/mq.conc.dilutionneeded()) # Add the samples self.e.sanitize() # In case we are aligned for a in torun: s=a[0] t=a[1] p=a[2] v=a[3]/dil[p] t.conc=None # Concentration of master mix is irrelevant now self.e.transfer(v,s,t) return [a[1] for a in torun]
def runT7Setup(self, theo, src, vol, srcdil, tgt=None, rlist=["MT7"]): [theo, src, tgt, srcdil] = listify([theo, src, tgt, srcdil]) for i in range(len(src)): if tgt[i] is None: if theo[i]: tgt[i] = Sample("%s.T+" % src[i].name, decklayout.SAMPLEPLATE) else: tgt[i] = Sample("%s.T-" % src[i].name, decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s" % [str(s) for s in src]) rvols = [reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal = sum(rvols) sourcevols = [vol * 1.0 / s for s in srcdil] if any(theo): theovols = [ (vol * 1.0 / reagents.getsample("Theo").conc.dilutionneeded() if t else 0) for t in theo ] watervols = [ vol - theovols[i] - sourcevols[i] - rtotal for i in range(len(src)) ] else: watervols = [vol - sourcevols[i] - rtotal for i in range(len(src))] if any([w < -1e-10 for w in watervols]): print "runT7Setup: Negative amount of water required: ", watervols assert False if sum(watervols) > 0.01: self.e.multitransfer(watervols, decklayout.WATER, tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt], reagents.getsample(rlist[ir]), tgt) if any(theo): self.e.multitransfer( [tv for tv in theovols if tv > 0.01], reagents.getsample("Theo"), [tgt[i] for i in range(len(theovols)) if theovols[i] > 0], ignoreContents=True) for i in range(len(src)): self.e.transfer(sourcevols[i], src[i], tgt[i]) self.e.shakeSamples(tgt, returnPlate=True) for t in tgt: t.ingredients['BIND'] = 1e-20 * sum(t.ingredients.values()) return tgt
def runPCRInPlace(self, prefix, src, vol, ncycles, suffix, annealtemp=57, save=None): [prefix, src, vol, suffix] = listify([prefix, src, vol, suffix]) primer = [ reagents.getsample("MPCR" + prefix[i] + suffix[i]) for i in range(len(prefix)) ] self.runRxInPlace(src, vol, primer, returnPlate=(save is not None)) if save is not None: self.saveSamps(src=src, vol=5, dil=10, tgt=save, plate=decklayout.DILPLATE, dilutant=decklayout.SSDDIL) pgm = "PCR%d" % ncycles # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun( 'PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@%f,10 GOTO@2,%d TEMP@72,120 TEMP@25,2' % (pgm, annealtemp, ncycles - 1)) self.e.runpgm(pgm, 4.80 + 1.55 * ncycles, False, max(vol), hotlidmode="CONSTANT", hotlidtemp=100)
def addReferences(self,mindil=1,nsteps=6,dstep=4,nreplicates=1,ref=None,primers=None): 'Add all needed references' #print "addReferences(mindil=",mindil,", nsteps=",nsteps,", dstep=",dstep,", nrep=", nreplicates, ", ref=",ref,")" # Make sure the ref reagent is loaded if ref is None: ref=reagents.getsample("QPCRREF") if primers is None: primers=self.allprimers() dils=[1] for i in range(nsteps): needDil=mindil*math.pow(dstep,i) srcDil=1 src=[ref] for j in range(len(dils)): if needDil/dils[j] <= self.MAXDIL: srcDil=dils[j] if srcDil==1: src=[ref] else: srcname="%s.D%d"%(ref.name,srcDil) src=[Sample.lookup(srcname)] if src[0] is None: src=[Sample(srcname,decklayout.DILPLATE)] break tmp=self.MINDILVOL self.MINDILVOL=75 # Make sure there's enough for resuing dilutions self.addSamples(src=src,needDil=needDil/srcDil,primers=primers,nreplicates=nreplicates,save=needDil/srcDil>self.MAXDIL,saveVol=75) self.MINDILVOL=tmp dils.append(needDil) self.addSamples(src=[self.dilutant],needDil=1,primers=primers,nreplicates=nreplicates,save=False)
def addReferences(self, mindil=1, nsteps=6, dstep=4, nreplicates=1, ref=None, primers=None): """Add all needed references""" # print "addReferences(mindil=",mindil,", nsteps=",nsteps,", dstep=",dstep,", nrep=", nreplicates, ", ref=",ref,")" # Make sure the ref reagent is loaded if ref is None: ref = reagents.getsample("QPCRREF") if primers is None: primers = self.allprimers() dils = [1.0] for i in range(nsteps): needDil = mindil * math.pow(dstep, i) srcDil = 1 src = [ref] for j in range(len(dils)): if needDil / dils[j] <= self.MAXDIL: srcDil = dils[j] if srcDil == 1: src = [ref] else: srcname = "%s.D%d" % (ref.name, srcDil) src = [Sample.lookup(srcname)] if src[0] is None: src = [Sample(srcname, decklayout.DILPLATE)] break tmp = self.MINDILVOL self.MINDILVOL = 75 # Make sure there's enough for resuing dilutions self.addSamples(src=src, needDil=needDil / srcDil, primers=primers, nreplicates=nreplicates, save=needDil / srcDil > self.MAXDIL, saveVol=75) self.MINDILVOL = tmp dils.append(needDil) self.addSamples(src=[self.dilutant], needDil=1, primers=primers, nreplicates=nreplicates, save=False)
def pgm(self): self.q = QSetup(self, maxdil=16, debug=False, mindilvol=60) # Don't start idler (to minimize tip cross-contamination); last PCR allows plenty of time for doing dilutions without any effect on run time # Will start after first constriction PCR is running #self.q.debug = True # self.e.addIdleProgram(self.q.idler) self.q.addReferences(dstep=10, primers=self.qprimers, ref=reagents.getsample("BT5310"),nreplicates=2) samps=[r.getsample() for r in self.rsrc] for s in samps: self.q.addSamples([s],needDil=max(10,s.conc.stock*1e-9/self.qconc),primers=self.qprimers) print("### Mixdown #### (%.0f min)" % (clock.elapsed() / 60.0)) if len(samps)>1: mixdown = self.mix(samps, [x['weight'] for x in self.inputs]) else: mixdown=samps[0] self.q.addSamples(mixdown, needDil=max(1.0,mixdown.conc.stock * 1e-9 / self.qconc), primers=self.qprimers) print("Mixdown final concentration = %.0f pM" % (mixdown.conc.stock * 1000)) print("### Constriction #### (%.1f min)" % (clock.elapsed() / 60.0)) constricted = self.constrict(mixdown, mixdown.conc.stock * 1e-9) print("### Regeneration #### (%.0f min)" % (clock.elapsed() / 60.0)) prefixes = set([x['left'][0] for x in self.inputs]) self.regenerate(constricted * len(prefixes), [p for p in prefixes for _ in constricted]) print("### qPCR #### (%.0f min)" % (clock.elapsed() / 60.0)) self.q.run(confirm=False, enzName='EvaGreen', waitForPTC=True) print("### qPCR Done #### (%.0f min)" % (clock.elapsed() / 60.0)) worklist.userprompt("qPCR done -- only need to complete final PCR", 300) self.e.waitpgm() print("### Final PCR Done #### (%.0f min)" % (clock.elapsed() / 60.0))
def runLigInPlace(self,src,vol,ligmaster,anneal=True,ligtemp=25): 'Run ligation on beads' [vol,src]=listify([vol,src]) annealvol=[v*(1-1/reagents.getsample("MLigase").conc.dilutionneeded()) for v in vol] # Adjust source dilution for i in range(len(src)): src[i].conc=None self.runRxInPlace(src,annealvol,reagents.getsample(ligmaster),returnPlate=not anneal,finalx=1.5) if anneal: self.e.runpgm("TRPANN",5,False,max([s.volume for s in src]),hotlidmode="CONSTANT",hotlidtemp=100) ## Add ligase self.runRxInPlace(src,vol,reagents.getsample("MLigase"),returnPlate=False) self.runLigPgm(max(vol),ligtemp,inactivate=False) # Do not heat inactivate since it may denature the beads
def __init__(self, inputs, pcr1inputconc=0.05, used=None,doqpcr=True,inputPlate=decklayout.SAMPLEPLATE): super(Barcoding, self).__init__() if used is None: used = [] self.inputs = inputs self.qconc = 50e-12 # Target qPCR concentration self.qprimers = ["End"] self.doqpcr=doqpcr self.bc1_inputvol = 4 # ul of input samples self.mix_conc = 100e-9 # Concentration of mixdown self.pcr1inputconc = pcr1inputconc for inp in inputs: bc = "%s-%s" % (inp['left'], inp['right']) if bc in used: logging.error("Barcode %s is being reused for %s" % (bc, inp['name'])) used.append(bc) for x in inputs: if not reagents.isReagent(x['name']): reagents.add(x['name'], inputPlate, well=x['well'] if 'well' in x else None, conc=Concentration(stock=x['conc'], units="nM"), initVol=self.bc1_inputvol, extraVol=0) else: r = reagents.getsample(x['name']) if r.conc.stock != x['conc']: logging.error('Input %s has conflicting concentrations set: %f and %f', x['name'], r.conc.stock, x['conc']) assert False self.q = None # Defined in pgm()
def runT7Setup(self,src,vol,srcdil,ligands=None,tgt=None,rlist=["MT7"]): if isinstance(ligands,bool): if not ligands: ligands=None else: assert('runT7Setup: ligands arg should be ligand samples or None, not True') [ligands,src,tgt,srcdil]=listify([ligands,src,tgt,srcdil]) for i in range(len(src)): if tgt[i] is None: if ligands[i] is not None: tgt[i]=Sample("%s.T+%s"%(src[i].name,ligands[i].name),decklayout.SAMPLEPLATE) else: tgt[i]=Sample("%s.T-"%src[i].name,decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s"%[str(s) for s in src]) rvols=[reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal=sum(rvols) sourcevols=[vol*1.0/s for s in srcdil] ligandvols=[0 for s in srcdil] watervols=[0 for s in srcdil] for i in range(len(srcdil)): if ligands[i] is not None: ligandvols[i]=vol*1.0/ligands[i].conc.dilutionneeded() watervols[i]=vol-ligandvols[i]-sourcevols[i]-rtotal else: watervols[i]=vol-sourcevols[i]-rtotal if any([w<-.01 for w in watervols]): logging.error("runT7Setup: Negative amount of water required: "+str(watervols)) if sum(watervols)>0.01: self.e.multitransfer(watervols,decklayout.WATER,tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt],reagents.getsample(rlist[ir]),tgt) for i in range(len(ligands)): if ligandvols[i] > 0.01: self.e.transfer(ligandvols[i],ligands[i],tgt[i]) for i in range(len(src)): self.e.transfer(sourcevols[i],src[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) for t in tgt: t.ingredients['BIND']=1e-20*sum(t.ingredients.values()) return tgt
def addEDTA(self,tgt,finalconc=4): edta=reagents.getsample("EDTA") edta.conc.final=finalconc srcdil=edta.conc.stock*1.0/(edta.conc.stock-finalconc) for t in tgt: t.conc=Concentration(srcdil,1) v=t.volume*finalconc/(edta.conc.stock-finalconc) self.e.transfer(v,edta,t,mix=(False,False)) self.e.shakeSamples(tgt,returnPlate=True)
def runRTInPlace(self,src,vol,dur=20,heatInactivate=False): 'Run RT on beads in given volume' # Adjust source dilution for i in range(len(src)): src[i].conc=None self.runRxInPlace(src,vol,reagents.getsample("MPosRT"),returnPlate=False) self.runRTPgm(dur,heatInactivate=heatInactivate)
def pgm(self): self.q = QSetup(self, maxdil=16, debug=False, mindilvol=60) self.q.debug = True self.q.addReferences(dstep=10, primers=self.qprimers, ref=reagents.getsample("BT5310"),nreplicates=2) print("### Barcoding #### (%.0f min)" % (clock.elapsed() / 60.0)) self.idbarcoding(self.rsrc, left=[x['left'] for x in self.inputs], right=[x['right'] for x in self.inputs]) print("### qPCR #### (%.0f min)" % (clock.elapsed() / 60.0)) self.q.run(confirm=False, enzName='EvaGreen')
def runPCRInPlace(self,prefix,src,vol,ncycles,suffix,annealtemp=57,save=None): [prefix,src,vol,suffix]=listify([prefix,src,vol,suffix]) primer=[reagents.getsample("MPCR"+prefix[i]+suffix[i]) for i in range(len(prefix))] self.runRxInPlace(src,vol,primer,returnPlate=(save is not None)) if save is not None: self.saveSamps(src=src,vol=5,dil=10,tgt=save,plate=decklayout.DILPLATE,dilutant=decklayout.SSDDIL) pgm="PCR%d"%ncycles # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@%f,10 GOTO@2,%d TEMP@72,120 TEMP@25,2'%(pgm,annealtemp,ncycles-1)) self.e.runpgm(pgm,4.80+1.55*ncycles,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100)
def runRTInPlace(self, src, vol, dur=20, heatInactivate=False): 'Run RT on beads in given volume' # Adjust source dilution for i in range(len(src)): src[i].conc = None self.runRxInPlace(src, vol, reagents.getsample("MPosRT"), returnPlate=False) self.runRTPgm(dur, heatInactivate=heatInactivate)
def runT7Stop(self,theo,tgt,stopmaster=None,srcdil=2): [theo,tgt,stopmaster,srcdil]=listify([theo,tgt,stopmaster,srcdil]) assert( stopmaster is not None) ## Stop sstopmaster=[reagents.getsample(s) for s in stopmaster] for i in range(len(tgt)): stopvol=tgt[i].volume/(sstopmaster[i].conc.dilutionneeded()-1) finalvol=tgt[i].volume+stopvol tgt[i].conc=Concentration(finalvol/tgt[i].volume,1) # Adjust source dilution to avoid warnings self.e.transfer(finalvol-tgt[i].volume,sstopmaster[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) return tgt
def runT7Setup(self,theo,src,vol,srcdil,tgt=None,rlist=["MT7"]): [theo,src,tgt,srcdil]=listify([theo,src,tgt,srcdil]) for i in range(len(src)): if tgt[i] is None: if theo[i]: tgt[i]=Sample("%s.T+"%src[i].name,decklayout.SAMPLEPLATE) else: tgt[i]=Sample("%s.T-"%src[i].name,decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s"%[str(s) for s in src]) rvols=[reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal=sum(rvols) sourcevols=[vol*1.0/s for s in srcdil] if any(theo): theovols=[(vol*1.0/reagents.getsample("Theo").conc.dilutionneeded() if t else 0) for t in theo] watervols=[vol-theovols[i]-sourcevols[i]-rtotal for i in range(len(src))] else: watervols=[vol-sourcevols[i]-rtotal for i in range(len(src))] if any([w<-1e-10 for w in watervols]): print "runT7Setup: Negative amount of water required: ",watervols assert False if sum(watervols)>0.01: self.e.multitransfer(watervols,decklayout.WATER,tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt],reagents.getsample(rlist[ir]),tgt) if any(theo): self.e.multitransfer([tv for tv in theovols if tv>0.01],reagents.getsample("Theo"),[tgt[i] for i in range(len(theovols)) if theovols[i]>0],ignoreContents=True) for i in range(len(src)): self.e.transfer(sourcevols[i],src[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) for t in tgt: t.ingredients['BIND']=1e-20*sum(t.ingredients.values()) return tgt
def bindBeads(self,src,beads=None,beadConc=None,bbuffer=None,incTime=60,addBuffer=False): if beads is None: beads=reagents.getsample("Dynabeads") if bbuffer is None: bbuffer=reagents.getsample("BeadBuffer") [src,beads,bbuffer,beadConc]=listify([src,beads,bbuffer,beadConc]) for s in src: if s.plate!=decklayout.SAMPLEPLATE: print "runBeadCleanup: src ",s," is not in sample plate." assert(0) s.conc=None # Can't track concentration of beads self.e.moveplate(src[0].plate,"Home") # Make sure we do this off the magnet # Calculate volumes needed beadConc=[beads[i].conc.final if beadConc[i] is None else beadConc[i] for i in range(len(beads))] beadDil=beads[i].conc.stock/beadConc[i] if addBuffer: totalvol=[s.volume/(1-1.0/beadDil-1.0/bbuffer[i].conc.dilutionneeded()) for s in src] buffervol=[totalvol[i]/bbuffer[i].conc.dilutionneeded() for i in range(len(src))] # Add binding buffer to bring to 1x (beads will already be in 1x, so don't need to provide for them) for i in range(len(src)): self.e.transfer(buffervol[i],bbuffer[i],src[i]) else: buffervol=[0.0 for i in range(len(src))] totalvol=[s.volume/(1-1.0/beadDil) for s in src] beadvol=[t/beadDil for t in totalvol] # Transfer the beads for i in range(len(src)): self.e.transfer(beadvol[i],beads[i],src[i],(True,True)) # Mix beads after (before mixing handled automatically by sample.py) self.e.shake(src[0].plate,dur=incTime,returnPlate=False)
def runRTSetup(self,src,vol,srcdil,tgt=None,rtmaster=None): if rtmaster is None: rtmaster=reagents.getsample("MPosRT") if tgt is None: tgt=[Sample(s.name+".RT+",decklayout.SAMPLEPLATE) for s in src] [src,tgt,vol,srcdil]=listify([src,tgt,vol,srcdil]) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) self.e.stage('RTPos',[rtmaster],[src[i] for i in range(len(src)) ],[tgt[i] for i in range(len(tgt)) ],[vol[i] for i in range(len(vol))],destMix=False) #self.e.shakeSamples(tgt,returnPlate=True) return tgt
def runUser(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, inPlace=False): return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, enzymes=[reagents.getsample("MUser")], inPlace=inPlace)
def runQPCR(self, src, vol, srcdil, primers=["A", "B"], nreplicates=1): ## QPCR setup worklist.comment("runQPCR: primers=%s, source=%s" % ([p for p in primers], [s.name for s in src])) [src, vol, srcdil, nreplicates] = listify([src, vol, srcdil, nreplicates]) self.e.shakeSamples(src, returnPlate=True) # Build a list of sets to be run torun = [] for repl in range(max(nreplicates)): for p in primers: for i in range(len(src)): if nreplicates[i] <= repl: continue if repl == 0: sampname = "%s.Q%s" % (src[i].name, p) else: sampname = "%s.Q%s.%d" % (src[i].name, p, repl + 1) s = Sample(sampname, decklayout.QPCRPLATE) torun = torun + [(src[i], s, p, vol[i])] # Fill the master mixes dil = {} for p in primers: mname = "MQ%s" % p if not reagents.isReagent(mname): reagents.add(name=mname, conc=15.0 / 9.0, extraVol=30) mq = reagents.getsample(mname) t = [a[1] for a in torun if a[2] == p] v = [a[3] / mq.conc.dilutionneeded() for a in torun if a[2] == p] self.e.multitransfer(v, mq, t, (False, False)) dil[p] = 1.0 / (1 - 1 / mq.conc.dilutionneeded()) # Add the samples self.e.sanitize() # In case we are aligned for a in torun: s = a[0] t = a[1] p = a[2] v = a[3] / dil[p] t.conc = None # Concentration of master mix is irrelevant now self.e.transfer(v, s, t) return [a[1] for a in torun]
def runDNase(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, hiTime=10, inPlace=False): return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, hiTemp=75, hiTime=hiTime, enzymes=[reagents.getsample("MDNase")], inPlace=inPlace)
def pgm(self): self.q = QSetup(self, maxdil=16, debug=False, mindilvol=100) self.e.addIdleProgram(self.q.idler) if self.doqpcr: self.q.addReferences(dstep=10, primers=self.qprimers, ref=reagents.getsample("BT5310")) print("### Barcoding #### (%.0f min)" % (clock.elapsed() / 60.0)) bcout = self.barcoding(names=[x['name'] for x in self.inputs], left=[x['left'] for x in self.inputs], right=[x['right'] for x in self.inputs]) for i in range(len(self.inputs)): x = self.inputs[i] if 'bconc' in x and x['bconc'] is not None: print("Resetting concentration of %s from expected %.1f to bconc setting of %.1f nM" % \ (x['name'], bcout[i].conc.stock, x['bconc'])) bcout[i].conc.stock = x['bconc'] print("### qPCR #### (%.0f min)" % (clock.elapsed() / 60.0)) self.q.run(confirm=False, enzName='EvaGreen') print("### qPCR Done #### (%.0f min)" % (clock.elapsed() / 60.0)) print("### Final PCR Done #### (%.0f min)" % (clock.elapsed() / 60.0)) worklist.flushQueue() if all(['bconc' in x and x['bconc'] is not None for x in self.inputs]): print("### Mixdown #### (%.0f min)" % (clock.elapsed() / 60.0)) worklist.flushQueue() worklist.comment('Start mixdown only at this point') self.e.sanitize(force=True) # mixdown = self.mix(bcout, [x['weight'] for x in self.inputs]) # Set default mix number to 1 for x in self.inputs: if 'mix' not in x: x['mix']=1 mixes=set([x['mix'] for x in self.inputs]) for m in mixes: sel=[ i for i in range(len(self.inputs)) if self.inputs[i]['mix']==m] print("sel=",sel) mixdown = self.mix([bcout[i] for i in sel], [self.inputs[i]['weight'] for i in sel],prefix="Mix%d_"%m) mixdown.name="Mix%d_Final"%m # self.q.addSamples(mixdown, needDil=mixdown.conc.stock * 1e-9 / self.qconc, primers=self.qprimers,nreplicates=3) else: print("### Not doing mixdown as bconc not set in all inputs")
def runT7Stop(self,theo,tgt,stopmaster=None,srcdil=2): [theo,tgt,stopmaster,srcdil]=listify([theo,tgt,stopmaster,srcdil]) if stopmaster is None: stopmaster=["MStpS_NT" if t==0 else "MStpS_WT" for t in theo] # Adjust source dilution for i in range(len(tgt)): tgt[i].conc=Concentration(srcdil[i],1) ## Stop sstopmaster=[reagents.getsample(s) for s in stopmaster] for i in range(len(tgt)): stopvol=tgt[i].volume/(sstopmaster[i].conc.dilutionneeded()-1) finalvol=tgt[i].volume+stopvol self.e.transfer(finalvol-tgt[i].volume,sstopmaster[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) return tgt
def runKlenow(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, hiTime=20, inPlace=False): assert (inPlace or vol is not None) return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, hiTemp=75, hiTime=hiTime, enzymes=[reagents.getsample("MKlenow")], inPlace=inPlace)
def runRTSetup(self, src, vol, srcdil, tgt=None, rtmaster=None): if rtmaster is None: rtmaster = reagents.getsample("MPosRT") if tgt is None: tgt = [ Sample(s.name + ".RT+", decklayout.SAMPLEPLATE) for s in src ] [src, tgt, vol, srcdil] = listify([src, tgt, vol, srcdil]) # Adjust source dilution for i in range(len(src)): src[i].conc = Concentration(srcdil[i], 1) self.e.stage('RTPos', [rtmaster], [src[i] for i in range(len(src))], [tgt[i] for i in range(len(tgt))], [vol[i] for i in range(len(vol))], destMix=False) #self.e.shakeSamples(tgt,returnPlate=True) return tgt
def runT7Stop(self, theo, tgt, stopmaster=None, srcdil=2): [theo, tgt, stopmaster, srcdil] = listify([theo, tgt, stopmaster, srcdil]) if stopmaster is None: stopmaster = ["MStpS_NT" if t == 0 else "MStpS_WT" for t in theo] # Adjust source dilution for i in range(len(tgt)): tgt[i].conc = Concentration(srcdil[i], 1) ## Stop sstopmaster = [reagents.getsample(s) for s in stopmaster] for i in range(len(tgt)): stopvol = tgt[i].volume / (sstopmaster[i].conc.dilutionneeded() - 1) finalvol = tgt[i].volume + stopvol self.e.transfer(finalvol - tgt[i].volume, sstopmaster[i], tgt[i]) self.e.shakeSamples(tgt, returnPlate=True) return tgt
def runRTSetup(self,src,vol,srcdil,tgt=None,rtmaster=None,stop=None): if rtmaster is None: rtmaster=reagents.getsample("MPosRT") if tgt is None: tgt=[Sample(s.name+".RT+",decklayout.SAMPLEPLATE) for s in src] [src,tgt,vol,srcdil,stop]=listify([src,tgt,vol,srcdil,stop]) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) stopvol=[ 0 if stop[i] is None else vol[i]/stop[i].conc.dilutionneeded() for i in range(len(vol))] assert(min(stopvol)==max(stopvol)) # Assume all stop volumes are the same self.e.stage('RTPos',[rtmaster],[src[i] for i in range(len(src)) ],[tgt[i] for i in range(len(tgt)) ],[vol[i]-stopvol[i] for i in range(len(vol))],destMix=False,finalx=vol[0]/(vol[0]-stopvol[0])) for i in range(len(tgt)): if stopvol[i]>0.1: self.e.transfer(stopvol[i],stop[i],tgt[i],(False,False)) #self.e.shakeSamples(tgt,returnPlate=True) return tgt
def pgm(self): q = QSetup(self,maxdil=self.maxdilstep,debug=False,mindilvol=60) self.e.addIdleProgram(q.idler) if self.barcoding: # Setup barcode primers for cleaved rounds only self.bcprimers=[["BC-%s-R%d_T7"%(inp['ligand'],r+1) for inp in self.inputs] if self.rounds[r]=='C' else None for r in range(len(self.rounds))] for bcp in self.bcprimers: if bcp is not None: for p in ["P-%s"%pp for pp in bcp]: if not reagents.isReagent(p): reagents.add(name=p,conc=4,extraVol=30,plate=decklayout.REAGENTPLATE,well="B2") s=reagents.getsample(p) # Force allocation of a well print("Adding %s to reagents at well %s"%(p,s.plate.wellname(s.well))) print("BC primers=", self.bcprimers) # Add any missing fields to inputs for i in range(len(self.inputs)): if 'ligand' not in self.inputs[i]: self.inputs[i]['ligand']=None if 'negligand' not in self.inputs[i]: self.inputs[i]['negligand']=None if 'round' not in self.inputs[i]: self.inputs[i]['round']=None if 'name' not in self.inputs[i]: if self.inputs[i]['ligand'] is None: self.inputs[i]['name']='%s_%d_R%d'%(self.inputs[i]['prefix'],self.inputs[i]['ID'],self.inputs[i]['round']) else: self.inputs[i]['name']='%s_%d_R%d_%s'%(self.inputs[i]['prefix'],self.inputs[i]['ID'],self.inputs[i]['round'],self.inputs[i]['ligand']) # Add templates if self.directT7: self.srcs = self.addTemplates([inp['name'] for inp in self.inputs],stockconc=self.tmplFinalConc/self.templateDilution,finalconc=self.tmplFinalConc,plate=decklayout.SAMPLEPLATE,looplengths=[inp['looplength'] for inp in self.inputs],initVol=self.t7vol[0]*self.templateDilution,extraVol=0) else: self.srcs = self.addTemplates([inp['name'] for inp in self.inputs],stockconc=self.tmplFinalConc/self.templateDilution,finalconc=self.tmplFinalConc,plate=decklayout.DILPLATE,looplengths=[inp['looplength'] for inp in self.inputs],extraVol=15) if self.dopcr: # Reserve space for PCR products pcrprods=[ [Sample("R%d-T%s"%(r,inp['ligand']),self.savePlate) for inp in self.inputs] for r in range(len(self.rounds))] else: pcrprods=None t7in = [s.getsample() for s in self.srcs] if "negative" in self.qpcrStages: q.addSamples(decklayout.SSDDIL,1,self.allprimers,save=False) # Negative controls if "reference" in self.qpcrStages: q.addReferences(dstep=10,nsteps=5,primers=["WX","MX","T7X"] if self.useMX else ["WX","T7X"],ref=reagents.getsample("BT5310"),nreplicates=1) # Save RT product from first (uncleaved) round and then use it during 2nd (cleaved) round for ligation and qPCR measurements self.rndNum=0 self.nextID=self.firstID curPrefix=[inp['prefix'] for inp in self.inputs] r1=t7in for roundType in self.rounds: # Run a single round of roundType with r1 as input # roundType is either "U" for uncleaved, or a new prefix for a cleaved round (with "T" being a T7 prepend) # Set r1 to new output at end if self.roundCallback is not None: self.roundCallback(self,self.rndNum,roundType) # Computed output prefix if roundType=='U': prefixOut=curPrefix stop=["Unclvd" for _ in curPrefix] else: if roundType=='T': stop=['T7%s'%p for p in curPrefix] prefixOut=curPrefix elif any([p==roundType for p in curPrefix]): logging.error( "Round %d is a cleaved round but goes to %s without changing prefix"%(self.rndNum, roundType)) assert False else: prefixOut=[roundType for _ in curPrefix] stop=prefixOut # May be explicitly overridden for i in range(len(self.inputs)): if 'stop' in self.inputs[i]: if isinstance(self.inputs[i]['stop'],list): assert(len(self.inputs[i]['stop'])==len(self.rounds)) t=self.inputs[i]['stop'][self.rndNum] else: t=self.inputs[i]['stop'] if (roundType=='U') != (t=='U'): print("Attempt to override round %d (type %s) with a input-specific round type of %s"%(self.rndNum, roundType, t)) assert False if roundType!='U': if t=='T': stop[i]='T7%s'%curPrefix[i] prefixOut[i]=curPrefix[i] else: stop[i]=t prefixOut[i]=t self.rndNum=self.rndNum+1 self.finalRound=self.rndNum==len(self.rounds) db.pushStatus("%s%d"%(roundType,self.rndNum)) [r1,bc1]=self.oneround(q,r1,prefixOut=prefixOut,stop=stop,prefixIn=curPrefix,keepCleaved=(roundType!='U'),rtvol=self.rtvol[self.rndNum-1],t7vol=self.t7vol[self.rndNum-1],cycles=self.pcrcycles[self.rndNum-1],pcrdil=self.pcrdil[self.rndNum-1],pcrvol=self.pcrvol[self.rndNum-1],dolig=self.allLig or (roundType!='U'),pcrtgt=None if pcrprods is None else pcrprods[self.rndNum-1]) db.popStatus() # Add TRefs specified in rnddefs if 'tref' in self.rnddef[self.rndNum-1]: tref=self.rnddef[self.rndNum-1]['tref'] assert len(tref)==len(r1) for i in range(len(r1)): if tref[i] is not None: trefname='TRef%d'%tref[i] print("Adding %s to %s"%(trefname,r1[i].name)) if not reagents.isReagent(trefname): reagents.add(name=trefname,conc=10,extraVol=30,well="E4") trefSamp=reagents.getsample(trefname) oldConc=r1[i].conc.stock oldUnits=r1[i].conc.units oldVol=r1[i].volume self.e.transfer(r1[i].volume/(trefSamp.conc.dilutionneeded()-1),trefSamp,r1[i],mix=(False,False)) # TODO: Check that these end up mixed r1[i].conc=Concentration(stock=oldConc*oldVol/r1[i].volume, units=oldUnits) # Treat TRef as straight dilution print("New conc=",r1[i].conc) for i in range(len(r1)): if self.inputs[i]['round'] is None: r1[i].name="%s_%d"%(prefixOut[i],self.nextID) else: r1[i].name="%d_%s_R%d%c"%(self.nextID,prefixOut[i],self.inputs[i]['round']+self.rndNum,roundType) if self.inputs[i]['ligand'] is not None: r1[i].name="%s_%s"%(r1[i].name,self.inputs[i]['ligand']) print("Used ID ", self.nextID," for ", r1[i].name,": ",r1[i]) self.nextID+=1 r1[i].conc.final=r1[i].conc.stock*self.templateDilution for i in range(len(bc1)): #print("Renaming",bc1[i].name) pts=bc1[i].name.split(".") bc1[i].name="%d_BC_R%d%c"%(self.nextID,self.inputs[i//2]['round']+self.rndNum,roundType) if self.inputs[i//2]['ligand'] is not None: bc1[i].name="%s_%s"%(bc1[i].name,self.inputs[i//2]['ligand']) bc1[i].name+="_"+pts[-2] print("Used ID ", self.nextID," for ", bc1[i].name,":",bc1[i]) self.nextID+=1 curPrefix=prefixOut if "finalpcr" in self.qpcrStages: for i in range(len(r1)): if self.singlePrefix: q.addSamples(src=r1[i],needDil=r1[i].conc.stock/self.qConc,primers=["T7X","MX"] if self.useMX else ["T7X"]) else: # noinspection PyUnboundLocalVariable q.addSamples(src=r1[i],needDil=r1[i].conc.stock/self.qConc,primers=["T7X",prefixOut[i]+"X"]+(["MX"] if self.useMX else [])) # Add TRefs if needed for i in range(len(r1)): if 'tref' in self.inputs[i]: trefname='TRef%d'%self.inputs[i]['tref'] if not reagents.isReagent(trefname): reagents.add(name=trefname,conc=10,extraVol=30) tref=reagents.getsample(trefname) self.e.transfer(r1[i].volume/(tref.conc.dilutionneeded()-1),tref,r1[i],mix=(False,False)) db.pushStatus('qPCR') print("######### qPCR ########### %.0f min"%(clock.elapsed()/60)) self.allprimers=q.allprimers() q.run(confirm=self.qpcrWait) db.popStatus()
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
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
def setVolumes(self): # Computed parameters # Observed data: 0.1nM@30min -> gain ~1000 self.rnaConc=8314.0*self.tmplFinalConc/(self.tmplFinalConc+55)*self.t7dur/30 if self.tmplFinalConc<1: self.rnaConc*=6 # Kludge based on being off at 0.1nM template concentrations self.rnaConc=max(40.0,self.rnaConc) # Another kludge if isinstance(self.stopConc,list): minStopConc=min(self.stopConc) else: minStopConc=self.stopConc maxConc=1000*minStopConc*4/0.9 if maxConc<self.rnaConc: logging.warning( "Stop@%.1f uM limits usable RNA to %.0f/%.0f nM"%(minStopConc,maxConc,self.rnaConc)) self.rnaConc=min(maxConc,self.rnaConc) stopConc=self.rnaConc*0.9 rtConc=stopConc/self.rtDil rtdilConc=[rtConc/self.rtpostdil[i] for i in range(len(self.rounds))] ligConc=[None if self.rounds[i]=='U' else rtdilConc[i]/1.25 for i in range(len(self.rounds))] ligdilConc=[None if self.rounds[i]=='U' else ligConc[i]/self.extpostdil[i] for i in range(len(self.rounds))] pcrConc=[rtConc/self.pcrdil[i] if self.rounds[i]=='U' else ligConc[i]/self.pcrdil[i] for i in range(len(self.rounds))] for i in range(len(self.rounds)): if ligConc[i] is None: print("R%d Concs(nM): RNA: %.0f, Stop: %.0f, RT: %.0f, RTDil: %.0f, PCRIn: %.0f"%(i, self.rnaConc, stopConc, rtConc, rtdilConc[i], pcrConc[i])) else: print("R%d Concs(nM): RNA: %.0f, Stop: %.0f, RT: %.0f, RTDil: %.0f, Lig: %.0f, LigDil: %.0f, PCRIn: %.0f"%(i, self.rnaConc, stopConc, rtConc, rtdilConc[i], ligConc[i], ligdilConc[i], pcrConc[i])) self.pcrvol=[self.pcrcopies*self.pmolesIn*1000/pcrConc[i]/math.pow(self.enrich,(i+1.0)) for i in range(len(self.rounds))] # Use at least 100ul so the evaporation of the saved sample that occurs during the run will be relatively small self.pcrvol=[max(100,v) for v in self.pcrvol] print("pcrvol=[%s]"%(",".join(["%.1f"%v for v in self.pcrvol]))) pcrExtra=[1.4*math.ceil(v*1.0/self.maxPCRVolume) for v in self.pcrvol] print("pcrExtra=[%s]"%(",".join(["%.1f"%v for v in pcrExtra]))) self.minligvol=[(self.pcrvol[i]*1.0+pcrExtra[i])/self.pcrdil[i]+((4.4 if self.saveDil is not None else 5.4 if 'ext' in self.qpcrStages else 0)+15.1)/self.extpostdil[i] for i in range(len(self.pcrvol))] print("minligvol=[%s]"%(",".join(["%.1f"%v for v in self.minligvol]))) # Compute RT volume self.rtvol=[ ((self.minligvol[i]/1.25+3.3)/self.rtpostdil[i]) if self.rounds[i]!='U' else (self.pcrvol[i]*1.0/self.pcrdil[i]+(pcrExtra[i]+15.1+3.3)/self.rtpostdil[i]) for i in range(len(self.rounds))] print("self.rtvol=",self.rtvol,", rtSave=",self.rtSave) if self.rtSave: self.rtvol=[max(15.0/self.rtpostdil[i],self.rtvol[i])+(self.rtSaveVol+1.4)/self.rtpostdil[i] for i in range(len(self.rtvol))] # Extra for saves elif "rt" in self.qpcrStages: # Take from save if rtSave is set self.rtvol=[max(15.0/self.rtpostdil[i],self.rtvol[i])+5.4/self.rtpostdil[i] for i in range(len(self.rtvol))] # Extra for qPCR self.rtvol=[max(v,8.0) for v in self.rtvol] # Minimum volume self.rtvol=[min(v,self.maxSampVolume) for v in self.rtvol] # Maximum volume # print ("self.rtvol=",self.rtvol) self.t7extravols=((4+1.4) if 'stopped' in self.qpcrStages else 0)+ ((self.saveRNAVolume+1.4) if self.saveRNA else 0) # + 3.3 # 3.3 in case pipette mixing used #print "self.t7extravols=%.1f ul\n"%self.t7extravols #print "self.rtvol=%s ul\n"%(",".join(["%.1f "%x for x in self.rtvol])) # Compute dilutions due to tref additions trefdil=[1 for _ in self.rnddef ] for i in range(len(self.rnddef)-1): rd=self.rnddef[i] if 'tref' in rd: tref = rd['tref'][0] if tref is not None: trefname = 'TRef%d' % tref if not reagents.isReagent(trefname): reagents.add(name=trefname, conc=10, extraVol=30, well="E4") trefs = reagents.getsample(trefname) trefdil[i+1]=(trefs.conc.dilutionneeded())/(trefs.conc.dilutionneeded()-1) print("Extra dilution due to tref additions: ",trefdil) self.t7vol=[max((15.1+self.rtvol[i]/4.0+1.4)+self.t7extravols,self.pmolesIn*1000.0/(self.tmplFinalConc if i==0 else 200*self.templateDilution)*trefdil[i]/math.pow(self.enrich,i*1.0)) for i in range(len(self.rounds))] print("self.t7vol=%s ul\n"%(",".join(["%.1f "%x for x in self.t7vol]))) #self.t7vol=[max(18.0,v) for v in self.t7vol] # Make sure that there's enough to add at least 2ul of stop if 'template' in self.qpcrStages: self.t7vol[0]+=5.4 self.t7vol=[min(self.maxSampVolume,v) for v in self.t7vol] # Make sure no tubes overflow
def runPCR(self,prefix,src,vol,srcdil,tgt=None,ncycles=20,suffix='S',sepPrimers=True,primerDil=4): ## PCR [prefix,src,tgt,vol,srcdil,suffix]=listify([prefix,src,tgt,vol,srcdil,suffix]) for i in range(len(tgt)): if tgt[i] is None: tgt[i]=Sample("%s.P%s%s"%(src[i].name,prefix[i],suffix[i]),src[i].plate) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) if sepPrimers: sampvols=[vol[i]/srcdil[i] for i in range(len(src))] mm=reagents.getsample("MPCR") mmvols=[vol[i]/mm.conc.dilutionneeded() for i in range(len(src))] for s in prefix + suffix: if not reagents.isReagent(s): reagents.add(name=s,conc=primerDil,extraVol=30) sprefix=[reagents.getsample(p) for p in prefix] ssuffix=[reagents.getsample(p) for p in suffix] prefixvols=[vol[i]/sprefix[i].conc.dilutionneeded() for i in range(len(src))] suffixvols=[vol[i]/ssuffix[i].conc.dilutionneeded() for i in range(len(src))] watervols=[vol[i]-mmvols[i]-prefixvols[i]-suffixvols[i]-sampvols[i] for i in range(len(src))] print "water=",watervols,", mm=",mmvols,", prefix=",prefixvols,", suffix=",suffixvols,", samp=",sampvols self.e.multitransfer(watervols,decklayout.WATER,tgt,(False,False)) # Transfer water self.e.multitransfer(mmvols,mm,tgt,(False,False)) # PCR master mix sprefixset=set(sprefix) ssuffixset=set(ssuffix) if len(sprefixset)<len(ssuffixset): # Distribute sprefix first for p in sprefixset: self.e.multitransfer([prefixvols[i] for i in range(len(src)) if sprefix[i]==p],p,[tgt[i] for i in range(len(src)) if sprefix[i]==p],(False,False)) # Then individually add ssuffix for i in range(len(src)): self.e.transfer(suffixvols[i],ssuffix[i],tgt[i],(False,False)) else: # Distribute ssuffix first for p in ssuffixset: self.e.multitransfer([suffixvols[i] for i in range(len(src)) if ssuffix[i]==p],p,[tgt[i] for i in range(len(src)) if ssuffix[i]==p],(False,False)) # Then individually add sprefix for i in range(len(src)): self.e.transfer(prefixvols[i],sprefix[i],tgt[i],(False,False)) # Now add templates for i in range(len(src)): self.e.transfer(sampvols[i],src[i],tgt[i],(False,False)) else: primer=[prefix[i]+suffix[i] for i in range(len(prefix))] print "primer=",primer for up in set(primer): s="MPCR%s"%up if not reagents.isReagent(s): reagents.add(name=s,conc=4/3.0,extraVol=30) self.e.stage('PCR%s'%up,[reagents.getsample("MPCR%s"%up)],[src[i] for i in range(len(src)) if primer[i]==up],[tgt[i] for i in range(len(tgt)) if primer[i]==up],[vol[i] for i in range(len(vol)) if primer[i]==up],destMix=False) pgm="PCR%d"%ncycles self.e.shakeSamples(tgt,returnPlate=False) # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@57,10 GOTO@2,%d TEMP@72,120 TEMP@25,2'%(pgm,ncycles-1)) self.e.runpgm(pgm,4.80+1.55*ncycles,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100) return tgt
def runKlenow(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=20,inPlace=False): assert(inPlace or vol is not None) return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=75,hiTime=hiTime,enzymes=[reagents.getsample("MKlenow")],inPlace=inPlace)
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
def runPCR(self, prefix, src, vol, srcdil, tgt=None, ncycles=20, suffix='S', sepPrimers=True, primerDil=4): ## PCR [prefix, src, tgt, vol, srcdil, suffix] = listify([prefix, src, tgt, vol, srcdil, suffix]) for i in range(len(tgt)): if tgt[i] is None: tgt[i] = Sample( "%s.P%s%s" % (src[i].name, prefix[i], suffix[i]), src[i].plate) # Adjust source dilution for i in range(len(src)): src[i].conc = Concentration(srcdil[i], 1) if sepPrimers: sampvols = [vol[i] / srcdil[i] for i in range(len(src))] mm = reagents.getsample("MPCR") mmvols = [ vol[i] / mm.conc.dilutionneeded() for i in range(len(src)) ] for s in prefix + suffix: if not reagents.isReagent(s): reagents.add(name=s, conc=primerDil, extraVol=30) sprefix = [reagents.getsample(p) for p in prefix] ssuffix = [reagents.getsample(p) for p in suffix] prefixvols = [ vol[i] / sprefix[i].conc.dilutionneeded() for i in range(len(src)) ] suffixvols = [ vol[i] / ssuffix[i].conc.dilutionneeded() for i in range(len(src)) ] watervols = [ vol[i] - mmvols[i] - prefixvols[i] - suffixvols[i] - sampvols[i] for i in range(len(src)) ] print "water=", watervols, ", mm=", mmvols, ", prefix=", prefixvols, ", suffix=", suffixvols, ", samp=", sampvols self.e.multitransfer(watervols, decklayout.WATER, tgt, (False, False)) # Transfer water self.e.multitransfer(mmvols, mm, tgt, (False, False)) # PCR master mix sprefixset = set(sprefix) ssuffixset = set(ssuffix) if len(sprefixset) < len(ssuffixset): # Distribute sprefix first for p in sprefixset: self.e.multitransfer([ prefixvols[i] for i in range(len(src)) if sprefix[i] == p ], p, [tgt[i] for i in range(len(src)) if sprefix[i] == p], (False, False)) # Then individually add ssuffix for i in range(len(src)): self.e.transfer(suffixvols[i], ssuffix[i], tgt[i], (False, False)) else: # Distribute ssuffix first for p in ssuffixset: self.e.multitransfer([ suffixvols[i] for i in range(len(src)) if ssuffix[i] == p ], p, [tgt[i] for i in range(len(src)) if ssuffix[i] == p], (False, False)) # Then individually add sprefix for i in range(len(src)): self.e.transfer(prefixvols[i], sprefix[i], tgt[i], (False, False)) # Now add templates for i in range(len(src)): self.e.transfer(sampvols[i], src[i], tgt[i], (False, False)) else: primer = [prefix[i] + suffix[i] for i in range(len(prefix))] print "primer=", primer for up in set(primer): s = "MPCR%s" % up if not reagents.isReagent(s): reagents.add(name=s, conc=4 / 3.0, extraVol=30) self.e.stage( 'PCR%s' % up, [reagents.getsample("MPCR%s" % up)], [src[i] for i in range(len(src)) if primer[i] == up], [tgt[i] for i in range(len(tgt)) if primer[i] == up], [vol[i] for i in range(len(vol)) if primer[i] == up], destMix=False) pgm = "PCR%d" % ncycles self.e.shakeSamples(tgt, returnPlate=False) # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun( 'PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@57,10 GOTO@2,%d TEMP@72,120 TEMP@25,2' % (pgm, ncycles - 1)) self.e.runpgm(pgm, 4.80 + 1.55 * ncycles, False, max(vol), hotlidmode="CONSTANT", hotlidtemp=100) return tgt
def runUser(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,enzymes=[reagents.getsample("MUser")],inPlace=inPlace)
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()
def runDNase(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=10,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=75,hiTime=hiTime,enzymes=[reagents.getsample("MDNase")],inPlace=inPlace)
def pgm(self): q = QSetup(self, maxdil=self.maxdilstep, debug=False, mindilvol=60) self.e.addIdleProgram(q.idler) if self.barcoding: # Setup barcode primers for cleaved rounds only self.bcprimers = [[ "BC-%s-R%d_T7" % (inp['ligand'], r + 1) for inp in self.inputs ] if self.rounds[r] == 'C' else None for r in range(len(self.rounds))] for bcp in self.bcprimers: if bcp is not None: for p in ["P-%s" % pp for pp in bcp]: if not reagents.isReagent(p): reagents.add(name=p, conc=4, extraVol=30, plate=decklayout.REAGENTPLATE, well="B2") s = reagents.getsample(p) # Force allocation of a well print "Adding %s to reagents at well %s" % ( p, s.plate.wellname(s.well)) print "BC primers=", self.bcprimers # Add any missing fields to inputs for i in range(len(self.inputs)): if 'ligand' not in self.inputs[i]: self.inputs[i]['ligand'] = None if 'round' not in self.inputs[i]: self.inputs[i]['round'] = None if 'name' not in self.inputs[i]: if self.inputs[i]['ligand'] is None: self.inputs[i]['name'] = '%s_%d_R%d' % ( self.inputs[i]['prefix'], self.inputs[i]['ID'], self.inputs[i]['round']) else: self.inputs[i]['name'] = '%s_%d_R%d_%s' % ( self.inputs[i]['prefix'], self.inputs[i]['ID'], self.inputs[i]['round'], self.inputs[i]['ligand']) # Add templates if self.directT7: self.srcs = self.addTemplates( [inp['name'] for inp in self.inputs], stockconc=self.tmplFinalConc / self.templateDilution, finalconc=self.tmplFinalConc, plate=decklayout.SAMPLEPLATE, looplengths=[inp['looplength'] for inp in self.inputs], initVol=self.t7vol[0] * self.templateDilution, extraVol=0) else: self.srcs = self.addTemplates( [inp['name'] for inp in self.inputs], stockconc=self.tmplFinalConc / self.templateDilution, finalconc=self.tmplFinalConc, plate=decklayout.DILPLATE, looplengths=[inp['looplength'] for inp in self.inputs], extraVol=15) t7in = [s.getsample() for s in self.srcs] if "negative" in self.qpcrStages: q.addSamples(decklayout.SSDDIL, 1, self.allprimers, save=False) # Negative controls if "reference" in self.qpcrStages: q.addReferences(dstep=10, nsteps=5, primers=["T7WX", "MX", "T7X"], ref=reagents.getsample("BT5310"), nreplicates=1) q.addReferences(dstep=10, nsteps=5, primers=["T7WX", "MX", "T7X"], ref=reagents.getsample("BT5310"), nreplicates=1) # Save RT product from first (uncleaved) round and then use it during 2nd (cleaved) round for ligation and qPCR measurements self.rndNum = 0 self.nextID = self.firstID curPrefix = [inp['prefix'] for inp in self.inputs] r1 = t7in for roundType in self.rounds: # Run a single round of roundType with r1 as input # roundType is either "U" for uncleaved, or a new prefix for a cleaved round (with "T" being a T7 prepend) # Set r1 to new output at end # Computed output prefix if roundType == 'U': prefixOut = curPrefix stop = ["Unclvd" for p in curPrefix] else: if roundType == 'T': stop = ['T7%s' % p for p in curPrefix] prefixOut = curPrefix elif any([p == roundType for p in curPrefix]): logging.error( "Round %d is a cleaved round but goes to %s without changing prefix" % (self.rndNum, roundType)) assert (False) else: prefixOut = [roundType for p in curPrefix] stop = prefixOut # May be explicitly overridden for i in range(len(self.inputs)): if 'stop' in self.inputs[i]: if isinstance(self.inputs[i]['stop'], list): assert (len(self.inputs[i]['stop']) == len( self.rounds)) t = self.inputs[i]['stop'][self.rndNum] else: t = self.inputs[i]['stop'] if (roundType == 'U') != (t == 'U'): print "Attempt to override round %d (type %s) with a input-specific round type of %s" % ( self.rndNum, roundType, t) assert (False) if roundType != 'U': if t == 'T': stop[i] = 'T7%s' % curPrefix[i] prefixOut[i] = curPrefix[i] else: stop[i] = t prefixOut[i] = t self.rndNum = self.rndNum + 1 self.finalRound = self.rndNum == len(self.rounds) r1 = self.oneround(q, r1, prefixOut=prefixOut, stop=stop, prefixIn=curPrefix, keepCleaved=(roundType != 'U'), rtvol=self.rtvol[self.rndNum - 1], t7vol=self.t7vol[self.rndNum - 1], cycles=self.pcrcycles[self.rndNum - 1], pcrdil=self.pcrdil[self.rndNum - 1], pcrvol=self.pcrvol[self.rndNum - 1], dolig=self.allLig or (roundType != 'U')) for i in range(len(r1)): r1[i].name = "%s_%d" % (prefixOut[i], self.nextID) if self.inputs[i]['round'] is not None: r1[i].name = "%s_R%d%c" % (r1[i].name, self.inputs[i]['round'] + self.rndNum, roundType) if self.inputs[i]['ligand'] is not None: r1[i].name = "%s_%s" % (r1[i].name, self.inputs[i]['ligand']) print "Used ID ", self.nextID, " for ", r1[i].name, ": ", r1[i] self.nextID += 1 r1[i].conc.final = r1[i].conc.stock * self.templateDilution curPrefix = prefixOut if "finalpcr" in self.qpcrStages: for i in range(len(r1)): if self.singlePrefix: q.addSamples(src=r1[i], needDil=r1[i].conc.stock / self.qConc, primers=["T7X", "MX"]) else: q.addSamples(src=r1[i], needDil=r1[i].conc.stock / self.qConc, primers=["T7X", prefixOut[i] + "X", "MX"]) print "######### qPCR ########### %.0f min" % (clock.elapsed() / 60) self.allprimers = q.allprimers() q.run(confirm=self.qpcrWait)
def barcoding(self, names, left, right): """Perform barcoding of the given inputs; rsrsc,left,right should all be equal length""" pcrcycles = [5, 10] pcr1inputdil = 10 pcr1vol = 30 pcr1postdil = 100.0 / pcr1vol pcr2dil = 10*pcr1postdil pcr2vol = 40.0 samps = [reagents.getsample(s) for s in names] print("Inputs:") for i in range(len(samps)): print("%2s %-10s %8s-%-8s %s" % ( samps[i].plate.wellname(samps[i].well), self.inputs[i]['name'], left[i], right[i], str(samps[i].conc))) 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 for s in samps: # Dilute down to desired conc dil = s.conc.stock / self.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 > 150.0: maxdil = 150.0 / s.volume logging.info( "Dilution of input %s (%.1f ul) by %.2f would require %.1f ul -- only diluting by %.1fx" % ( s.name, s.volume, dil, dilvol, maxdil)) dil = maxdil self.diluteInPlace(tgt=[s], dil=dil) print("Diluting %s by %.1f" % (s.name, dil)) print("### PCR1 #### (%.0f min)" % (clock.elapsed() / 60.0)) pcr1 = self.runPCR(src=samps, srcdil=[s.conc.stock / self.pcr1inputconc for s in samps], ncycles=pcrcycles[0], vol=pcr1vol, primers=[[left[i], right[i]] for i in range(len(left))], usertime=30, fastCycling=False, inPlace=False, master="MPCR1", kapa=False, annealTemp=57) pcr1finalconc = self.pcr1inputconc * 2 ** pcrcycles[0] print("PCR1 output concentration = %.1f 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') if len(pcrcycles) > 1: # Second PCR with 235p/236p on mixture (use at least 4ul of prior) print("### PCR2 #### (%.0f min)" % (clock.elapsed() / 60.0)) pcr2 = self.runPCR(src=pcr1, srcdil=pcr2dil / pcr1postdil, vol=pcr2vol, ncycles=pcrcycles[1], primers=None, fastCycling=False, master="MPCR2", kapa=True, annealTemp=64) pcr2finalconc = pcr1finalconc / (pcr2dil / pcr1postdil) * 2 ** pcrcycles[1] print("PCR2 final conc = %.1f nM" % pcr2finalconc) if pcr2finalconc > 200: print("Capping at 200nM") pcr2finalconc = 200 for x in pcr2: x.conc = Concentration(stock=pcr2finalconc, units='nM') if self.doqpcr: self.q.addSamples(src=pcr2, needDil=pcr2finalconc * 1e-9 / self.qconc, primers=self.qprimers) res = pcr2 else: self.q.addSamples(src=pcr1, needDil=pcr1finalconc / (self.qconc * 1e9), primers=self.qprimers, save=True, nreplicates=1) res = pcr1 return res
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, []
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)
def runLig(self, prefix=None, src=None, vol=None, srcdil=None, tgt=None, master=None, anneal=True, ligtemp=25): if master is None: master = [ reagents.getsample("MLigAN7") if p == 'A' else reagents.getsample("MLigBN7") for p in prefix ] #Extension [src, tgt, vol, srcdil, master] = listify([src, tgt, vol, srcdil, master]) if tgt is None: tgt = [ Sample("%s.%s" % (src[i].name, master[i].name), decklayout.SAMPLEPLATE) for i in range(len(src)) ] # Need to check since an unused ligation master mix will not have a concentration minsrcdil = 1 / (1 - 1 / master[0].conc.dilutionneeded() - 1 / reagents.getsample("MLigase").conc.dilutionneeded()) for i in srcdil: if i < minsrcdil: print "runLig: srcdil=%.2f, but must be at least %.2f based on concentrations of master mixes" % ( i, minsrcdil) assert (False) # Adjust source dilution for i in range(len(src)): src[i].conc = Concentration(srcdil[i], 1) i = 0 while i < len(tgt): lasti = i + 1 while lasti < len(tgt) and master[i] == master[lasti]: lasti = lasti + 1 self.e.stage('LigAnneal', [master[i]], src[i:lasti], tgt[i:lasti], [vol[j] / 1.5 for j in range(i, lasti)], 1.5, destMix=False) i = lasti if anneal: self.e.shakeSamples(tgt, returnPlate=False) self.e.runpgm("TRPANN", 5, False, max(vol), hotlidmode="CONSTANT", hotlidtemp=100) self.e.stage('Ligation', [reagents.getsample("MLigase")], [], tgt, vol, destMix=False) self.e.shakeSamples(tgt, returnPlate=False) self.runLigPgm(max(vol), ligtemp) return tgt