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 addTemplates(self,names,stockconc,finalconc=None,units="nM",plate=decklayout.EPPENDORFS,looplengths=None,extraVol=30,wellnames=None,initVol=0): 'Add templates as "reagents", return the list of them' if finalconc is None: logging.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]) if len(set(names))!=len(names): logging.error("addTemplates: template names must be unique") r=[] if looplengths is not None: assert(len(names)==len(looplengths)) for i in range(len(names)): if wellnames is None: well=None else: well=wellnames[i] if reagents.isReagent(names[i]): r.append(reagents.lookup(names[i])) elif looplengths is None: r.append(reagents.add(names[i],plate=plate,conc=Concentration(stockconc[i],finalconc[i],units),extraVol=extraVol,well=well,initVol=initVol)) else: r.append(reagents.add(names[i],plate=plate,conc=Concentration(stockconc[i],finalconc[i],units),extraVol=extraVol,extrainfo=looplengths[i],well=well,initVol=initVol)) return r
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 logmeasure(self,tip,height,submerge,zmax,zadd,time): # Time is the time in seconds of this measurement sample=self.lastSample[tip] if len(sample.extrainfo)>0: elapsed=time-sample.extrainfo[0] else: elapsed=timedelta(0) #print "%s: %f"%(sample.name,elapsed) sample.extrainfo=[time] # Keep track of last measurement time of this sample in the extrainfo list if sample.plate.location.zmax is not None: curzmax=2100-sample.plate.location.zmax-390+TIPOFFSETS[tip-1] if zmax!=curzmax: logging.warning("ZMax for plate %s, tip %d at time of run was %.0f, currently at %.0f"%(sample.plate.name, tip, zmax, curzmax)) zmax=curzmax prevol=sample.volume-sample.lastadd # Liquid height is measured before next op, whose volume effect has already been added to sample.volume if height==-1: vol=sample.plate.getliquidvolume((zadd+submerge)/10.0) if vol is not None: if prevol<vol and prevol!=0: # The liquid measure failed, but based on the previous volume estimate, it was guaranteed to fail since the submerge depth would've been below bottom # But if we don't know the volume (ie a prefilled tube -> prevol=0), then log this as a fail h=" @[DEEP <%.1fmm:<%.1ful#%d]"%((zadd+submerge)/10.0,vol,tip) #h="" else: h=" @[FAIL <%.1fmm:<%.1ful#%d]"%((zadd+submerge)/10,vol,tip) else: h=" @[FAIL <%.1f#%d]"%((zadd+submerge)/10.0,tip) else: vol=sample.plate.getliquidvolume((height+submerge-zmax)/10.0) if vol is None: h=" @[%.1fmm,%.1fmm#%d]"%((height-zmax)/10.0,submerge/10.0,tip) else: if prevol==0: logging.notice("Got a liquid height measurement for a well that should be empty -- assuming it was prefilled") sample.volume=vol+sample.lastadd prevol=vol expectHeight=sample.plate.getliquidheight(prevol) errorHeight=(height+submerge-zmax)-expectHeight*10 h=" @[%.1fmm,%.1fmm:%.1ful#%d]"%((height-zmax)/10.0,submerge/10.0,vol,tip) if abs(errorHeight)>1: if abs(errorHeight)>4: emphasize="*"*(min(10,int(abs(errorHeight))-3)) else: emphasize='' h=h+"{%sE=%d;%.1ful}"%(emphasize,errorHeight,vol-prevol) sample.volume=sample.volume+(vol-prevol) # Insert BEFORE last history entry since the liquid height is measured before aspirate/dispense hsplit=sample.history.split(' ') if elapsed.total_seconds()>=600: # Log elapsed time if more than 10 min sample.history=" ".join(hsplit[:-1]+["(T%.0f)"%(elapsed.total_seconds()/60)]+[h]+hsplit[-1:]) else: sample.history=" ".join(hsplit[:-1]+[h]+hsplit[-1:])
def beadAddElutant(self,src,elutant=None,elutionVol=30,eluteTime=60,returnPlate=True,temp=None): if elutant is None: elutant=decklayout.WATER [src,elutionVol,elutant]=listify([src,elutionVol,elutant]) for i in range(len(src)): if elutionVol[i]<30: logging.warning("elution from beads of %s with %.1f ul < minimum of 30ul"%(src[i].name,elutionVol[i])) self.e.moveplate(src[i].plate,"Home") self.e.transfer(elutionVol[i]-src[i].volume,elutant[i],src[i],(False,True)) if temp is None: for plate in set([s.plate for s in src]): self.e.shake(plate,dur=eluteTime,returnPlate=returnPlate,force=True) else: self.e.shakeSamples(src,dur=30,returnPlate=False) worklist.pyrun('PTC\\ptcsetpgm.py elute TEMP@%d,%d TEMP@25,2'%(temp,eluteTime)) self.e.runpgm("elute",eluteTime/60,False,elutionVol[0]) if returnPlate: self.e.moveplate(src[0].plate,"Home")
def __init__(self,op,tip,vol,wellx,welly,rack,grid,pos,lc,std,volset,isMulti): self.op=op self.tip=tip self.vol=vol self.lc=lc self.std=std self.volset=volset self.isMulti=isMulti self.sample=getSample(wellx,welly,rack,grid,pos) if lc=='Air' or lc[0:7]=='Blowout' or lc=='Dip': if op=='dispense': self.sample.addhistory(lc,vol,tip) elif op=='aspirate': self.sample.addhistory(lc,-vol,tip) else: logging.notice("LogEntry: bad op (%s) for LC %s"%(op,lc)) assert False self.sample.lastadd=0 elif op=='dispense': self.sample.addhistory("",vol,tip) self.sample.lastadd=vol elif op=='detect': self.sample.addhistory("detect",0,tip) self.sample.lastadd=0 elif op=='aspirate': self.sample.addhistory("",-vol,tip) self.sample.lastadd=-(vol+SURFACEREMOVE) # Extra for tip wetting elif op[0:3]=='mix': self.sample.addhistory(op,vol,tip) self.sample.lastadd=0 else: logging.warning("LogEntry: bad op: %s"%op) assert False if self.sample.volume+self.sample.lastadd<0 and self.sample.volume!=0: self.sample.history=self.sample.history + ("{Emptied%.2f}"%(self.sample.volume+self.sample.lastadd)) self.sample.volume=0 else: self.sample.volume+=self.sample.lastadd
def addSamples(self, src, needDil, primers, nreplicates=1, names=None, saveVol=None, saveDil=None, save=True): """Add sample(s) to list of qPCRs to do""" # print "addSamples(%s)"%src if not isinstance(src, list): src = [src] if save: # saveVol is total amount (after dilution) to be immediately saved if saveDil is None: saveDil = min(needDil, self.MAXDIL) if 1 < needDil / saveDil < 2: saveDil = math.sqrt(needDil) elif saveDil > needDil: logging.warning("addSamples: saveDil=" + saveDil + ", but needDil is only " + needDil) saveDil = needDil if saveVol is None: saveVol = max(self.MINDILVOL * 1.0 / saveDil, self.TGTINVOL) if names is None: tgt = [Sample(diluteName(src[i].name, saveDil), decklayout.DILPLATE) for i in range(len(src))] else: tgt = [Sample(diluteName(names[i], saveDil), decklayout.DILPLATE) for i in range(len(src))] sv = tgt for i in range(len(sv)): # print "Save ",src[i] svtmp = self.trp.runQPCRDIL(src=[src[i]], vol=saveVol * saveDil, srcdil=saveDil, tgt=[tgt[i]], dilPlate=True, dilutant=self.dilutant) sv[i] = svtmp[0] else: saveDil = 1 sv = src needDil = needDil / saveDil nstages = int(math.ceil(math.log(needDil) / math.log(self.MAXDIL))) ndil = len(src) * (nstages + (1 if save else 0)) logging.notice("QPCR: %dQ/%dD [%s], dilution:%.1fx, primers: [%s]" % ( len(src) * len(primers) * nreplicates, ndil, ",".join([s.name for s in src]) if names is None else ",".join(names), needDil, ",".join(primers))) for svi in range(len(sv)): s = sv[svi] if s.hasBeads: prereqs = [] else: j0 = self.jobq.addShake(sample=s, prereqs=[]) prereqs = [j0] intermed = s for i in range(nstages): dil = math.pow(needDil, 1.0 / nstages) # print "stage ",i,", needDil=",needDil,", dil=",dil if i > 0: vol = self.MAXDILVOL else: vol = min(self.MAXDILVOL * 1.0, max(self.MINDILVOL * 1.0, dil * self.TGTINVOL * 1.0)) if intermed.plate == decklayout.DILPLATE: firstWell = intermed.well + 4 # Skip by 4 wells at a time to optimize multi-tip movements else: firstWell = 0 if not save and i == 0 and names is not None: # Need to replace the name in this condition dest = Sample(diluteName(names[svi], dil), decklayout.DILPLATE, firstWell=firstWell) else: dest = Sample(diluteName(intermed.name, dil), decklayout.DILPLATE, firstWell=firstWell) # print "dest=",dest j1 = self.jobq.addMultiTransfer(volume=vol * (dil - 1) / dil, src=self.dilutant, dest=dest, prereqs=[]) prereqs.append(j1) j2 = self.jobq.addTransfer(volume=vol / dil, src=intermed, dest=dest, prereqs=prereqs) # print "Dilution of %s was %.2f instead of %.2f (error=%.0f%%)"%(dest.name,(dil/(1+dil))/(1/dil),dil,((dil/(1+dil))/(1/dil)/dil-1)*100) if dest.hasBeads: prereqs = [j2] else: j3 = self.jobq.addShake(sample=dest, prereqs=[j2]) prereqs = [j3] intermed = dest self.dilProds = self.dilProds + [intermed] self.primers = self.primers + [primers] self.nreplicates = self.nreplicates + [nreplicates]
def setVolumes(self): # Computed parameters self.rnaConc = 8314 * self.tmplFinalConc / (self.tmplFinalConc + 55) * self.t7dur / 30 maxConc = 1000 * self.stopConc * 4 / 0.9 if maxConc < self.rnaConc: logging.warning("Stop@%.1f uM limits usable RNA to %.0f/%.0f nM" % (self.stopConc, 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] pcrExtra = [ 1.4 * math.ceil(v / self.maxPCRVolume) for v in self.pcrvol ] self.minligvol = [ self.pcrvol[i] / self.pcrdil[i] + (pcrExtra[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] == 'C' 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 #print "self.rtvol=",self.rtvol 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 self.t7extravols = ( (4 + 1.4) * 0.9 if 'stopped' in self.qpcrStages else 0) + ( (5 + 1.4) * 0.9 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])) self.t7vol = [ max((15.1 + self.rtvol[i] / 4.0 + 1.4) * 0.9 + self.t7extravols, self.pmolesIn * 1000 / self.tmplFinalConc / 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 self.t7vol = [min(self.maxSampVolume, v) for v in self.t7vol] # Make sure no tubes overflow if 'template' in self.qpcrStages: self.t7vol[0] += 5.4
def addSamples(self, src, needDil, primers, nreplicates=1, names=None, saveVol=None, saveDil=None, save=True): 'Add sample(s) to list of qPCRs to do' #print "addSamples(%s)"%src if not isinstance(src, list): src = [src] if save: # saveVol is total amount (after dilution) to be immediately saved if saveDil is None: saveDil = min(needDil, self.MAXDIL) if needDil / saveDil > 1 and needDil / saveDil < 2: saveDil = math.sqrt(needDil) elif saveDil > needDil: logging.warning("addSamples: saveDil=", saveDil, ", but needDil is only ", needDil) saveDil = needDil if saveVol is None: saveVol = max(self.MINDILVOL * 1.0 / saveDil, self.TGTINVOL) if names is None: tgt = [ Sample(diluteName(src[i].name, saveDil), decklayout.DILPLATE) for i in range(len(src)) ] else: tgt = [ Sample(diluteName(names[i], saveDil), decklayout.DILPLATE) for i in range(len(src)) ] sv = tgt for i in range(len(sv)): #print "Save ",src[i] svtmp = self.trp.runQPCRDIL(src=[src[i]], vol=saveVol * saveDil, srcdil=saveDil, tgt=[tgt[i]], dilPlate=True, dilutant=self.dilutant) sv[i] = svtmp[0] else: saveDil = 1 sv = src needDil = needDil / saveDil nstages = int(math.ceil(math.log(needDil) / math.log(self.MAXDIL))) ndil = len(src) * (nstages + (1 if save else 0)) logging.notice( "QPCR: %dQ/%dD [%s], dilution:%.1fx, primers: [%s]" % (len(src) * len(primers) * nreplicates, ndil, ",".join([s.name for s in src]) if names is None else ",".join(names), needDil, ",".join(primers))) for svi in range(len(sv)): s = sv[svi] if s.hasBeads: prereqs = [] else: j0 = self.jobq.addShake(sample=s, prereqs=[]) prereqs = [j0] intermed = s for i in range(nstages): dil = math.pow(needDil, 1.0 / nstages) #print "stage ",i,", needDil=",needDil,", dil=",dil if i > 0: vol = self.MAXDILVOL else: vol = min(self.MAXDILVOL, max(self.MINDILVOL, dil * self.TGTINVOL)) if intermed.plate == decklayout.DILPLATE: firstWell = intermed.well + 4 # Skip by 4 wells at a time to optimize multi-tip movements else: firstWell = 0 if not save and i == 0 and names is not None: # Need to replace the name in this condition dest = Sample(diluteName(names[svi], dil), decklayout.DILPLATE, firstWell=firstWell) else: dest = Sample(diluteName(intermed.name, dil), decklayout.DILPLATE, firstWell=firstWell) #print "dest=",dest j1 = self.jobq.addMultiTransfer(volume=vol * (dil - 1) / dil, src=self.dilutant, dest=dest, prereqs=[]) prereqs.append(j1) j2 = self.jobq.addTransfer(volume=vol / dil, src=intermed, dest=dest, prereqs=prereqs) #print "Dilution of %s was %.2f instead of %.2f (error=%.0f%%)"%(dest.name,(dil/(1+dil))/(1/dil),dil,((dil/(1+dil))/(1/dil)/dil-1)*100) if dest.hasBeads: prereqs = [j2] else: j3 = self.jobq.addShake(sample=dest, prereqs=[j2]) prereqs = [j3] intermed = dest self.dilProds = self.dilProds + [intermed] self.primers = self.primers + [primers] self.nreplicates = self.nreplicates + [nreplicates]
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