def simulate_without_rl(flags, module): flow_params = getattr(module, flags.exp_config).flow_params if hasattr(getattr(module, flags.exp_config), "custom_callables"): callables = getattr(module, flags.exp_config).custom_callables else: callables = None flow_params['sim'].render = not flags.no_render flow_params['simulator'] = 'traci' # Specify an emission path if they are meant to be generated. if flags.gen_emission: flow_params['sim'].emission_path = "./data" # Create the flow_params object fp_ = flow_params['exp_tag'] dir_ = flow_params['sim'].emission_path with open(os.path.join(dir_, "{}.json".format(fp_)), 'w') as outfile: json.dump(flow_params, outfile, cls=FlowParamsEncoder, sort_keys=True, indent=4) # Run for the specified number of rollouts. flow_params['env'].horizon = 3000 # Create the experiment object. exp = Experiment(flow_params, callables) exp.run(flags.num_runs, convert_to_csv=flags.gen_emission)
def __init__(self, trp, vol=15, maxdil=16, mindilvol=90, maxdilvol=100, debug=False): 'Create a new QPCR setup structure' self.volume = vol self.samples = [] self.needDil = [] self.primers = [] self.nreplicates = [] self.dilProds = [] self.reuse = [ ] # Index of prior dilution that can be used as input to this one; otherwise None self.stages = [] self.MAXDIL = maxdil self.MINDILVOL = mindilvol self.MAXDILVOL = maxdilvol self.trp = trp self.debug = debug self.dilutant = decklayout.SSDDIL self.jobq = JobQueue() self.e = Experiment()
def train_stable_baselines3(submodule, flags): """Train policies using the PPO algorithm in stable-baselines3.""" from stable_baselines3.common.vec_env import DummyVecEnv from stable_baselines3 import PPO import torch start_time = timeit.default_timer() flow_params = submodule.flow_params # Path to the saved files exp_tag = flow_params['exp_tag'] result_name = '{}/{}'.format(exp_tag, strftime("%Y-%m-%d-%H:%M:%S")) # Perform training. print("cuda is available: ", torch.cuda.is_available()) print('Beginning training.') print("==========================================") model = run_model_stablebaseline3(flow_params, flags.num_cpus, flags.rollout_size, flags.num_steps) # Save the model to a desired folder and then delete it to demonstrate # loading. print('Saving the trained model!') path = os.path.realpath(os.path.expanduser('~/baseline_results')) ensure_dir(path) save_path = os.path.join(path, result_name) model.save(save_path) # dump the flow params # check time for choose GPU and CPU stop_time = timeit.default_timer() run_time = stop_time - start_time with open(os.path.join(path, result_name) + '.json', 'w') as outfile: json.dump(flow_params, outfile, cls=FlowParamsEncoder, sort_keys=True, indent=4) # Replay the result by loading the model print('Loading the trained model and testing it out!') model.load(save_path) flow_params = get_flow_params(os.path.join(path, result_name) + '.json') flow_params['sim'].render = False flow_params['env'].horizon = 1500 # 150seconds operation env = env_constructor(params=flow_params, version=0)() # The algorithms require a vectorized environment to run eval_env = DummyVecEnv([lambda: env]) obs = eval_env.reset() reward = 0 for _ in range(flow_params['env'].horizon): action, _states = model.predict(obs) obs, rewards, dones, info = eval_env.step(action) reward += rewards print("--------------------------------------------------------") flow_params['sim'].render = True simulation = Experiment(flow_params) simulation.run(num_runs=1) print('the final reward is {}'.format(reward)) print("total run_time:", run_time, "s")
def reset(self): 'Reset this experiment so we can generate it again after adjusting the reagent initial volumes and total time' totalTime = clock.elapsed() clock.reset(totalTime) #print "After reset, elapsed=%d"%clock.elapsed() worklist.reset() self.e = Experiment() self.e.setreagenttemp(6.0) self.e.sanitize(3, 50) # Heavy sanitize reagents.reset() Sample.clearall() decklayout.initWellKnownSamples()
def run(self): parser=argparse.ArgumentParser(description="TRP") parser.add_argument('-v','--verbose',help='Enable verbose output',default=False,action="store_true") parser.add_argument('-D','--dewpoint',type=float,help='Dew point',default=10.0) args=parser.parse_args() print "Estimating evaporation for dew point of %.1f C"%args.dewpoint globals.dewpoint=args.dewpoint self.e=Experiment() self.e.setreagenttemp(args.dewpoint) self.e.sanitize(3,50) # Heavy sanitize self.setup() if args.verbose: print '------ Preliminary run to set volume -----' else: sys.stdout=open(os.devnull,'w') self.pgm() self.reset() self.pgm() if args.verbose: globals.verbose=True print '------ Main run -----' else: sys.stdout=sys.__stdout__ self.reset() self.pgm() self.finish()
def reset(self): 'Reset this experiment so we can generate it again after adjusting the reagent initial volumes and total time' totalTime=clock.elapsed() clock.reset(totalTime) #print "After reset, elapsed=%d"%clock.elapsed() worklist.reset() self.e=Experiment() self.e.setreagenttemp(6.0) self.e.sanitize(3,50) # Heavy sanitize reagents.reset() Sample.clearall() decklayout.initWellKnownSamples()
def run(self): parser = argparse.ArgumentParser(description="TRP") parser.add_argument('-v', '--verbose', help='Enable verbose output', default=False, action="store_true") parser.add_argument('-D', '--dewpoint', type=float, help='Dew point', default=10.0) args = parser.parse_args() print "Estimating evaporation for dew point of %.1f C" % args.dewpoint globals.dewpoint = args.dewpoint self.e = Experiment() self.e.setreagenttemp(args.dewpoint) self.e.sanitize(3, 50) # Heavy sanitize self.setup() if args.verbose: print '------ Preliminary run to set volume -----' else: sys.stdout = open(os.devnull, 'w') self.pgm() self.reset() self.pgm() if args.verbose: globals.verbose = True print '------ Main run -----' else: sys.stdout = sys.__stdout__ self.reset() self.pgm() self.finish()
def train_rllib(submodule, flags): """Train policies using the PPO algorithm in RLlib.""" import ray from ray.tune import run_experiments flow_params = submodule.flow_params n_cpus = submodule.N_CPUS n_rollouts = submodule.N_ROLLOUTS policy_graphs = getattr(submodule, "POLICY_GRAPHS", None) policy_mapping_fn = getattr(submodule, "policy_mapping_fn", None) policies_to_train = getattr(submodule, "policies_to_train", None) alg_run, gym_name, config = setup_exps_rllib(flow_params, n_cpus, n_rollouts, policy_graphs, policy_mapping_fn, policies_to_train, flags) ray.init(num_cpus=n_cpus + 1, object_store_memory=200 * 1024 * 1024) exp_config = { "run": alg_run, "env": gym_name, "config": { **config }, "checkpoint_freq": 20, "checkpoint_at_end": True, "max_failures": 999, "stop": { "training_iteration": flags.num_steps, }, } print(exp_config["config"]["framework"]) if flags.checkpoint_path is not None: exp_config['restore'] = flags.checkpoint_path run_experiments({flow_params["exp_tag"]: exp_config}) simulation = Experiment(flow_params) simulation.run(num_runs=1)
def __init__(self, trp, vol=15, maxdil=16, mindilvol=90, maxdilvol=100, debug=False): """Create a new QPCR setup structure""" self.volume = vol self.samples = [] self.needDil = [] self.primers = [] self.nreplicates = [] self.dilProds = [] self.reuse = [] # Index of prior dilution that can be used as input to this one; otherwise None self.stages = [] self.MAXDIL = maxdil self.MINDILVOL = mindilvol self.MAXDILVOL = maxdilvol self.trp = trp self.debug = debug self.dilutant = decklayout.SSDDIL self.jobq = JobQueue() self.e = Experiment()
class MSetup(object): TGTINVOL = 4 def __init__(self, trp, vol=15, maxdil=16, mindilvol=90, maxdilvol=100, debug=False): """Create a new QPCR setup structure""" self.volume = vol self.samples = [] self.needDil = [] self.primers = [] self.nreplicates = [] self.dilProds = [] self.reuse = [] # Index of prior dilution that can be used as input to this one; otherwise None self.stages = [] self.MAXDIL = maxdil self.MINDILVOL = mindilvol self.MAXDILVOL = maxdilvol self.trp = trp self.debug = debug self.dilutant = decklayout.SSDDIL self.jobq = JobQueue() self.e = Experiment() 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 allprimers(self): return set([p for sublist in self.primers for p in sublist]) def addReferences(self, mindil=1, nsteps=6, dstep=4, nreplicates=1, ref=None, primers=None): """Add all needed references""" # print "addReferences(mindil=",mindil,", nsteps=",nsteps,", dstep=",dstep,", nrep=", nreplicates, ", ref=",ref,")" # Make sure the ref reagent is loaded if ref is None: ref = reagents.getsample("QPCRREF") if primers is None: primers = self.allprimers() dils = [1.0] for i in range(nsteps): needDil = mindil * math.pow(dstep, i) srcDil = 1 src = [ref] for j in range(len(dils)): if needDil / dils[j] <= self.MAXDIL: srcDil = dils[j] if srcDil == 1: src = [ref] else: srcname = "%s.D%d" % (ref.name, srcDil) src = [Sample.lookup(srcname)] if src[0] is None: src = [Sample(srcname, decklayout.DILPLATE)] break tmp = self.MINDILVOL self.MINDILVOL = 75 # Make sure there's enough for resuing dilutions self.addSamples(src=src, needDil=needDil / srcDil, primers=primers, nreplicates=nreplicates, save=needDil / srcDil > self.MAXDIL, saveVol=75) self.MINDILVOL = tmp dils.append(needDil) self.addSamples(src=[self.dilutant], needDil=1, primers=primers, nreplicates=nreplicates, save=False) def idler(self, t): endTime = clock.elapsed() + t if self.debug: print("Idler(%.0f)" % t) while clock.elapsed() < endTime: j = self.jobq.getJob() if j is None: break self.jobq.execJob(self.trp.e, j) if self.debug: print("Idler done with ", endTime - clock.elapsed(), " seconds remaining") 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 TC to complete before able to do final jobs self.idler(100000) if self.jobq.len() > 0: logging.error("Blocked jobs remain on queue:") self.jobq.dump() assert False tgt1 = Sample("Barcoded.Mixdown1", decklayout.EPPENDORFS) for i in range(1, len(self.dilProds)): self.e.transfer(12.5 * 1.2 * 2 / 1.5, self.dilProds[i], tgt1, mix=(False, False))
class TRP(object): def __init__(self): 'Create a new TRP run' def reset(self): 'Reset this experiment so we can generate it again after adjusting the reagent initial volumes and total time' totalTime=clock.elapsed() clock.reset(totalTime) #print "After reset, elapsed=%d"%clock.elapsed() worklist.reset() self.e=Experiment() self.e.setreagenttemp(6.0) self.e.sanitize(3,50) # Heavy sanitize reagents.reset() Sample.clearall() decklayout.initWellKnownSamples() 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 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") ######################## # Save samples to another well ######################## 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 distribute(self,src,dil,vol,wells,tgt=None,dilutant=None,plate=decklayout.SAMPLEPLATE): if tgt is None: tgt=[Sample("%s.dist%d"%(src[0].name,j),plate) for j in range(wells)] if dilutant is None: dilutant=decklayout.WATER self.e.multitransfer([vol*(dil-1) for i in range(wells)],dilutant,tgt) self.e.multitransfer([vol for i in range(wells)],src[0],tgt) return tgt ######################## # Dilute samples in place ######################## def diluteInPlace(self,tgt,dil=None,finalvol=None): # Dilute in place # e.g.: trp.diluteInPlace(tgt=rt1,dil=2) [tgt,dil,finalvol]=listify([tgt,dil,finalvol]) dilutant=decklayout.WATER for i in range(len(tgt)): if finalvol[i] is not None and dil[i] is None: self.e.transfer(finalvol[i]-tgt[i].volume,dilutant,tgt[i],mix=(False,False)) elif finalvol[i] is None and dil[i] is not None: self.e.transfer(tgt[i].volume*(dil[i]-1),dilutant,tgt[i],mix=(False,False)) else: print "diluteInPlace: cannot specify both dil and finalvol" assert(False) #print "after dilute, tgt[0]=",str(tgt[0]),",mixed=",tgt[0].isMixed() return tgt # The name of the samples are unchanged -- the predilution names ######################## # Run a reaction in place ######################## def runRxInPlace(self,src,vol,master,returnPlate=True,finalx=1.0): 'Run reaction on beads in given total volume' [vol,src,master]=listify([vol,src,master]) mastervol=[vol[i]*finalx/master[i].conc.dilutionneeded() for i in range(len(vol))] watervol=[vol[i]-src[i].volume-mastervol[i] for i in range(len(vol))] if any([w < -0.01 for w in watervol]): print "runRxInPlace: negative amount of water needed: ",w assert(False) for i in range(len(src)): if watervol[i]>0: self.e.transfer(watervol[i],decklayout.WATER,src[i],(False,False)) for i in range(len(src)): self.e.transfer(mastervol[i],master[i],src[i],(True,src[i].hasBeads)) self.e.shakeSamples(src,returnPlate=returnPlate) ######################## # T7 - Transcription ######################## def runT7Setup(self,theo,src,vol,srcdil,tgt=None,rlist=["MT7"]): [theo,src,tgt,srcdil]=listify([theo,src,tgt,srcdil]) for i in range(len(src)): if tgt[i] is None: if theo[i]: tgt[i]=Sample("%s.T+"%src[i].name,decklayout.SAMPLEPLATE) else: tgt[i]=Sample("%s.T-"%src[i].name,decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s"%[str(s) for s in src]) rvols=[reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal=sum(rvols) sourcevols=[vol*1.0/s for s in srcdil] if any(theo): theovols=[(vol*1.0/reagents.getsample("Theo").conc.dilutionneeded() if t else 0) for t in theo] watervols=[vol-theovols[i]-sourcevols[i]-rtotal for i in range(len(src))] else: watervols=[vol-sourcevols[i]-rtotal for i in range(len(src))] if any([w<-1e-10 for w in watervols]): print "runT7Setup: Negative amount of water required: ",watervols assert False if sum(watervols)>0.01: self.e.multitransfer(watervols,decklayout.WATER,tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt],reagents.getsample(rlist[ir]),tgt) if any(theo): self.e.multitransfer([tv for tv in theovols if tv>0.01],reagents.getsample("Theo"),[tgt[i] for i in range(len(theovols)) if theovols[i]>0],ignoreContents=True) for i in range(len(src)): self.e.transfer(sourcevols[i],src[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) for t in tgt: t.ingredients['BIND']=1e-20*sum(t.ingredients.values()) return tgt def runT7Pgm(self,vol,dur): if dur<100: pgm="TRP37-%d"%dur else: pgm="T37-%d"%dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@25,2'%(pgm,dur*60)) self.e.runpgm(pgm,dur, False,vol) 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 runT7(self,theo,src,vol,srcdil,tgt=None,dur=15,stopmaster=None): [theo,src,tgt,srcdil,stopmaster]=listify([theo,src,tgt,srcdil,stopmaster]) tgt=self.runT7Setup(theo,src,vol,srcdil,tgt) self.runT7Pgm(vol,dur) tgt=self.runT7Stop(theo,tgt,stopmaster) return tgt ######################## # Beads ######################## def bindBeads(self,src,beads=None,beadConc=None,bbuffer=None,incTime=60,addBuffer=False): if beads is None: beads=reagents.getsample("Dynabeads") if bbuffer is None: bbuffer=reagents.getsample("BeadBuffer") [src,beads,bbuffer,beadConc]=listify([src,beads,bbuffer,beadConc]) for s in src: if s.plate!=decklayout.SAMPLEPLATE: print "runBeadCleanup: src ",s," is not in sample plate." assert(0) s.conc=None # Can't track concentration of beads self.e.moveplate(src[0].plate,"Home") # Make sure we do this off the magnet # Calculate volumes needed beadConc=[beads[i].conc.final if beadConc[i] is None else beadConc[i] for i in range(len(beads))] beadDil=beads[i].conc.stock/beadConc[i] if addBuffer: totalvol=[s.volume/(1-1.0/beadDil-1.0/bbuffer[i].conc.dilutionneeded()) for s in src] buffervol=[totalvol[i]/bbuffer[i].conc.dilutionneeded() for i in range(len(src))] # Add binding buffer to bring to 1x (beads will already be in 1x, so don't need to provide for them) for i in range(len(src)): self.e.transfer(buffervol[i],bbuffer[i],src[i]) else: buffervol=[0.0 for i in range(len(src))] totalvol=[s.volume/(1-1.0/beadDil) for s in src] beadvol=[t/beadDil for t in totalvol] # Transfer the beads for i in range(len(src)): self.e.transfer(beadvol[i],beads[i],src[i],(True,True)) # Mix beads after (before mixing handled automatically by sample.py) self.e.shake(src[0].plate,dur=incTime,returnPlate=False) def sepWait(self,src,sepTime=None): if sepTime is None: maxvol=max([s.volume for s in src]) if maxvol > 50: sepTime=50 else: sepTime=30 self.e.pause(sepTime) # Wait for separation def beadWash(self,src,washTgt=None,sepTime=None,residualVolume=10,keepWash=False,numWashes=2,wash=None,washVol=50,keepFinal=False,finalTgt=None,keepVol=4.2,keepDil=5): # Perform washes # If keepWash is true, retain all washes (combined) # If keepFinal is true, take a sample of the final wash (diluted by keepDil) if wash is None: wash=decklayout.WATER [src,wash]=listify([src,wash]) # Do all washes while on magnet assert(len(set([s.plate for s in src]))==1) # All on same plate if keepWash: if washTgt is None: washTgt=[] for i in range(len(src)): if s[i].volume-residualVolume+numWashes*(washVol-residualVolume) > decklayout.DILPLATE.maxVolume-20: print "Saving %.1f ul of wash in eppendorfs"%(numWashes*washVol) washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.EPPENDORFS)) else: washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.DILPLATE)) if keepFinal: if finalTgt is None: finalTgt=[] for i in range(len(src)): finalTgt.append(Sample("%s.Final"%src[i].name,decklayout.DILPLATE)) if any([s.volume>residualVolume for s in src]): # Separate and remove supernatant self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) # Remove the supernatant for i in range(len(src)): if src[i].volume > residualVolume: amt=src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt,src[i],washTgt[i]) # Keep supernatants washTgt[i].conc=None # Allow it to be reused else: self.e.dispose(amt,src[i]) # Discard supernatant # Wash for washnum in range(numWashes): self.e.moveplate(src[0].plate,"Home") if keepFinal and washnum==numWashes-1: 'Retain sample of final' for i in range(len(src)): src[i].conc=None self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,True)) # Add wash self.e.shake(src[0].plate,returnPlate=True) self.saveSamps(src=src,tgt=finalTgt,vol=keepVol,dil=keepDil,plate=decklayout.DILPLATE) else: for i in range(len(src)): src[i].conc=None self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,False)) # Add wash, no need to pipette mix since some heterogenity won't hurt here self.e.shake(src[0].plate,returnPlate=False) self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) for i in range(len(src)): amt=src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt,src[i],washTgt[i]) # Remove wash washTgt[i].conc=None # Allow it to be reused else: self.e.dispose(amt,src[i]) # Remove wash self.e.moveplate(src[0].plate,"Home") # Should only be residualVolume left with beads now result=[] if keepWash: result=result+washTgt if keepFinal: result=result+finalTgt return result 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: print "WARNING: elution from beads with %.1f ul < minimum of 30ul"%elutionVol[i] print " src=",src[i] self.e.transfer(elutionVol[i]-src[i].volume,elutant[i],src[i],(False,True)) if temp is None: self.e.shake(src[0].plate,dur=eluteTime,returnPlate=returnPlate) else: self.e.shake(src[0].plate,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 beadSupernatant(self,src,tgt=None,sepTime=None,residualVolume=10,plate=None): if plate is None: plate=decklayout.SAMPLEPLATE if tgt is None: tgt=[] for i in range(len(src)): tgt.append(Sample("%s.SN"%src[i].name,plate)) [src,tgt]=listify([src,tgt]) if any([s.plate!=src[0].plate for s in src]): print "beadSupernatant: Attempt to magsep on multiple plates at the same time" assert False self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) for i in range(len(src)): self.e.transfer(src[i].amountToRemove(residualVolume),src[i],tgt[i],(False,False)) # Transfer elution to new tube self.e.moveplate(src[0].plate,"Home") return tgt def beadCombine(self,src,residualVolume=10,suspendVolume=150,sepTime=None): 'Combine everything in the src wells into a the first well; assumes that there are enough beads in that well for all the combination' tgt=src[0] for s in src[1:]: # Combine s with tgt if tgt.volume>residualVolume: self.e.moveplate(tgt.plate,"Magnet") # Move to magnet self.sepWait([tgt],sepTime) self.e.dispose(tgt.amountToRemove(residualVolume),tgt) self.e.moveplate(tgt.plate,"Home") if s.volume<suspendVolume: self.e.transfer(suspendVolume-s.volume,decklayout.WATER,s,(False,False)) vol=s.volume-residualVolume-1 s.conc=None self.e.transfer(vol,s,tgt,mix=(True,True)) self.e.moveplate(tgt.plate,"Home") return src[0:1] ######################## # RT - Reverse Transcription ######################## def runRT(self,src,vol,srcdil,tgt=None,dur=20,heatInactivate=False): result=self.runRTSetup(src,vol,srcdil,tgt) self.runRTPgm(dur,heatInactivate=heatInactivate) return result def runRTInPlace(self,src,vol,dur=20,heatInactivate=False): 'Run RT on beads in given volume' # Adjust source dilution for i in range(len(src)): src[i].conc=None self.runRxInPlace(src,vol,reagents.getsample("MPosRT"),returnPlate=False) self.runRTPgm(dur,heatInactivate=heatInactivate) def 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 runRTPgm(self,dur=20,heatInactivate=False): if heatInactivate: hidur=2 pgm="RT-%d"%dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@95,%d TEMP@25,2 RATE 0.5'%(pgm,dur*60,hidur*60)) self.e.runpgm(pgm,dur+hidur+2.5,False,100) # Volume doesn't matter since it's just an incubation, use 100ul else: if dur<100: pgm="TRP37-%d"%dur else: pgm="T37-%d"%dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@25,2'%(pgm,dur*60)) self.e.runpgm(pgm,dur,False,100) # Volume doesn't matter since it's just an incubation, use 100ul ######################## # Lig - Ligation ######################## def runLig(self,prefix=None,src=None,vol=None,srcdil=None,tgt=None,master=None,anneal=True,ligtemp=25): if master is None: master=[reagents.getsample("MLigAN7") if p=='A' else reagents.getsample("MLigBN7") for p in prefix] #Extension [src,tgt,vol,srcdil,master]=listify([src,tgt,vol,srcdil,master]) if tgt is None: tgt=[Sample("%s.%s"%(src[i].name,master[i].name),decklayout.SAMPLEPLATE) for i in range(len(src))] # Need to check since an unused ligation master mix will not have a concentration minsrcdil=1/(1-1/master[0].conc.dilutionneeded()-1/reagents.getsample("MLigase").conc.dilutionneeded()) for i in srcdil: if i<minsrcdil: print "runLig: srcdil=%.2f, but must be at least %.2f based on concentrations of master mixes"%(i,minsrcdil) assert(False) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) i=0 while i<len(tgt): lasti=i+1 while lasti<len(tgt) and master[i]==master[lasti]: lasti=lasti+1 self.e.stage('LigAnneal',[master[i]],src[i:lasti],tgt[i:lasti],[vol[j]/1.5 for j in range(i,lasti)],1.5,destMix=False) i=lasti if anneal: self.e.shakeSamples(tgt,returnPlate=False) self.e.runpgm("TRPANN",5,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100) self.e.stage('Ligation',[reagents.getsample("MLigase")],[],tgt,vol,destMix=False) self.e.shakeSamples(tgt,returnPlate=False) self.runLigPgm(max(vol),ligtemp) return tgt def runLigPgm(self,vol,ligtemp,inactivate=True,inacttemp=65): if inactivate: pgm="LIG15-%.0f"%ligtemp worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@%.0f,900 TEMP@%.0f,600 TEMP@25,30'%(pgm,ligtemp,inacttemp)) self.e.runpgm(pgm,27,False,vol,hotlidmode="TRACKING",hotlidtemp=10) elif ligtemp==25: worklist.comment('Ligation at room temp') self.e.pause(15*60) else: pgm="TRP%.0f-15"%ligtemp worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@%.0f,900 TEMP@25,30'%(pgm,ligtemp)) self.e.runpgm(pgm,17,False,vol,hotlidmode="TRACKING",hotlidtemp=10) def runLigInPlace(self,src,vol,ligmaster,anneal=True,ligtemp=25): 'Run ligation on beads' [vol,src]=listify([vol,src]) annealvol=[v*(1-1/reagents.getsample("MLigase").conc.dilutionneeded()) for v in vol] # Adjust source dilution for i in range(len(src)): src[i].conc=None self.runRxInPlace(src,annealvol,reagents.getsample(ligmaster),returnPlate=not anneal,finalx=1.5) if anneal: self.e.runpgm("TRPANN",5,False,max([s.volume for s in src]),hotlidmode="CONSTANT",hotlidtemp=100) ## Add ligase self.runRxInPlace(src,vol,reagents.getsample("MLigase"),returnPlate=False) self.runLigPgm(max(vol),ligtemp,inactivate=False) # Do not heat inactivate since it may denature the beads ######################## # Incubation - run a single temp incubation followed by inactivation ######################## 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 ######################## # USER - USER enzyme digestion ######################## def runUser(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,enzymes=[reagents.getsample("MUser")],inPlace=inPlace) ######################## # Klenow extension ######################## def runKlenow(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=20,inPlace=False): assert(inPlace or vol is not None) return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=75,hiTime=hiTime,enzymes=[reagents.getsample("MKlenow")],inPlace=inPlace) ######################## # DNase digestion ######################## def runDNase(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=10,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=75,hiTime=hiTime,enzymes=[reagents.getsample("MDNase")],inPlace=inPlace) ######################## # PCR ######################## 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 runPCRInPlace(self,prefix,src,vol,ncycles,suffix,annealtemp=57,save=None): [prefix,src,vol,suffix]=listify([prefix,src,vol,suffix]) primer=[reagents.getsample("MPCR"+prefix[i]+suffix[i]) for i in range(len(prefix))] self.runRxInPlace(src,vol,primer,returnPlate=(save is not None)) if save is not None: self.saveSamps(src=src,vol=5,dil=10,tgt=save,plate=decklayout.DILPLATE,dilutant=decklayout.SSDDIL) pgm="PCR%d"%ncycles # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@%f,10 GOTO@2,%d TEMP@72,120 TEMP@25,2'%(pgm,annealtemp,ncycles-1)) self.e.runpgm(pgm,4.80+1.55*ncycles,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100) ######################## # qPCR ######################## def runQPCRDIL(self,src,vol,srcdil,tgt=None,dilPlate=False,pipMix=False,dilutant=decklayout.SSDDIL): [src,vol,srcdil]=listify([src,vol,srcdil]) vol=[float(v) for v in vol] if tgt is None: if dilPlate: tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.DILPLATE) for i in range(len(src))] else: tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.SAMPLEPLATE) for i in range(len(src))] srcvol=[vol[i]/srcdil[i] for i in range(len(vol))] watervol=[vol[i]-srcvol[i] for i in range(len(vol))] if len(watervol) > 4 and sum(watervol)>800: print "Could optimize distribution of ",len(watervol)," moves of ",dilutant.name,": vol=[", ["%.1f"%w for w in watervol],"]" self.e.multitransfer(watervol,dilutant,tgt,(False,False)) self.e.shakeSamples(src,returnPlate=True) for i in range(len(src)): tgt[i].conc=None # Assume dilutant does not have a concentration of its own # Check if we can align the tips here if i<len(src)-3 and tgt[i].well+1==tgt[i+1].well and tgt[i].well+2==tgt[i+2].well and tgt[i].well+3==tgt[i+3].well and tgt[i].well%4==0 and self.e.cleanTips!=15: #print "Aligning tips" self.e.sanitize() self.e.transfer(srcvol[i],src[i],tgt[i],(not src[i].isMixed(),pipMix)) if tgt[i].conc != None: tgt[i].conc.final=None # Final conc are meaningless now return tgt def runQPCR(self,src,vol,srcdil,primers=["A","B"],nreplicates=1): ## QPCR setup worklist.comment("runQPCR: primers=%s, source=%s"%([p for p in primers],[s.name for s in src])) [src,vol,srcdil,nreplicates]=listify([src,vol,srcdil,nreplicates]) self.e.shakeSamples(src,returnPlate=True) # Build a list of sets to be run torun=[] for repl in range(max(nreplicates)): for p in primers: for i in range(len(src)): if nreplicates[i]<=repl: continue if repl==0: sampname="%s.Q%s"%(src[i].name,p) else: sampname="%s.Q%s.%d"%(src[i].name,p,repl+1) s=Sample(sampname,decklayout.QPCRPLATE) torun=torun+[(src[i],s,p,vol[i])] # Fill the master mixes dil={} for p in primers: mname="MQ%s"%p if not reagents.isReagent(mname): reagents.add(name=mname,conc=15.0/9.0,extraVol=30) mq=reagents.getsample(mname) t=[a[1] for a in torun if a[2]==p] v=[a[3]/mq.conc.dilutionneeded() for a in torun if a[2]==p] self.e.multitransfer(v,mq,t,(False,False)) dil[p]=1.0/(1-1/mq.conc.dilutionneeded()) # Add the samples self.e.sanitize() # In case we are aligned for a in torun: s=a[0] t=a[1] p=a[2] v=a[3]/dil[p] t.conc=None # Concentration of master mix is irrelevant now self.e.transfer(v,s,t) return [a[1] for a in torun] def setup(self): 'Setup for experiment -- run once. Usually overridden by actual experiment' worklist.setOptimization(True) def pgm(self): 'Actual robot code generation -- may be run multiple times to establish initial volumes. Overridden by actual experiment' def run(self): parser=argparse.ArgumentParser(description="TRP") parser.add_argument('-v','--verbose',help='Enable verbose output',default=False,action="store_true") parser.add_argument('-D','--dewpoint',type=float,help='Dew point',default=10.0) args=parser.parse_args() print "Estimating evaporation for dew point of %.1f C"%args.dewpoint globals.dewpoint=args.dewpoint self.e=Experiment() self.e.setreagenttemp(args.dewpoint) self.e.sanitize(3,50) # Heavy sanitize self.setup() if args.verbose: print '------ Preliminary run to set volume -----' else: sys.stdout=open(os.devnull,'w') self.pgm() self.reset() self.pgm() if args.verbose: globals.verbose=True print '------ Main run -----' else: sys.stdout=sys.__stdout__ self.reset() self.pgm() self.finish()
import os from Experiment.sample import Sample from Experiment.experiment import Experiment from Experiment.experiment import Concentration e = Experiment() e.w.pyrun('PTC\\ptcsetpgm.py TEST TEMP@95,1 TEMP@25,1') e.runpgm("TEST", 0, waitForCompletion=False) e.waitpgm(sanitize=False) e.savegem("platemovetest_orig.gem") os.system( "grep -v 'Wash\|reagent tubes' platemovetest_orig.gem > platemovetest.gem" )
class TRP(object): def __init__(self): 'Create a new TRP run' def reset(self): 'Reset this experiment so we can generate it again after adjusting the reagent initial volumes and total time' totalTime = clock.elapsed() clock.reset(totalTime) #print "After reset, elapsed=%d"%clock.elapsed() worklist.reset() self.e = Experiment() self.e.setreagenttemp(6.0) self.e.sanitize(3, 50) # Heavy sanitize reagents.reset() Sample.clearall() decklayout.initWellKnownSamples() 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 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") ######################## # Save samples to another well ######################## 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 distribute(self, src, dil, vol, wells, tgt=None, dilutant=None, plate=decklayout.SAMPLEPLATE): if tgt is None: tgt = [ Sample("%s.dist%d" % (src[0].name, j), plate) for j in range(wells) ] if dilutant is None: dilutant = decklayout.WATER self.e.multitransfer([vol * (dil - 1) for i in range(wells)], dilutant, tgt) self.e.multitransfer([vol for i in range(wells)], src[0], tgt) return tgt ######################## # Dilute samples in place ######################## def diluteInPlace(self, tgt, dil=None, finalvol=None): # Dilute in place # e.g.: trp.diluteInPlace(tgt=rt1,dil=2) [tgt, dil, finalvol] = listify([tgt, dil, finalvol]) dilutant = decklayout.WATER for i in range(len(tgt)): if finalvol[i] is not None and dil[i] is None: self.e.transfer(finalvol[i] - tgt[i].volume, dilutant, tgt[i], mix=(False, False)) elif finalvol[i] is None and dil[i] is not None: self.e.transfer(tgt[i].volume * (dil[i] - 1), dilutant, tgt[i], mix=(False, False)) else: print "diluteInPlace: cannot specify both dil and finalvol" assert (False) #print "after dilute, tgt[0]=",str(tgt[0]),",mixed=",tgt[0].isMixed() return tgt # The name of the samples are unchanged -- the predilution names ######################## # Run a reaction in place ######################## def runRxInPlace(self, src, vol, master, returnPlate=True, finalx=1.0): 'Run reaction on beads in given total volume' [vol, src, master] = listify([vol, src, master]) mastervol = [ vol[i] * finalx / master[i].conc.dilutionneeded() for i in range(len(vol)) ] watervol = [ vol[i] - src[i].volume - mastervol[i] for i in range(len(vol)) ] if any([w < -0.01 for w in watervol]): print "runRxInPlace: negative amount of water needed: ", w assert (False) for i in range(len(src)): if watervol[i] > 0: self.e.transfer(watervol[i], decklayout.WATER, src[i], (False, False)) for i in range(len(src)): self.e.transfer(mastervol[i], master[i], src[i], (True, src[i].hasBeads)) self.e.shakeSamples(src, returnPlate=returnPlate) ######################## # T7 - Transcription ######################## def runT7Setup(self, theo, src, vol, srcdil, tgt=None, rlist=["MT7"]): [theo, src, tgt, srcdil] = listify([theo, src, tgt, srcdil]) for i in range(len(src)): if tgt[i] is None: if theo[i]: tgt[i] = Sample("%s.T+" % src[i].name, decklayout.SAMPLEPLATE) else: tgt[i] = Sample("%s.T-" % src[i].name, decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s" % [str(s) for s in src]) rvols = [reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal = sum(rvols) sourcevols = [vol * 1.0 / s for s in srcdil] if any(theo): theovols = [ (vol * 1.0 / reagents.getsample("Theo").conc.dilutionneeded() if t else 0) for t in theo ] watervols = [ vol - theovols[i] - sourcevols[i] - rtotal for i in range(len(src)) ] else: watervols = [vol - sourcevols[i] - rtotal for i in range(len(src))] if any([w < -1e-10 for w in watervols]): print "runT7Setup: Negative amount of water required: ", watervols assert False if sum(watervols) > 0.01: self.e.multitransfer(watervols, decklayout.WATER, tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt], reagents.getsample(rlist[ir]), tgt) if any(theo): self.e.multitransfer( [tv for tv in theovols if tv > 0.01], reagents.getsample("Theo"), [tgt[i] for i in range(len(theovols)) if theovols[i] > 0], ignoreContents=True) for i in range(len(src)): self.e.transfer(sourcevols[i], src[i], tgt[i]) self.e.shakeSamples(tgt, returnPlate=True) for t in tgt: t.ingredients['BIND'] = 1e-20 * sum(t.ingredients.values()) return tgt def runT7Pgm(self, vol, dur): if dur < 100: pgm = "TRP37-%d" % dur else: pgm = "T37-%d" % dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@25,2' % (pgm, dur * 60)) self.e.runpgm(pgm, dur, False, vol) 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 runT7(self, theo, src, vol, srcdil, tgt=None, dur=15, stopmaster=None): [theo, src, tgt, srcdil, stopmaster] = listify([theo, src, tgt, srcdil, stopmaster]) tgt = self.runT7Setup(theo, src, vol, srcdil, tgt) self.runT7Pgm(vol, dur) tgt = self.runT7Stop(theo, tgt, stopmaster) return tgt ######################## # Beads ######################## def bindBeads(self, src, beads=None, beadConc=None, bbuffer=None, incTime=60, addBuffer=False): if beads is None: beads = reagents.getsample("Dynabeads") if bbuffer is None: bbuffer = reagents.getsample("BeadBuffer") [src, beads, bbuffer, beadConc] = listify([src, beads, bbuffer, beadConc]) for s in src: if s.plate != decklayout.SAMPLEPLATE: print "runBeadCleanup: src ", s, " is not in sample plate." assert (0) s.conc = None # Can't track concentration of beads self.e.moveplate(src[0].plate, "Home") # Make sure we do this off the magnet # Calculate volumes needed beadConc = [ beads[i].conc.final if beadConc[i] is None else beadConc[i] for i in range(len(beads)) ] beadDil = beads[i].conc.stock / beadConc[i] if addBuffer: totalvol = [ s.volume / (1 - 1.0 / beadDil - 1.0 / bbuffer[i].conc.dilutionneeded()) for s in src ] buffervol = [ totalvol[i] / bbuffer[i].conc.dilutionneeded() for i in range(len(src)) ] # Add binding buffer to bring to 1x (beads will already be in 1x, so don't need to provide for them) for i in range(len(src)): self.e.transfer(buffervol[i], bbuffer[i], src[i]) else: buffervol = [0.0 for i in range(len(src))] totalvol = [s.volume / (1 - 1.0 / beadDil) for s in src] beadvol = [t / beadDil for t in totalvol] # Transfer the beads for i in range(len(src)): self.e.transfer( beadvol[i], beads[i], src[i], (True, True) ) # Mix beads after (before mixing handled automatically by sample.py) self.e.shake(src[0].plate, dur=incTime, returnPlate=False) def sepWait(self, src, sepTime=None): if sepTime is None: maxvol = max([s.volume for s in src]) if maxvol > 50: sepTime = 50 else: sepTime = 30 self.e.pause(sepTime) # Wait for separation def beadWash(self, src, washTgt=None, sepTime=None, residualVolume=10, keepWash=False, numWashes=2, wash=None, washVol=50, keepFinal=False, finalTgt=None, keepVol=4.2, keepDil=5): # Perform washes # If keepWash is true, retain all washes (combined) # If keepFinal is true, take a sample of the final wash (diluted by keepDil) if wash is None: wash = decklayout.WATER [src, wash] = listify([src, wash]) # Do all washes while on magnet assert (len(set([s.plate for s in src])) == 1) # All on same plate if keepWash: if washTgt is None: washTgt = [] for i in range(len(src)): if s[i].volume - residualVolume + numWashes * ( washVol - residualVolume ) > decklayout.DILPLATE.maxVolume - 20: print "Saving %.1f ul of wash in eppendorfs" % ( numWashes * washVol) washTgt.append( Sample("%s.Wash" % src[i].name, decklayout.EPPENDORFS)) else: washTgt.append( Sample("%s.Wash" % src[i].name, decklayout.DILPLATE)) if keepFinal: if finalTgt is None: finalTgt = [] for i in range(len(src)): finalTgt.append( Sample("%s.Final" % src[i].name, decklayout.DILPLATE)) if any([s.volume > residualVolume for s in src]): # Separate and remove supernatant self.e.moveplate(src[0].plate, "Magnet") # Move to magnet self.sepWait(src, sepTime) # Remove the supernatant for i in range(len(src)): if src[i].volume > residualVolume: amt = src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt, src[i], washTgt[i]) # Keep supernatants washTgt[i].conc = None # Allow it to be reused else: self.e.dispose(amt, src[i]) # Discard supernatant # Wash for washnum in range(numWashes): self.e.moveplate(src[0].plate, "Home") if keepFinal and washnum == numWashes - 1: 'Retain sample of final' for i in range(len(src)): src[i].conc = None self.e.transfer(washVol - src[i].volume, wash[i], src[i], mix=(False, True)) # Add wash self.e.shake(src[0].plate, returnPlate=True) self.saveSamps(src=src, tgt=finalTgt, vol=keepVol, dil=keepDil, plate=decklayout.DILPLATE) else: for i in range(len(src)): src[i].conc = None self.e.transfer( washVol - src[i].volume, wash[i], src[i], mix=(False, False) ) # Add wash, no need to pipette mix since some heterogenity won't hurt here self.e.shake(src[0].plate, returnPlate=False) self.e.moveplate(src[0].plate, "Magnet") # Move to magnet self.sepWait(src, sepTime) for i in range(len(src)): amt = src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt, src[i], washTgt[i]) # Remove wash washTgt[i].conc = None # Allow it to be reused else: self.e.dispose(amt, src[i]) # Remove wash self.e.moveplate(src[0].plate, "Home") # Should only be residualVolume left with beads now result = [] if keepWash: result = result + washTgt if keepFinal: result = result + finalTgt return result 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: print "WARNING: elution from beads with %.1f ul < minimum of 30ul" % elutionVol[ i] print " src=", src[i] self.e.transfer(elutionVol[i] - src[i].volume, elutant[i], src[i], (False, True)) if temp is None: self.e.shake(src[0].plate, dur=eluteTime, returnPlate=returnPlate) else: self.e.shake(src[0].plate, 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 beadSupernatant(self, src, tgt=None, sepTime=None, residualVolume=10, plate=None): if plate is None: plate = decklayout.SAMPLEPLATE if tgt is None: tgt = [] for i in range(len(src)): tgt.append(Sample("%s.SN" % src[i].name, plate)) [src, tgt] = listify([src, tgt]) if any([s.plate != src[0].plate for s in src]): print "beadSupernatant: Attempt to magsep on multiple plates at the same time" assert False self.e.moveplate(src[0].plate, "Magnet") # Move to magnet self.sepWait(src, sepTime) for i in range(len(src)): self.e.transfer(src[i].amountToRemove(residualVolume), src[i], tgt[i], (False, False)) # Transfer elution to new tube self.e.moveplate(src[0].plate, "Home") return tgt def beadCombine(self, src, residualVolume=10, suspendVolume=150, sepTime=None): 'Combine everything in the src wells into a the first well; assumes that there are enough beads in that well for all the combination' tgt = src[0] for s in src[1:]: # Combine s with tgt if tgt.volume > residualVolume: self.e.moveplate(tgt.plate, "Magnet") # Move to magnet self.sepWait([tgt], sepTime) self.e.dispose(tgt.amountToRemove(residualVolume), tgt) self.e.moveplate(tgt.plate, "Home") if s.volume < suspendVolume: self.e.transfer(suspendVolume - s.volume, decklayout.WATER, s, (False, False)) vol = s.volume - residualVolume - 1 s.conc = None self.e.transfer(vol, s, tgt, mix=(True, True)) self.e.moveplate(tgt.plate, "Home") return src[0:1] ######################## # RT - Reverse Transcription ######################## def runRT(self, src, vol, srcdil, tgt=None, dur=20, heatInactivate=False): result = self.runRTSetup(src, vol, srcdil, tgt) self.runRTPgm(dur, heatInactivate=heatInactivate) return result def runRTInPlace(self, src, vol, dur=20, heatInactivate=False): 'Run RT on beads in given volume' # Adjust source dilution for i in range(len(src)): src[i].conc = None self.runRxInPlace(src, vol, reagents.getsample("MPosRT"), returnPlate=False) self.runRTPgm(dur, heatInactivate=heatInactivate) def 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 runRTPgm(self, dur=20, heatInactivate=False): if heatInactivate: hidur = 2 pgm = "RT-%d" % dur worklist.pyrun( 'PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@95,%d TEMP@25,2 RATE 0.5' % (pgm, dur * 60, hidur * 60)) self.e.runpgm( pgm, dur + hidur + 2.5, False, 100 ) # Volume doesn't matter since it's just an incubation, use 100ul else: if dur < 100: pgm = "TRP37-%d" % dur else: pgm = "T37-%d" % dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@25,2' % (pgm, dur * 60)) self.e.runpgm( pgm, dur, False, 100 ) # Volume doesn't matter since it's just an incubation, use 100ul ######################## # Lig - Ligation ######################## def runLig(self, prefix=None, src=None, vol=None, srcdil=None, tgt=None, master=None, anneal=True, ligtemp=25): if master is None: master = [ reagents.getsample("MLigAN7") if p == 'A' else reagents.getsample("MLigBN7") for p in prefix ] #Extension [src, tgt, vol, srcdil, master] = listify([src, tgt, vol, srcdil, master]) if tgt is None: tgt = [ Sample("%s.%s" % (src[i].name, master[i].name), decklayout.SAMPLEPLATE) for i in range(len(src)) ] # Need to check since an unused ligation master mix will not have a concentration minsrcdil = 1 / (1 - 1 / master[0].conc.dilutionneeded() - 1 / reagents.getsample("MLigase").conc.dilutionneeded()) for i in srcdil: if i < minsrcdil: print "runLig: srcdil=%.2f, but must be at least %.2f based on concentrations of master mixes" % ( i, minsrcdil) assert (False) # Adjust source dilution for i in range(len(src)): src[i].conc = Concentration(srcdil[i], 1) i = 0 while i < len(tgt): lasti = i + 1 while lasti < len(tgt) and master[i] == master[lasti]: lasti = lasti + 1 self.e.stage('LigAnneal', [master[i]], src[i:lasti], tgt[i:lasti], [vol[j] / 1.5 for j in range(i, lasti)], 1.5, destMix=False) i = lasti if anneal: self.e.shakeSamples(tgt, returnPlate=False) self.e.runpgm("TRPANN", 5, False, max(vol), hotlidmode="CONSTANT", hotlidtemp=100) self.e.stage('Ligation', [reagents.getsample("MLigase")], [], tgt, vol, destMix=False) self.e.shakeSamples(tgt, returnPlate=False) self.runLigPgm(max(vol), ligtemp) return tgt def runLigPgm(self, vol, ligtemp, inactivate=True, inacttemp=65): if inactivate: pgm = "LIG15-%.0f" % ligtemp worklist.pyrun( 'PTC\\ptcsetpgm.py %s TEMP@%.0f,900 TEMP@%.0f,600 TEMP@25,30' % (pgm, ligtemp, inacttemp)) self.e.runpgm(pgm, 27, False, vol, hotlidmode="TRACKING", hotlidtemp=10) elif ligtemp == 25: worklist.comment('Ligation at room temp') self.e.pause(15 * 60) else: pgm = "TRP%.0f-15" % ligtemp worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@%.0f,900 TEMP@25,30' % (pgm, ligtemp)) self.e.runpgm(pgm, 17, False, vol, hotlidmode="TRACKING", hotlidtemp=10) def runLigInPlace(self, src, vol, ligmaster, anneal=True, ligtemp=25): 'Run ligation on beads' [vol, src] = listify([vol, src]) annealvol = [ v * (1 - 1 / reagents.getsample("MLigase").conc.dilutionneeded()) for v in vol ] # Adjust source dilution for i in range(len(src)): src[i].conc = None self.runRxInPlace(src, annealvol, reagents.getsample(ligmaster), returnPlate=not anneal, finalx=1.5) if anneal: self.e.runpgm("TRPANN", 5, False, max([s.volume for s in src]), hotlidmode="CONSTANT", hotlidtemp=100) ## Add ligase self.runRxInPlace(src, vol, reagents.getsample("MLigase"), returnPlate=False) self.runLigPgm( max(vol), ligtemp, inactivate=False ) # Do not heat inactivate since it may denature the beads ######################## # Incubation - run a single temp incubation followed by inactivation ######################## 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 ######################## # USER - USER enzyme digestion ######################## def runUser(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, inPlace=False): return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, enzymes=[reagents.getsample("MUser")], inPlace=inPlace) ######################## # Klenow extension ######################## def runKlenow(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, hiTime=20, inPlace=False): assert (inPlace or vol is not None) return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, hiTemp=75, hiTime=hiTime, enzymes=[reagents.getsample("MKlenow")], inPlace=inPlace) ######################## # DNase digestion ######################## def runDNase(self, src=None, vol=None, srcdil=None, tgt=None, incTime=15, hiTime=10, inPlace=False): return self.runIncubation(src=src, vol=vol, srcdil=srcdil, tgt=tgt, incTemp=37, incTime=incTime, hiTemp=75, hiTime=hiTime, enzymes=[reagents.getsample("MDNase")], inPlace=inPlace) ######################## # PCR ######################## 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 runPCRInPlace(self, prefix, src, vol, ncycles, suffix, annealtemp=57, save=None): [prefix, src, vol, suffix] = listify([prefix, src, vol, suffix]) primer = [ reagents.getsample("MPCR" + prefix[i] + suffix[i]) for i in range(len(prefix)) ] self.runRxInPlace(src, vol, primer, returnPlate=(save is not None)) if save is not None: self.saveSamps(src=src, vol=5, dil=10, tgt=save, plate=decklayout.DILPLATE, dilutant=decklayout.SSDDIL) pgm = "PCR%d" % ncycles # worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,30 TEMP@55,30 TEMP@72,25 GOTO@2,%d TEMP@72,180 TEMP@16,2'%(pgm,ncycles-1)) worklist.pyrun( 'PTC\\ptcsetpgm.py %s TEMP@95,120 TEMP@95,10 TEMP@%f,10 GOTO@2,%d TEMP@72,120 TEMP@25,2' % (pgm, annealtemp, ncycles - 1)) self.e.runpgm(pgm, 4.80 + 1.55 * ncycles, False, max(vol), hotlidmode="CONSTANT", hotlidtemp=100) ######################## # qPCR ######################## def runQPCRDIL(self, src, vol, srcdil, tgt=None, dilPlate=False, pipMix=False, dilutant=decklayout.SSDDIL): [src, vol, srcdil] = listify([src, vol, srcdil]) vol = [float(v) for v in vol] if tgt is None: if dilPlate: tgt = [ Sample(diluteName(src[i].name, srcdil[i]), decklayout.DILPLATE) for i in range(len(src)) ] else: tgt = [ Sample(diluteName(src[i].name, srcdil[i]), decklayout.SAMPLEPLATE) for i in range(len(src)) ] srcvol = [vol[i] / srcdil[i] for i in range(len(vol))] watervol = [vol[i] - srcvol[i] for i in range(len(vol))] if len(watervol) > 4 and sum(watervol) > 800: print "Could optimize distribution of ", len( watervol), " moves of ", dilutant.name, ": vol=[", [ "%.1f" % w for w in watervol ], "]" self.e.multitransfer(watervol, dilutant, tgt, (False, False)) self.e.shakeSamples(src, returnPlate=True) for i in range(len(src)): tgt[i].conc = None # Assume dilutant does not have a concentration of its own # Check if we can align the tips here if i < len(src) - 3 and tgt[i].well + 1 == tgt[ i + 1].well and tgt[i].well + 2 == tgt[ i + 2].well and tgt[i].well + 3 == tgt[i + 3].well and tgt[ i].well % 4 == 0 and self.e.cleanTips != 15: #print "Aligning tips" self.e.sanitize() self.e.transfer(srcvol[i], src[i], tgt[i], (not src[i].isMixed(), pipMix)) if tgt[i].conc != None: tgt[i].conc.final = None # Final conc are meaningless now return tgt def runQPCR(self, src, vol, srcdil, primers=["A", "B"], nreplicates=1): ## QPCR setup worklist.comment("runQPCR: primers=%s, source=%s" % ([p for p in primers], [s.name for s in src])) [src, vol, srcdil, nreplicates] = listify([src, vol, srcdil, nreplicates]) self.e.shakeSamples(src, returnPlate=True) # Build a list of sets to be run torun = [] for repl in range(max(nreplicates)): for p in primers: for i in range(len(src)): if nreplicates[i] <= repl: continue if repl == 0: sampname = "%s.Q%s" % (src[i].name, p) else: sampname = "%s.Q%s.%d" % (src[i].name, p, repl + 1) s = Sample(sampname, decklayout.QPCRPLATE) torun = torun + [(src[i], s, p, vol[i])] # Fill the master mixes dil = {} for p in primers: mname = "MQ%s" % p if not reagents.isReagent(mname): reagents.add(name=mname, conc=15.0 / 9.0, extraVol=30) mq = reagents.getsample(mname) t = [a[1] for a in torun if a[2] == p] v = [a[3] / mq.conc.dilutionneeded() for a in torun if a[2] == p] self.e.multitransfer(v, mq, t, (False, False)) dil[p] = 1.0 / (1 - 1 / mq.conc.dilutionneeded()) # Add the samples self.e.sanitize() # In case we are aligned for a in torun: s = a[0] t = a[1] p = a[2] v = a[3] / dil[p] t.conc = None # Concentration of master mix is irrelevant now self.e.transfer(v, s, t) return [a[1] for a in torun] def setup(self): 'Setup for experiment -- run once. Usually overridden by actual experiment' worklist.setOptimization(True) def pgm(self): 'Actual robot code generation -- may be run multiple times to establish initial volumes. Overridden by actual experiment' def run(self): parser = argparse.ArgumentParser(description="TRP") parser.add_argument('-v', '--verbose', help='Enable verbose output', default=False, action="store_true") parser.add_argument('-D', '--dewpoint', type=float, help='Dew point', default=10.0) args = parser.parse_args() print "Estimating evaporation for dew point of %.1f C" % args.dewpoint globals.dewpoint = args.dewpoint self.e = Experiment() self.e.setreagenttemp(args.dewpoint) self.e.sanitize(3, 50) # Heavy sanitize self.setup() if args.verbose: print '------ Preliminary run to set volume -----' else: sys.stdout = open(os.devnull, 'w') self.pgm() self.reset() self.pgm() if args.verbose: globals.verbose = True print '------ Main run -----' else: sys.stdout = sys.__stdout__ self.reset() self.pgm() self.finish()
class MSetup(object): TGTINVOL = 4 def __init__(self, trp, vol=15, maxdil=16, mindilvol=90, maxdilvol=100, debug=False): 'Create a new QPCR setup structure' self.volume = vol self.samples = [] self.needDil = [] self.primers = [] self.nreplicates = [] self.dilProds = [] self.reuse = [ ] # Index of prior dilution that can be used as input to this one; otherwise None self.stages = [] self.MAXDIL = maxdil self.MINDILVOL = mindilvol self.MAXDILVOL = maxdilvol self.trp = trp self.debug = debug self.dilutant = decklayout.SSDDIL self.jobq = JobQueue() self.e = Experiment() 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 allprimers(self): return set([p for sublist in self.primers for p in sublist]) def addReferences(self, mindil=1, nsteps=6, dstep=4, nreplicates=1, ref=None, primers=None): 'Add all needed references' #print "addReferences(mindil=",mindil,", nsteps=",nsteps,", dstep=",dstep,", nrep=", nreplicates, ", ref=",ref,")" # Make sure the ref reagent is loaded if ref is None: ref = reagents.getsample("QPCRREF") if primers is None: primers = self.allprimers() dils = [1] for i in range(nsteps): needDil = mindil * math.pow(dstep, i) srcDil = 1 src = [ref] for j in range(len(dils)): if needDil / dils[j] <= self.MAXDIL: srcDil = dils[j] if srcDil == 1: src = [ref] else: srcname = "%s.D%d" % (ref.name, srcDil) src = [Sample.lookup(srcname)] if src[0] is None: src = [Sample(srcname, decklayout.DILPLATE)] break tmp = self.MINDILVOL self.MINDILVOL = 75 # Make sure there's enough for resuing dilutions self.addSamples(src=src, needDil=needDil / srcDil, primers=primers, nreplicates=nreplicates, save=needDil / srcDil > self.MAXDIL, saveVol=75) self.MINDILVOL = tmp dils.append(needDil) self.addSamples(src=[self.dilutant], needDil=1, primers=primers, nreplicates=nreplicates, save=False) def idler(self, t): endTime = clock.elapsed() + t if self.debug: print "Idler(%.0f)" % t while clock.elapsed() < endTime: j = self.jobq.getJob() if j is None: break self.jobq.execJob(self.trp.e, j) if self.debug: print "Idler done with ", endTime - clock.elapsed( ), " seconds remaining" 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: logging.error("Blocked jobs remain on queue:", fatal=False) self.jobq.dump() assert False tgt1 = Sample("Barcoded.Mixdown1", decklayout.EPPENDORFS) for i in range(1, len(self.dilProds)): self.e.transfer(12.5 * 1.2 * 2 / 1.5, self.dilProds[i], tgt1, mix=(False, False))
class TRP(object): def __init__(self): 'Create a new TRP run' def reset(self): 'Reset this experiment so we can generate it again after adjusting the reagent initial volumes and total time' totalTime=clock.elapsed() clock.reset(totalTime) #print "After reset, elapsed=%d"%clock.elapsed() worklist.reset() self.e=Experiment() self.e.setreagenttemp(globals.dewpoint) self.e.sanitize(3,50) # Heavy sanitize reagents.reset() Sample.clearall() Plate.reset() decklayout.initWellKnownSamples() 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 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") ######################## # Save samples to another well ######################## def saveSamps(self,src,vol,dil,tgt=None,dilutant=None,plate=None,mix=(True,False),atEnd=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,atEnd=atEnd) 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=src[i].conc tgt[i].conc.stock=tgt[i].conc.stock/dil[i] return tgt def distribute(self,src,dil,vol,wells,tgt=None,dilutant=None,plate=decklayout.SAMPLEPLATE): if tgt is None: tgt=[Sample("%s.dist%d"%(src[0].name,j),plate) for j in range(wells)] if dilutant is None: dilutant=decklayout.WATER self.e.multitransfer([vol*(dil-1) for i in range(wells)],dilutant,tgt) self.e.multitransfer([vol for i in range(wells)],src[0],tgt) return tgt ######################## # Dilute samples in place ######################## def diluteInPlace(self,tgt,dil=None,finalvol=None): # Dilute in place # e.g.: trp.diluteInPlace(tgt=rt1,dil=2) [tgt,dil,finalvol]=listify([tgt,dil,finalvol]) dilutant=decklayout.WATER for i in range(len(tgt)): if finalvol[i] is not None and dil[i] is None: self.e.transfer(finalvol[i]-tgt[i].volume,dilutant,tgt[i],mix=(False,False)) elif finalvol[i] is None and dil[i] is not None: self.e.transfer(tgt[i].volume*(dil[i]-1),dilutant,tgt[i],mix=(False,False)) else: logging.error("diluteInPlace: cannot specify both dil and finalvol") #print "after dilute, tgt[0]=",str(tgt[0]),",mixed=",tgt[0].isMixed() return tgt # The name of the samples are unchanged -- the predilution names ######################## # Run a reaction in place ######################## def runRxInPlace(self,src,vol,master,master2=None,master3=None,returnPlate=True,finalx=1.0): 'Run reaction on beads in given total volume' [vol,src,master,master2,master3]=listify([vol,src,master,master2,master3]) mastervol=[vol[i]*finalx/master[i].conc.dilutionneeded() for i in range(len(vol))] master2vol=[0 if master2[i] is None else vol[i]*finalx/master2[i].conc.dilutionneeded() for i in range(len(vol))] master3vol=[0 if master3[i] is None else vol[i]*finalx/master3[i].conc.dilutionneeded() for i in range(len(vol))] watervol=[vol[i]-src[i].volume-mastervol[i]-master2vol[i]-master3vol[i] for i in range(len(vol))] if any([w < -0.02 for w in watervol]): logging.error("runRxInPlace: negative amount of water needed: %.2f"%min(watervol)) for i in range(len(src)): if watervol[i]+src[i].volume>=4.0 and watervol[i]>0.1: self.e.transfer(watervol[i],decklayout.WATER,src[i],(False,False)) watervol[i]=0 for i in range(len(src)): self.e.transfer(mastervol[i],master[i],src[i],(True,False)) for i in range(len(src)): if master2vol[i]>0: self.e.transfer(master2vol[i],master2[i],src[i],(True,False)) if master3vol[i]>0: self.e.transfer(master3vol[i],master3[i],src[i],(True,False)) for i in range(len(src)): if watervol[i]>=0.1: self.e.transfer(watervol[i],decklayout.WATER,src[i],(False,False)) self.e.shakeSamples(src,returnPlate=returnPlate) ######################## # T7 - Transcription ######################## def runT7Setup(self,src,vol,srcdil,ligands=None,tgt=None,rlist=["MT7"]): if isinstance(ligands,bool): if not ligands: ligands=None else: assert('runT7Setup: ligands arg should be ligand samples or None, not True') [ligands,src,tgt,srcdil]=listify([ligands,src,tgt,srcdil]) for i in range(len(src)): if tgt[i] is None: if ligands[i] is not None: tgt[i]=Sample("%s.T+%s"%(src[i].name,ligands[i].name),decklayout.SAMPLEPLATE) else: tgt[i]=Sample("%s.T-"%src[i].name,decklayout.SAMPLEPLATE) worklist.comment("runT7: source=%s"%[str(s) for s in src]) rvols=[reagents.getsample(x).conc.volneeded(vol) for x in rlist] rtotal=sum(rvols) sourcevols=[vol*1.0/s for s in srcdil] ligandvols=[0 for s in srcdil] watervols=[0 for s in srcdil] for i in range(len(srcdil)): if ligands[i] is not None: ligandvols[i]=vol*1.0/ligands[i].conc.dilutionneeded() watervols[i]=vol-ligandvols[i]-sourcevols[i]-rtotal else: watervols[i]=vol-sourcevols[i]-rtotal if any([w<-.01 for w in watervols]): logging.error("runT7Setup: Negative amount of water required: "+str(watervols)) if sum(watervols)>0.01: self.e.multitransfer(watervols,decklayout.WATER,tgt) for ir in range(len(rlist)): self.e.multitransfer([rvols[ir] for s in tgt],reagents.getsample(rlist[ir]),tgt) for i in range(len(ligands)): if ligandvols[i] > 0.01: self.e.transfer(ligandvols[i],ligands[i],tgt[i]) for i in range(len(src)): self.e.transfer(sourcevols[i],src[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) for t in tgt: t.ingredients['BIND']=1e-20*sum(t.ingredients.values()) return tgt def runT7Pgm(self,vol,dur): if dur<100: pgm="TRP37-%d"%dur else: pgm="T37-%d"%dur worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@37,%d TEMP@25,2'%(pgm,dur*60)) print "Running T7 at 37C for %d minutes"%dur self.e.runpgm(pgm,dur, False,vol) def runT7Stop(self,theo,tgt,stopmaster=None,srcdil=2): [theo,tgt,stopmaster,srcdil]=listify([theo,tgt,stopmaster,srcdil]) assert( stopmaster is not None) ## Stop sstopmaster=[reagents.getsample(s) for s in stopmaster] for i in range(len(tgt)): stopvol=tgt[i].volume/(sstopmaster[i].conc.dilutionneeded()-1) finalvol=tgt[i].volume+stopvol tgt[i].conc=Concentration(finalvol/tgt[i].volume,1) # Adjust source dilution to avoid warnings self.e.transfer(finalvol-tgt[i].volume,sstopmaster[i],tgt[i]) self.e.shakeSamples(tgt,returnPlate=True) return tgt def addEDTA(self,tgt,finalconc=4): edta=reagents.getsample("EDTA") edta.conc.final=finalconc srcdil=edta.conc.stock*1.0/(edta.conc.stock-finalconc) for t in tgt: t.conc=Concentration(srcdil,1) v=t.volume*finalconc/(edta.conc.stock-finalconc) self.e.transfer(v,edta,t,mix=(False,False)) self.e.shakeSamples(tgt,returnPlate=True) def runT7(self,theo,src,vol,srcdil,tgt=None,dur=15,stopmaster=None): [theo,src,tgt,srcdil,stopmaster]=listify([theo,src,tgt,srcdil,stopmaster]) tgt=self.runT7Setup(theo,src,vol,srcdil,tgt) self.runT7Pgm(vol,dur) tgt=self.runT7Stop(theo,tgt,stopmaster) return tgt ######################## # Beads ######################## def bindBeads(self,src,beads=None,beadConc=None,beadDil=None,bbuffer=None,incTime=60,addBuffer=False): if beads is None: beads=reagents.getsample("Dynabeads") if bbuffer is None: bbuffer=reagents.getsample("BeadBuffer") [src,beads,bbuffer,beadConc,beadDil]=listify([src,beads,bbuffer,beadConc,beadDil]) for s in src: if s.plate!=decklayout.SAMPLEPLATE: logging.error( "runBeadCleanup: src "+s.name+" is not in sample plate.") s.conc=None # Can't track concentration of beads self.e.moveplate(src[0].plate,"Home") # Make sure we do this off the magnet # Calculate volumes needed beadDil=[beads[i].conc.stock/(beads[i].conc.final if beadConc[i] is None else beadConc[i]) if beadDil[i] is None else beadDil[i] for i in range(len(beads))] if addBuffer: totalvol=[s.volume/(1-1.0/beadDil-1.0/bbuffer[i].conc.dilutionneeded()) for s in src] buffervol=[totalvol[i]/bbuffer[i].conc.dilutionneeded() for i in range(len(src))] # Add binding buffer to bring to 1x (beads will already be in 1x, so don't need to provide for them) for i in range(len(src)): self.e.transfer(buffervol[i],bbuffer[i],src[i]) else: buffervol=[0.0 for i in range(len(src))] totalvol=[src[i].volume/(1-1.0/beadDil[i]) for i in range(len(src))] beadvol=[totalvol[i]/beadDil[i] for i in range(len(totalvol))] # Transfer the beads for i in range(len(src)): self.e.transfer(beadvol[i],beads[i],src[i],(True,False)) # Mix beads before self.e.shakeSamples(src,dur=incTime,returnPlate=False) def sepWait(self,src,sepTime=None): if sepTime is None: maxvol=max([s.volume for s in src]) if maxvol > 50: sepTime=50 else: sepTime=30 sepTime=120 self.e.pause(sepTime) # Wait for separation def beadWash(self,src,washTgt=None,sepTime=None,residualVolume=0.1,keepWash=False,numWashes=2,wash=None,washVol=50,keepFinal=False,finalTgt=None,keepVol=4.2,keepDil=5,shakeWashes=False): # Perform washes # If keepWash is true, retain all washes (combined) # If keepFinal is true, take a sample of the final wash (diluted by keepDil) if wash is None: wash=decklayout.WATER [src,wash]=listify([src,wash]) # Do all washes while on magnet assert(len(set([s.plate for s in src]))==1) # All on same plate if keepWash: if washTgt is None: washTgt=[] for i in range(len(src)): if s[i].volume-residualVolume+numWashes*(washVol-residualVolume) > decklayout.DILPLATE.maxVolume-20: logging.notice("Saving %.1f ul of wash in eppendorfs"%(numWashes*washVol)) washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.EPPENDORFS)) else: washTgt.append(Sample("%s.Wash"%src[i].name,decklayout.DILPLATE)) if keepFinal: if finalTgt is None: finalTgt=[] for i in range(len(src)): finalTgt.append(Sample("%s.Final"%src[i].name,decklayout.DILPLATE)) if any([s.volume>residualVolume for s in src]): # Separate and remove supernatant self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) # Remove the supernatant for i in range(len(src)): if src[i].volume > residualVolume: amt=src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt,src[i],washTgt[i]) # Keep supernatants washTgt[i].conc=None # Allow it to be reused else: self.e.dispose(amt,src[i]) # Discard supernatant # Wash for washnum in range(numWashes): if src[0].plate.curloc!="Home" and src[0].plate.curloc!="Magnet": self.e.moveplate(src[0].plate,"Home") if keepFinal and washnum==numWashes-1: 'Retain sample of final' for i in range(len(src)): src[i].conc=None self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,True)) # Add wash self.e.shakeSamples(src,returnPlate=True) self.saveSamps(src=src,tgt=finalTgt,vol=keepVol,dil=keepDil,plate=decklayout.DILPLATE) else: for i in range(len(src)): src[i].conc=None self.e.transfer(washVol-src[i].volume,wash[i],src[i],mix=(False,False)) # Add wash, no need to pipette mix since some heterogenity won't hurt here if shakeWashes: self.e.shakeSamples(src,returnPlate=False) self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) for i in range(len(src)): amt=src[i].amountToRemove(residualVolume) if keepWash: self.e.transfer(amt,src[i],washTgt[i],mix=(False,False)) # Remove wash washTgt[i].conc=None # Allow it to be reused else: self.e.dispose(amt,src[i]) # Remove wash #self.e.moveplate(src[0].plate,"Home") # Should only be residualVolume left with beads now result=[] if keepWash: result=result+washTgt if keepFinal: result=result+finalTgt return result 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 beadSupernatant(self,src,tgt=None,sepTime=None,residualVolume=0.1,plate=None): if plate is None: plate=decklayout.SAMPLEPLATE if tgt is None: tgt=[] for i in range(len(src)): tgt.append(Sample("%s.SN"%src[i].name,plate)) [src,tgt]=listify([src,tgt]) if any([s.plate!=src[0].plate for s in src]): logging.error("beadSupernatant: Attempt to magsep on multiple plates at the same time") self.e.moveplate(src[0].plate,"Magnet") # Move to magnet self.sepWait(src,sepTime) for i in range(len(src)): self.e.transfer(src[i].amountToRemove(residualVolume),src[i],tgt[i],(False,False)) # Transfer elution to new tube self.e.moveplate(src[0].plate,"Home") return tgt def beadCombine(self,src,residualVolume=0.1,suspendVolume=150,sepTime=None): 'Combine everything in the src wells into a the first well; assumes that there are enough beads in that well for all the combination' tgt=src[0] for s in src[1:]: # Combine s with tgt if tgt.volume>residualVolume: self.e.moveplate(tgt.plate,"Magnet") # Move to magnet self.sepWait([tgt],sepTime) self.e.dispose(tgt.amountToRemove(residualVolume),tgt) self.e.moveplate(tgt.plate,"Home") if s.volume<suspendVolume: self.e.transfer(suspendVolume-s.volume,decklayout.WATER,s,(False,False)) vol=s.volume-residualVolume-1 s.conc=None self.e.transfer(vol,s,tgt,mix=(True,True)) self.e.moveplate(tgt.plate,"Home") return src[0:1] ######################## # Ampure Cleanup ######################## def runAmpure(self,src,ratio,tgt=None,incTime=5*60,elutionVol=None,evapTime=2*60): if elutionVol is None: elutionVol=src[0].volume self.bindBeads(src=src,beads=reagents.getsample("Ampure"),beadDil=(ratio+1)/ratio,incTime=incTime) self.beadWash(src=src,wash=reagents.getsample("EtOH80"),washVol=100,numWashes=2) self.e.pause(evapTime) # Wait for evaporation self.beadAddElutant(src=src,elutant=reagents.getsample("TE8"),elutionVol=elutionVol) tgt=self.beadSupernatant(src=src,sepTime=120,tgt=[Sample("%s.ampure"%r.name,decklayout.SAMPLEPLATE) for r in src]) return tgt ######################## # RT - Reverse Transcription ######################## def runRT(self,src,vol,srcdil,tgt=None,dur=20,heatInactivate=False,hiTemp=None,incTemp=37,stop=None): result=self.runRTSetup(src,vol,srcdil,tgt,stop=stop) self.runRTPgm(dur,heatInactivate=heatInactivate,hiTemp=hiTemp,incTemp=incTemp) return result def runRTInPlace(self,src,vol,dur=20,heatInactivate=False,hiTemp=None,incTemp=37): 'Run RT on beads in given volume' # Adjust source dilution for i in range(len(src)): src[i].conc=None self.runRxInPlace(src,vol,reagents.getsample("MPosRT"),returnPlate=False) self.runRTPgm(dur,heatInactivate=heatInactivate,hiTemp=hiTemp,incTemp=incTemp) def runRTSetup(self,src,vol,srcdil,tgt=None,rtmaster=None,stop=None): if rtmaster is None: rtmaster=reagents.getsample("MPosRT") if tgt is None: tgt=[Sample(s.name+".RT+",decklayout.SAMPLEPLATE) for s in src] [src,tgt,vol,srcdil,stop]=listify([src,tgt,vol,srcdil,stop]) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) stopvol=[ 0 if stop[i] is None else vol[i]/stop[i].conc.dilutionneeded() for i in range(len(vol))] assert(min(stopvol)==max(stopvol)) # Assume all stop volumes are the same self.e.stage('RTPos',[rtmaster],[src[i] for i in range(len(src)) ],[tgt[i] for i in range(len(tgt)) ],[vol[i]-stopvol[i] for i in range(len(vol))],destMix=False,finalx=vol[0]/(vol[0]-stopvol[0])) for i in range(len(tgt)): if stopvol[i]>0.1: self.e.transfer(stopvol[i],stop[i],tgt[i],(False,False)) #self.e.shakeSamples(tgt,returnPlate=True) return tgt def runRTPgm(self,dur=20,heatInactivate=False,hiTemp=None,incTemp=37): pgm="RT-%d"%dur if heatInactivate: if hiTemp is None: hiTemp=95 print "Assuming RT heat inactivation temperature of ",hiTemp hidur=2 worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@%d,%d TEMP@%d,%d TEMP@25,2 RATE 0.5'%(pgm,incTemp,dur*60,hiTemp,hidur*60)) self.e.runpgm(pgm,dur+hidur+2.5,False,100) # Volume doesn't matter since it's just an incubation, use 100ul print "Running RT at %dC for %d min, followed by heat inactivation/refold at %dC for %d minutes"%(incTemp,dur,hiTemp,hidur) else: worklist.pyrun('PTC\\ptcsetpgm.py %s TEMP@%d,%d TEMP@25,2'%(pgm,incTemp,dur*60)) self.e.runpgm(pgm,dur,False,100) # Volume doesn't matter since it's just an incubation, use 100ul print "Running RT at %dC for %d min without heat inactivation"%(incTemp,dur) ######################## # Incubation - run a single temp incubation followed by inactivation ######################## 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: logging.error("runIncubation only supports a single master mix") if inPlace: if tgt is not None: logging.error("tgt specified for in-place incubation") 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('Incubation',enzymes,src,tgt,vol,destMix=False) self.e.shakeSamples(tgt,returnPlate=(incTime is None)) if incTime is None: print "Setup only of incubation with %s"%enzymes[0].name else: if hiTemp is None: worklist.pyrun('PTC\\ptcsetpgm.py INC TEMP@%.0f,%.0f TEMP@25,30'%(incTemp,incTime*60)) print "Incubating at %dC for %d minutes without heat inactivation"%(incTemp, incTime) hiTime=0 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)) print "Incubating at %dC for %d minutes followed by heat inactivate at %dC for %d minutes"%(incTemp,incTime,hiTemp,hiTime) self.e.runpgm("INC",incTime+hiTime+2,False,max(vol),hotlidmode="TRACKING",hotlidtemp=10) return tgt ######################## # USER - USER enzyme digestion ######################## def runUser(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,enzymes=[reagents.getsample("MUser")],inPlace=inPlace) ######################## # EXO - EXO enzyme digestion ######################## def runExo(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,enzymes=[reagents.getsample("MExo")],inPlace=inPlace,hiTemp=80,hiTime=20) ######################## # Klenow extension ######################## def runKlenow(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=20,hiTemp=75,inPlace=False): assert(inPlace or vol is not None) return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=hiTemp,hiTime=hiTime,enzymes=[reagents.getsample("MKlenow")],inPlace=inPlace) ######################## # Ligation ######################## def runLig(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=10,hiTemp=65,inPlace=False): assert(inPlace or vol is not None) return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=hiTemp,hiTime=hiTime,enzymes=[reagents.getsample("MLigase")],inPlace=inPlace) ######################## # DNase digestion ######################## def runDNase(self,src=None,vol=None,srcdil=None,tgt=None,incTime=15,hiTime=10,inPlace=False): return self.runIncubation(src=src,vol=vol,srcdil=srcdil,tgt=tgt,incTemp=37,incTime=incTime,hiTemp=75,hiTime=hiTime,enzymes=[reagents.getsample("MDNase")],inPlace=inPlace) ######################## # PCR ######################## def runPCR(self,primers,src,srcdil,vol=None,tgt=None,ncycles=20,usertime=None,fastCycling=False,inPlace=False,master="MTaq",annealTemp=None,kapa=False): ## PCR if inPlace: if vol!=None: print "runPCR: cannot specify volume when using inPlace=True, srcdil and input volume determine reaction volume" assert(False) if tgt!=None: print "runPCR: cannot specify tgt when using inPlace=True" assert(False) [primers,src,vol,srcdil]=listify([primers,src,vol,srcdil]) vol=[src[i].volume*srcdil[i] for i in range(len(src))] tgt=src else: [primers,src,tgt,vol,srcdil]=listify([primers,src,tgt,vol,srcdil]) for i in range(len(tgt)): if tgt[i] is None: if isinstance(primers[i],list): tgt[i]=Sample("%s.P%s"%(src[i].name,"+".join(primers[i])),src[i].plate) else: tgt[i]=Sample("%s.P%s"%(src[i].name,primers[i]),src[i].plate) # Adjust source dilution for i in range(len(src)): src[i].conc=Concentration(srcdil[i],1) logging.notice( "primer="+str(primers)) # Add reagent entries for any missing primers if isinstance(primers[0],list): allprimers=[x for y in primers for x in y] else: allprimers=primers for up in set(allprimers): s="P-%s"%up if not reagents.isReagent(s): reagents.add(name=s,conc=4,extraVol=30) if isinstance(primers[0],list): # Multiple primers if inPlace: assert len(primers[0])==2 self.runRxInPlace(src,vol,reagents.getsample(master),master2=[reagents.getsample("P-%s"%p[0]) for p in primers],master3=[reagents.getsample("P-%s"%p[1]) for p in primers],returnPlate=False) else: for i in range(len(primers)): self.e.stage('PCR%d'%i,[reagents.getsample(master)]+[reagents.getsample("P-%s"%s) for s in primers[i]],src[i:i+1] ,tgt[i:i+1],vol[i:i+1],destMix=False) #self.e.shakeSamples(tgt,returnPlate=False) else: # Single primer if inPlace: self.runRxInPlace(src,vol,reagents.getsample(master),master2=[reagents.getsample("P-%s"%p) for p in primers],returnPlate=False) else: for up in set(primers): self.e.stage('PCR%s'%up,[reagents.getsample(master),reagents.getsample("P-%s"%up)],[src[i] for i in range(len(src)) if primers[i]==up],[tgt[i] for i in range(len(tgt)) if primers[i]==up],[vol[i] for i in range(len(vol)) if primers[i]==up],destMix=False) #self.e.shakeSamples(tgt,returnPlate=False) pgm="PCR%d"%ncycles if usertime is None: runTime=0 else: runTime=usertime if annealTemp is None: annealTemp=60 if kapa else 57 meltTemp=98 if kapa else 95 hotTime=180 if kapa else 30 extTemp=72 if kapa else 68 if fastCycling: cycling='TEMP@37,%d TEMP@95,%d TEMP@%.1f,10 TEMP@%.1f,10 TEMP @%.1f,1 GOTO@3,%d TEMP@%.1f,60 TEMP@25,2'%(1 if usertime is None else usertime*60,hotTime,meltTemp,annealTemp,extTemp,ncycles-1,extTemp) runTime+=hotTime/60+2.8+1.65*ncycles else: cycling='TEMP@37,%d TEMP@95,%d TEMP@%.1f,30 TEMP@%.1f,30 TEMP@%.1f,30 GOTO@3,%d TEMP@%.1f,60 TEMP@25,2'%(1 if usertime is None else usertime*60,hotTime,meltTemp,annealTemp,extTemp,ncycles-1,extTemp) runTime+=hotTime/60+2.8+3.0*ncycles print "PCR volume=[",",".join(["%.1f"%t.volume for t in tgt]), "], srcdil=[",",".join(["%.1fx"%s for s in srcdil]),"], program: %s"%cycling worklist.pyrun('PTC\\ptcsetpgm.py %s %s'%(pgm,cycling)) self.e.runpgm(pgm,runTime,False,max(vol),hotlidmode="CONSTANT",hotlidtemp=100) # Mark samples as mixed (by thermal convection) print "Marking samples as mixed (by thermal convection)" for t in tgt: t.wellMixed=True t.lastMixed=clock.elapsed() #self.e.shakeSamples(tgt,returnPlate=True) return tgt ######################## # qPCR ######################## def runQPCRDIL(self,src,vol,srcdil,tgt=None,dilPlate=False,pipMix=False,dilutant=decklayout.SSDDIL): [src,vol,srcdil]=listify([src,vol,srcdil]) vol=[float(v) for v in vol] if tgt is None: if dilPlate: tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.DILPLATE) for i in range(len(src))] else: tgt=[Sample(diluteName(src[i].name,srcdil[i]),decklayout.SAMPLEPLATE) for i in range(len(src))] srcvol=[vol[i]/srcdil[i] for i in range(len(vol))] watervol=[vol[i]-srcvol[i] for i in range(len(vol))] if len(watervol) > 4 and sum(watervol)>800: logging.notice("Could optimize distribution of "+str(len(watervol))+" moves of "+dilutant.name+": vol=["+str(["%.1f"%w for w in watervol])+"]") self.e.multitransfer(watervol,dilutant,tgt,(False,False)) self.e.shakeSamples(src,returnPlate=True) for i in range(len(src)): tgt[i].conc=None # Assume dilutant does not have a concentration of its own # Check if we can align the tips here if i<len(src)-3 and tgt[i].well+1==tgt[i+1].well and tgt[i].well+2==tgt[i+2].well and tgt[i].well+3==tgt[i+3].well and tgt[i].well%4==0 and self.e.cleanTips!=15: #print "Aligning tips" self.e.sanitize() self.e.transfer(srcvol[i],src[i],tgt[i],(not src[i].isMixed(),pipMix)) if tgt[i].conc != None: tgt[i].conc.final=None # Final conc are meaningless now return tgt def runQPCR(self,src,vol,primers,nreplicates=1,enzName="EvaUSER"): ## QPCR setup worklist.comment("runQPCR: primers=%s, source=%s"%([p for p in primers],[s.name for s in src])) [src,vol,nreplicates]=listify([src,vol,nreplicates]) self.e.shakeSamples(src,returnPlate=True) # Build a list of sets to be run torun=[] for repl in range(max(nreplicates)): for p in primers: for i in range(len(src)): if nreplicates[i]<=repl: continue if repl==0: sampname="%s.Q%s"%(src[i].name,p) else: sampname="%s.Q%s.%d"%(src[i].name,p,repl+1) s=Sample(sampname,decklayout.QPCRPLATE) torun=torun+[(src[i],s,p,vol[i])] # Add enzyme e=reagents.getsample(enzName) v=[a[3]/e.conc.dilutionneeded() for a in torun] t=[a[1] for a in torun] self.e.multitransfer(v,e,t) # Make the target have 'none' concentration so we can multiadd to it again for s in t: s.conc=None # Fill the master mixes dil={} for p in primers: mname="P-%s"%p if not reagents.isReagent(mname): reagents.add(name=mname,conc=4,extraVol=30) mq=reagents.getsample(mname) t=[a[1] for a in torun if a[2]==p] v=[a[3]/mq.conc.dilutionneeded() for a in torun if a[2]==p] assert(v>0) self.e.multitransfer(v,mq,t,(False,False)) dil[p]=1.0/(1-1/e.conc.dilutionneeded()-1/mq.conc.dilutionneeded()) # Add the samples self.e.sanitize() # In case we are aligned for a in torun: s=a[0] t=a[1] p=a[2] v=a[3]/dil[p] t.conc=None # Concentration of master mix is irrelevant now self.e.transfer(v,s,t) return [a[1] for a in torun] def setup(self): 'Setup for experiment -- run once. Usually overridden by actual experiment' worklist.setOptimization(True) def pgm(self): 'Actual robot code generation -- may be run multiple times to establish initial volumes. Overridden by actual experiment' def run(self): parser=argparse.ArgumentParser(description="TRP") parser.add_argument('-v','--verbose',help='Enable verbose output',default=False,action="store_true") parser.add_argument('-D','--dewpoint',type=float,help='Dew point',default=10.0) args=parser.parse_args() print "Estimating evaporation for dew point of %.1f C"%args.dewpoint globals.dewpoint=args.dewpoint self.reset() self.setup() if args.verbose: globals.verbose=True print '------ Preliminary runs to set volume -----' else: sys.stdout=open(os.devnull,'w') self.pgm() self.reset() self.pgm() if args.verbose: print '------ Main run -----' else: sys.stdout=sys.__stdout__ self.reset() self.pgm() self.finish()
def getJob(self): 'Return the next job on the queue to execute, removing it from queue' if self.runningJob!=None: logging.warning("Call of getJob() while a job is running - returning None") return None # Remove any shake jobs that are unneeded for id,j in self.jobs.items(): if j['type']=='shake' and len(j['prereqs'])==0 and j['sample'].isMixed() and not Experiment.shakerIsActive(): #print "Removing unneeded shake job ",id self.removeJob(id) for id in self.jobs: j=self.jobs[id] if j['type']!='transfer' or len(j['prereqs'])>0 or j['src'].plate.curloc!='Home' or j['dest'].plate.curloc!='Home': #if j['type']=='transfer': # print "Can't execute job ",id,": ",j,", curlocs=",j['src'].plate.curloc,", ",j['dest'].plate.curloc continue return id for id,j in self.jobs.iteritems(): if j['type']!='multitransfer' or len(j['prereqs'])>0 or j['src'].plate.curloc!='Home' or j['dest'].plate.curloc!='Home': continue # Combine with all other multitransfers from same src alldest=[] allvol=[] for id2,j2 in self.jobs.items(): if j2['type']!='multitransfer' or len(j2['prereqs'])>0 or j['src']!=j2['src']: continue alldest.append(j2['dest']) allvol.append(j2['volume']) self.removeJob(id2) combined=self.addMultiTransfer(volume=allvol,src=j['src'],dest=alldest,prereqs=[]) return combined for id in self.jobs: j=self.jobs[id] if j['type']!='shake' or len(j['prereqs'])>0 or not j['sample'].plate.curloc=='Home' or Experiment.shakerIsActive(): continue return id # Nothing to do return None
import os from Experiment.sample import Sample from Experiment.experiment import Experiment from Experiment.experiment import Concentration e=Experiment() e.w.pyrun('PTC\\ptcsetpgm.py TEST TEMP@95,1 TEMP@25,1') e.runpgm("TEST",0,waitForCompletion=False) e.waitpgm(sanitize=False) e.savegem("platemovetest_orig.gem") os.system("grep -v 'Wash\|reagent tubes' platemovetest_orig.gem > platemovetest.gem")