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