def finish(self): self.e.lihahome() worklist.userprompt("Process complete. Continue to turn off reagent cooler") self.e.setreagenttemp(None) #Sample.printallsamples("At completion") hasError=False for s in Sample.getAllOnPlate(): if s.volume<1.0 and s.conc is not None and not s.hasBeads: print "ERROR: Insufficient volume for ", s," need at least ",1.0-s.volume," ul additional" #hasError=True elif s.volume<2.5 and s.conc is not None: print "WARNING: Low final volume for ", s elif s.volume>s.plate.maxVolume: print "ERROR: Excess final volume (",s.volume,") for ",s,", maximum is ",s.plate.maxVolume hasError=True if hasError: print "NO OUTPUT DUE TO ERRORS" assert(False) print "Wells used: samples: %d, dilutions: %d, qPCR: %d"%(Sample.numSamplesOnPlate(decklayout.SAMPLEPLATE),Sample.numSamplesOnPlate(decklayout.DILPLATE),Sample.numSamplesOnPlate(decklayout.QPCRPLATE)) # Save worklist to a file #e.saveworklist("trp1.gwl") (scriptname,ext)=os.path.splitext(sys.argv[0]) self.e.savegem(scriptname+".gem") self.e.savesummary(scriptname+".txt") Sample.savematlab(scriptname+".m")
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 run(self,confirm=False,enzName="EvaUSER",waitForPTC=True): """Run the dilutions and QPCR setup""" # Setup qPCRs #self.jobq.dump() self.idler(100000) if waitForPTC: self.trp.e.waitpgm() # May still need to wait for TC to complete before able to do final jobs self.idler(100000) worklist.flushQueue() if self.jobq.len()>0: logging.error( "Blocked jobs remain on queue:") self.jobq.dump() assert False if len(self.dilProds)==0: return if confirm: worklist.userprompt('Continue to setup qPCR') worklist.comment('Starting qPCR setup') self.trp.e.sanitize(force=True) if all([allp in p for allp in self.allprimers() for p in self.primers]): print("All samples use same qPCR primers") # This allows the Eva to be distributed all at once self.trp.runQPCR(src=self.dilProds,vol=self.volume,primers=self.allprimers(),nreplicates=self.nreplicates,enzName=enzName) else: for p in self.allprimers(): # Build list of relevant entries ind=[ i for i in range(len(self.dilProds)) if p in self.primers[i]] self.trp.runQPCR(src=[self.dilProds[i] for i in ind],vol=self.volume,primers=[p],nreplicates=[self.nreplicates[i] for i in ind],enzName=enzName)
def finish(self): self.e.lihahome() worklist.userprompt("Process complete. Continue to turn off reagent cooler") self.e.setreagenttemp(None) #Sample.printallsamples("At completion") hasError=False for s in Sample.getAllOnPlate(): if s.volume<1.0 and s.conc is not None and not s.emptied: logging.error("Insufficient volume for %s: need at least %.1f ul additional"%(s.name,1.0-s.volume),fatal=False) #hasError=True elif s.volume<2.5 and s.conc is not None and not s.emptied: logging.warning("Low final volume for "+ s.name) elif s.volume>s.plate.maxVolume: logging.erorr("Excess final volume (%.1f) for %s: maximum is %.1f ul"%(s.volume,s.name,s.plate.maxVolume),fatal=False) hasError=True if hasError: logging.error("NO OUTPUT DUE TO ERRORS") print "Wells used: samples: %d, dilutions: %d, qPCR: %d"%(Sample.numSamplesOnPlate(decklayout.SAMPLEPLATE),Sample.numSamplesOnPlate(decklayout.DILPLATE),Sample.numSamplesOnPlate(decklayout.QPCRPLATE)) # Save worklist to a file #e.saveworklist("trp1.gwl") (scriptname,ext)=os.path.splitext(sys.argv[0]) self.e.savegem(scriptname+".gem") self.e.savesummary(scriptname+".txt") Sample.savematlab(scriptname+".m")
def finish(self): self.e.lihahome() worklist.userprompt( "Process complete. Continue to turn off reagent cooler") self.e.setreagenttemp(None) #Sample.printallsamples("At completion") hasError = False for s in Sample.getAllOnPlate(): if s.volume < 1.0 and s.conc is not None and not s.hasBeads: print "ERROR: Insufficient volume for ", s, " need at least ", 1.0 - s.volume, " ul additional" #hasError=True elif s.volume < 2.5 and s.conc is not None: print "WARNING: Low final volume for ", s elif s.volume > s.plate.maxVolume: print "ERROR: Excess final volume (", s.volume, ") for ", s, ", maximum is ", s.plate.maxVolume hasError = True if hasError: print "NO OUTPUT DUE TO ERRORS" assert (False) print "Wells used: samples: %d, dilutions: %d, qPCR: %d" % ( Sample.numSamplesOnPlate(decklayout.SAMPLEPLATE), Sample.numSamplesOnPlate(decklayout.DILPLATE), Sample.numSamplesOnPlate(decklayout.QPCRPLATE)) # Save worklist to a file #e.saveworklist("trp1.gwl") (scriptname, ext) = os.path.splitext(sys.argv[0]) self.e.savegem(scriptname + ".gem") self.e.savesummary(scriptname + ".txt") Sample.savematlab(scriptname + ".m")
def pgm(self): q = QSetup(self,maxdil=16,debug=False,mindilvol=60) self.e.addIdleProgram(q.idler) t7in = [s.getsample() for s in self.srcs] if "negative" in self.qpcrStages: 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 self.rndNum=0 self.nextID=self.firstID curPrefix=[inp['prefix'] for inp in self.inputs] while self.rndNum<self.nrounds: self.rndNum=self.rndNum+1 prefixOut=["A" if p=="W" else "B" if p=="A" else "W" if p=="B" else "BADPREFIX" for p in curPrefix] if self.rndNum==1: self.t7vol1=self.t7vol1a else: self.t7vol1=max(20,self.pmolesIn*1000/min([inp.conc.final for inp in t7in])) # New input volueme r1=self.oneround(q,t7in,prefixOut,prefixIn=curPrefix,keepCleaved=False,rtvol=self.rtvol1,t7vol=self.t7vol1,cycles=self.pcrcycles1,pcrdil=self.pcrdil1,pcrvol=self.pcrvol1,dolig=self.allLig) # pcrvol is set to have same diversity as input for i in range(len(r1)): r1[i].name="%s_%d_R%dU_%s"%(curPrefix[i],self.nextID,self.inputs[i]['round']+self.rndNum,self.inputs[i]['ligand']) self.nextID+=1 r1[i].conc.final=r1[i].conc.stock*self.templateDilution if self.rndNum>=self.nrounds: logging.warning("Warning: ending on an uncleaved round") break self.rndNum=self.rndNum+1 print "prefixIn=",curPrefix print "prefixOut=",prefixOut self.t7vol2=max(20,self.pmolesIn*1000/min([inp.conc.final for inp in r1])) r2=self.oneround(q,r1,prefixOut,prefixIn=curPrefix,keepCleaved=True,rtvol=self.rtvol2,t7vol=self.t7vol2,cycles=self.pcrcycles2,pcrdil=self.pcrdil2,pcrvol=self.pcrvol2,dolig=True) # pcrvol is set to have same diversity as input = (self.t7vol2*self.templateDilution/rnagain*stopdil*rtdil*extdil*exodil*pcrdil) for i in range(len(self.inputs)): r2[i].name="%s_%d_R%dC_%s"%(prefixOut[i],self.nextID,self.inputs[i]['round']+self.rndNum,self.inputs[i]['ligand']) self.nextID+=1 r2[i].conc.final=r2[i].conc.stock*self.templateDilution t7in=r2 curPrefix=prefixOut if "finalpcr" in self.qpcrStages: for i in range(len(r2)): q.addSamples(src=r2[i],needDil=r2[i].conc.stock/self.qConc,primers=["T7X","T7"+prefixOut[i]+"X"]) print "######### qPCR ###########" #q.addReferences(mindil=4,nsteps=6,primers=["T7X","MX","T7AX"]) if self.qpcrWait: worklist.userprompt('Continue to setup qPCR') q.run()
def run(self): 'Run the dilutions and QPCR setup' # Setup qPCRs #self.jobq.dump() self.idler(100000) self.trp.e.waitpgm() # May still need to wait for PTC to complete before able to do final jobs self.idler(100000) if self.jobq.len()>0: print "Blocked jobs remain on queue:" self.jobq.dump() assert False worklist.userprompt('Starting qPCR setup',timeout=5) for p in self.allprimers(): # Build list of relevant entries ind=[ i for i in range(len(self.dilProds)) if p in self.primers[i]] self.trp.runQPCR(src=[self.dilProds[i] for i in ind],vol=self.volume,srcdil=10.0/4,primers=[p],nreplicates=[self.nreplicates[i] for i in ind])
def run(self,confirm=False,enzName="EvaUSER"): 'Run the dilutions and QPCR setup' # Setup qPCRs #self.jobq.dump() self.idler(100000) self.trp.e.waitpgm() # May still need to wait for PTC to complete before able to do final jobs self.idler(100000) worklist.flushQueue() if self.jobq.len()>0: logging.error( "Blocked jobs remain on queue:",fatal=False) self.jobq.dump() assert False if confirm: worklist.userprompt('Continue to setup qPCR') worklist.comment('Starting qPCR setup') self.trp.e.sanitize(force=True) for p in self.allprimers(): # Build list of relevant entries ind=[ i for i in range(len(self.dilProds)) if p in self.primers[i]] self.trp.runQPCR(src=[self.dilProds[i] for i in ind],vol=self.volume,primers=[p],nreplicates=[self.nreplicates[i] for i in ind],enzName=enzName)
def run(self): 'Run the dilutions and QPCR setup' # Setup qPCRs #self.jobq.dump() self.idler(100000) self.trp.e.waitpgm( ) # May still need to wait for PTC to complete before able to do final jobs self.idler(100000) if self.jobq.len() > 0: print "Blocked jobs remain on queue:" self.jobq.dump() assert False worklist.userprompt('Starting qPCR setup', timeout=5) for p in self.allprimers(): # Build list of relevant entries ind = [ i for i in range(len(self.dilProds)) if p in self.primers[i] ] self.trp.runQPCR(src=[self.dilProds[i] for i in ind], vol=self.volume, srcdil=10.0 / 4, primers=[p], nreplicates=[self.nreplicates[i] for i in ind])
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, []