def saveSamps(self, src, vol, dil, tgt=None, dilutant=None, plate=None, mix=(True, False)): [src, vol, dil] = listify([src, vol, dil]) if plate is None: plate = decklayout.REAGENTPLATE if tgt is None: tgt = [ Sample(diluteName(src[i].name, dil[i]), plate) for i in range(len(src)) ] if any([d != 1.0 for d in dil]): if dilutant is None: dilutant = decklayout.WATER self.e.multitransfer( [vol[i] * (dil[i] - 1) for i in range(len(vol))], dilutant, tgt, (False, False)) self.e.shakeSamples(src, returnPlate=True) for i in range(len(src)): self.e.transfer(vol[i], src[i], tgt[i], mix) tgt[i].conc = Concentration(1.0 / dil[i]) return tgt
def runIncubation(self, src=None, vol=None, srcdil=None, tgt=None, enzymes=None, incTemp=37, incTime=15, hiTemp=None, hiTime=0, inPlace=False): if len(enzymes) != 1: print "ERROR: runIncubation only supports a single master mix" assert False if inPlace: if tgt is not None: print "ERROR: tgt specified for in-place incubation" assert False elif tgt is None: tgt = [ Sample("%s.%s" % (src[i].name, enzymes[0].name), decklayout.SAMPLEPLATE) for i in range(len(src)) ] if srcdil == None: # Minimum dilution (no water) srcdil = 1 / (1 - sum([1 / e.conc.dilutionneeded() for e in enzymes])) if vol is None and inPlace: vol = [s.volume * srcdil 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) if inPlace: self.runRxInPlace(src, vol, enzymes[0], returnPlate=False) tgt = src else: self.e.stage('User', enzymes, src, tgt, vol, destMix=False) self.e.shakeSamples(tgt, returnPlate=False) if hiTemp is None: worklist.pyrun('PTC\\ptcsetpgm.py INC TEMP@%.0f,%.0f TEMP@25,30' % (incTemp, incTime * 60)) else: assert (hiTime > 0) worklist.pyrun( 'PTC\\ptcsetpgm.py INC TEMP@%.0f,%.0f TEMP@%.0f,%.0f TEMP@25,30' % (incTemp, incTime * 60, hiTemp, hiTime * 60)) self.e.runpgm("INC", incTime + hiTime + 2, False, max(vol), hotlidmode="TRACKING", hotlidtemp=10) return tgt
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 addTemplates(self, names, stockconc, finalconc=None, units="nM", plate=decklayout.EPPENDORFS): 'Add templates as "reagents", return the list of them' if finalconc is None: print "WARNING: final concentration of template not specified, assuming 0.6x (should add to addTemplates() call" [names, stockconc] = listify([names, stockconc]) finalconc = [0.6 * x for x in stockconc] else: [names, stockconc, finalconc] = listify([names, stockconc, finalconc]) r = [] for i in range(len(names)): r.append( reagents.add(names[i], plate=plate, conc=Concentration(stockconc[i], finalconc[i], units), extraVol=30)) return r
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 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
# Generic selection progam import debughook import math from Experiment.concentration import Concentration from Experiment.sample import Sample from Experiment import worklist, reagents, decklayout, logging, clock from TRPLib.TRP import TRP from TRPLib.QSetup import QSetup from pcrgain import pcrgain reagents.add("BT5310", well="B5", conc=Concentration(20, 20, "pM")) class PGMSelect(TRP): '''Selection experiment''' def __init__(self, inputs, rounds, firstID, pmolesIn, directT7=True, templateDilution=0.3, tmplFinalConc=50, saveDil=24, qpcrWait=False, allLig=False, qpcrStages=["negative", "template", "ext", "finalpcr"], finalPlus=True, t7dur=30, usertime=10,
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 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
reagents.add("MStpX", well="C2", conc=2) reagents.add("MStopXSelfExtendB", well="C2", conc=5) reagents.add("MQREF", well="D2", conc=10.0 / 6) reagents.add("MQAX", well="E2", conc=10.0 / 6) reagents.add("MQBX", well="A3", conc=10.0 / 6) reagents.add("MPCRAX", well="B3", conc=4.0 / 3) reagents.add("MPCRBX", well="C3", conc=4.0 / 3) reagents.add("MQMX", well="D3", conc=10.0 / 6) reagents.add("MQWX", well="E3", conc=10.0 / 6) reagents.add("SSD", well="A4", conc=10.0) reagents.add("MLigAT7W", well="B4", conc=3) reagents.add("BeadBuffer", well="C4", conc=1) reagents.add("Dynabeads", well="D4", conc=2, hasBeads=True) reagents.add("MQT7X", well="E4", conc=15.0 / 9) reagents.add("MStpBeads", well="A5", conc=3.7) reagents.add("QPCRREF", well="B5", conc=Concentration(50, 50, 'pM')) reagents.add("MPCRT7X", well="C5", conc=4.0 / 3) reagents.add("NaOH", well="D5", conc=1.0) reagents.add("TE8", well="E5", conc=None) reagents.add("MLigBT7WBio", well=None, conc=3) reagents.add("MLigBT7Bio", well=None, conc=3) reagents.add("MLigBT7", well=None, conc=3) reagents.add("MPCR", well=None, conc=4) reagents.add("MLigB", well=None, conc=3) reagents.add("MNegRT", well=None, conc=2) reagents.add("MLigAT7", well=None, conc=3) # Conc is relative to annealing time (not to post-ligase) reagents.add("Theo", well=None, conc=Concentration(25, 7.5, 'mM'))