def find_by_location(self, location, return_one=True, require_hit=True): ''' TODO: Deal with whether to have a return one flag or always return an array. To accept a solution as a query or to require a naked location. I prefer to be able to have as much of the logic that is repeated across different protocols handled by the underlying framework and thus favor find(solution, by="location") or find(solution, by="components") over location=sample['container']['location']; find_by_location(location)[0]. ''' print location hits = list(self.db.find({'container.location': location})) if len(hits) > 1: print 'Found more than one DB entry for location query.' print 'Theres probably something wrong with your database.' hit = hits[0] if require_hit and (len(hits) == 0): raise Exception( 'Did not find DB hit for query with require_hit enabled.') stripped = strip_internal(hit) s = Solution(**stripped) s.update_units() # Note - this will fail if the thing being passed in # has a dna concentration of unknown or string None... return s
def find_by_location(self, location, return_one=True, require_hit=True): ''' TODO: Deal with whether to have a return one flag or always return an array. To accept a solution as a query or to require a naked location. I prefer to be able to have as much of the logic that is repeated across different protocols handled by the underlying framework and thus favor find(solution, by="location") or find(solution, by="components") over location=sample['container']['location']; find_by_location(location)[0]. ''' print location hits = list(self.db.find({'container.location': location})) if len(hits) > 1: print 'Found more than one DB entry for location query.' print 'Theres probably something wrong with your database.' hit = hits[0] if require_hit and (len(hits) == 0): raise Exception('Did not find DB hit for query with require_hit enabled.') stripped = strip_internal(hit) s = Solution(**stripped) s.update_units() # Note - this will fail if the thing being passed in # has a dna concentration of unknown or string None... return s
class Reaction(object): '''An individual reaction, which may be composed of multiple sub-reactions. ''' def __init__(self, reactions=None, module=None, inputs=None, outputs=None, solution=None, incubation=None, name=None, meta=None, params=None, constraints=None): self.reactions = reactions self.module = module self.inputs = inputs self.outputs = outputs self.name = name self.solution = solution self.incubation = incubation self.meta = meta self.params = params self.constraints = constraints if (solution is not None) and not isinstance(solution, Solution): self.solution = Solution(**solution) #print self.solution.components if self.solution.components is not None: self.solution.update_units() if isinstance(reactions, list): names = set() for i,r in enumerate(reactions): assert 'name' in r, 'Each reaction must have a name.' assert r['name'] not in names, 'Found two reactions with the same name.' names.add(r['name']) self.reactions[i] = Reaction(**r) if params is not None: self.params = make_dottable_dict(params) if inputs is not None: if not isinstance(inputs, list): inputs = [inputs] for i, ipt in enumerate(inputs): assert isinstance(ipt, dict), 'Reaction object tried to load an input but was passed something other than a dict: ' + str(ipt) assert ('container' in ipt) and ('location' in ipt['container']), 'an input must have a container and location' def named(self, name): if isinstance(self.reactions, list): for i,r in enumerate(self.reactions): assert hasattr(r, 'name'), 'Found reaction without a name when looking for named reaction.' if r.name == name: return r return None
def test_build_component_index(self): s = Solution(**self.d) s.build_component_index() assert s.comp_index == { 'CHEBI:1234': 0, 'CHEBI:9123': 2, 'CHEBI:5678': 1 }
def __init__(self, reactions=None, module=None, inputs=None, outputs=None, solution=None, incubation=None, name=None, meta=None, params=None, constraints=None): self.reactions = reactions self.module = module self.inputs = inputs self.outputs = outputs self.name = name self.solution = solution self.incubation = incubation self.meta = meta self.params = params self.constraints = constraints if (solution is not None) and not isinstance(solution, Solution): self.solution = Solution(**solution) #print self.solution.components if self.solution.components is not None: self.solution.update_units() if isinstance(reactions, list): names = set() for i, r in enumerate(reactions): assert 'name' in r, 'Each reaction must have a name.' assert r[ 'name'] not in names, 'Found two reactions with the same name.' names.add(r['name']) self.reactions[i] = Reaction(**r) if params is not None: self.params = make_dottable_dict(params) if inputs is not None: if not isinstance(inputs, list): inputs = [inputs] for i, ipt in enumerate(inputs): assert isinstance( ipt, dict ), 'Reaction object tried to load an input but was passed something other than a dict: ' + str( ipt) assert ('container' in ipt) and ( 'location' in ipt['container'] ), 'an input must have a container and location'
def test_compatible(self): s = Solution(**self.d) s2 = Solution(components=[{'classification':{'CHEBI':'1234'}, 'concentration':1 * ureg.molar}], container={"ctype":"micro-1.5"}, volume=1*ureg.milliliter) s3 = Solution(components=[{'classification':{'CHEBI':'1234'}, 'concentration':1 * ureg.units}], container={"ctype":"micro-1.5"}, volume=1*ureg.milliliter) assert s.compatible(s2) == True assert s.compatible(s3) == False
def test_lazy_ref(self): tc = TestContext() s = Solution(**{ "container": { "location": "1234:transcriptic", "ctype": "96-pcr" } }) ref = tc.env.lazy_ref(s)
def test_add(self): s = Solution(**self.d) s2 = Solution(components=[{ 'classification': { 'CHEBI': '1234' }, 'concentration': 2 * ureg.micromolar }], container={"ctype": "micro-1.5"}, volume=1 * ureg.milliliter) s.add(s2, 10 * ureg.microliter) assert (s.components[0]['concentration'] - 1.01 * ureg.micromolar) < 0.001 * ureg.micromolar s3 = Solution(volume=1 * ureg.liter) s3.add(s2, 10 * ureg.microliter)
def test_compatible(self): s = Solution(**self.d) s2 = Solution(components=[{ 'classification': { 'CHEBI': '1234' }, 'concentration': 1 * ureg.molar }], container={"ctype": "micro-1.5"}, volume=1 * ureg.milliliter) s3 = Solution(components=[{ 'classification': { 'CHEBI': '1234' }, 'concentration': 1 * ureg.units }], container={"ctype": "micro-1.5"}, volume=1 * ureg.milliliter) assert s.compatible(s2) == True assert s.compatible(s3) == False
def test_add(self): s = Solution(**self.d) s2 = Solution(components=[{'classification':{'CHEBI':'1234'}, 'concentration':2 * ureg.micromolar}], container={"ctype":"micro-1.5"}, volume=1*ureg.milliliter) s.add(s2, 10 * ureg.microliter) assert (s.components[0]['concentration'] - 1.01*ureg.micromolar) < 0.001*ureg.micromolar s3 = Solution(volume=1*ureg.liter) s3.add(s2, 10*ureg.microliter)
def setUp(self): self.rxn = { "meta": [ "type:enzymatic", "sensitivity:temperature,ph", "amplifies:dna", "named:pcr" ], "params": { "reagent_thaw_time": "10:minute", "reagent_thaw_temp": "ambient", "initial_temp": "94:celsius", "initial_time": "120:second", "extension_temp": "72:celsius", "extension_time": "90:second", "annealing_temp": "55:celsius", "annealing_time": "60:second", "melting_temp": "94:celsius", "melting_time": "45:second", "final_step_temp": "72:celsius", "final_step_time": "600:second", "hold_temp": "8:celsius", "hold_time": "600:second", "cycles": 30 }, "solution": { "components": [{ "_reference": "primer_f", "classification": { "CHEBI": "double-stranded_dna", "target": "515:16s", "orientation": "f" }, "concentration": 200 * ureg.nanomolar }, { "_reference": "primer_r", "classification": { "CHEBI": "double-stranded_dna", "target": "806:16s", "orientation": "r" }, "concentration": 200 * ureg.nanomolar }, { "_reference": "template_dna", "concentration": 2 * ureg.ng / ureg.microliter, "_type": "user_specified", "classification": { "CHEBI": "double-stranded_dna" } }, { "_reference": "pcr_master_mix", "classification": { "model": "11306-016", "supplier": "invitrogen" }, "concentration": 0.9 * ureg.x }, { "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore": True }], "volume": 200 * ureg.microliter }, "constraints": [ "glycerol:concentration:<:0.1:nM", "ph:range:6.5:7.5", ":auto_constraints" ], "inputs": [{ "_reference": "template_dna", "location": "ct177en2w6ggxv:transcriptic", "name": "seadna_oct" }] } self.target_solution = Solution(**self.rxn['solution']) self.input_solution_1 = Solution( **{ "components": [ { "_reference": "primer_f", "classification": { "CHEBI": "double-stranded_dna", "target": "515:16s", "orientation": "f" }, "concentration": 1000 * ureg.nanomolar }, ], "container": { "ctype": "micro-1.5", "location": "1234:transcriptic" }, "volume": 55 * ureg.microliter }) self.input_solution_2 = Solution( **{ "components": [{ "_reference": "primer_r", "classification": { "CHEBI": "double-stranded_dna", "target": "806:16s", "orientation": "r" }, "concentration": 1000 * ureg.nanomolar }], "container": { "ctype": "micro-1.5", "location": "456:transcriptic" }, "volume": 55 * ureg.microliter }) ''' self.input_solution_3 = Solution(**{"components": [{ "_reference": "template_dna", "concentration": 4*ureg.nanograms/ureg.microliter, "classification": {"CHEBI":"double-stranded_dna"} } ], "container":{"ctype":"micro-1.5", "location":"789:transcriptic"}, "volume": 55*ureg.microliter}) ''' self.input_solution_4 = Solution( **{ "components": [{ "_reference": "pcr_master_mix", "classification": { "model": "11306-016", "supplier": "invitrogen" }, "concentration": 4 * ureg.x }], "container": { "ctype": "micro-1.5", "location": "654:transcriptic" }, "volume": 55 * ureg.microliter }) self.diluent = Solution( **{ "components": [{ "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore_concentration": True }], "container": { "ctype": "micro-1.5", "location": "321:transcriptic" }, "volume": 200 * ureg.microliter }) self.diluent2 = Solution( **{ "components": [{ "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore_concentration": True }], "container": { "ctype": "micro-1.5", "location": "321:transcriptic" }, "volume": 200 * ureg.microliter }) self.sample = Solution( **{ "components": [{ "classification": { "CHEBI": "double-stranded_dna" }, "concentration": 40 * ureg.nanograms / ureg.ul, }], "container": { "ctype": "micro-1.5", "location": "987:transcriptic" }, "volume": 55 * ureg.microliter }) self.solution_set = [ self.input_solution_1, self.input_solution_2, #self.input_solution_3, self.input_solution_4, self.sample, self.diluent, self.diluent2 ]
def find_solution_set(self, components, return_one=False, require_hit=False): print components from pcompile.helper import unserialize all_hits = {} filt = [ 'unknown', 'Unknown', 'unknown:micromolar', 'Unknown:micromolar', '?:x' ] # For now, it will ignore any hit with a concentration or component concentration # of one of the above types. for comp in components: query = dict_to_str(strip_internal(comp)) classif = dict_to_str(strip_internal(comp))['classification'] sol_query = {'classification': classif} comp_query = { 'components': { '$elemMatch': { 'classification': classif } } } query = {'$or': [sol_query, comp_query]} hits = self.db.find(query) for hit in hits: unique_identifier = hit['_id'] if unique_identifier not in all_hits: if hit['concentration'] not in filt: f = 0 #for hitcomp in hit['components']: # print hitcomp # if hitcomp['concentration'] in filt: # f=0 if f == 0: hit_stripped = strip_internal(hit) all_hits[unique_identifier] = Solution( **hit_stripped) print all_hits[unique_identifier].name print all_hits[unique_identifier].components all_hits[unique_identifier].update_units() if require_hit and (len(all_hits.values()) == 0): raise Exception( 'Did not find DB hit for query with require_hit enabled.') if (return_one) and (len(all_hits.values()) >= 1): return all_hits.values()[0] else: return all_hits.values()
def step(env, rxn, inputs=None): '''Pipette colored liquid into a plate to reproduce a jpeg''' env.rprotocol.step( 'jpeg', 'Pipette colored liquid into a plate to reproduce a jpeg.') jpg = rxn.reactions[0] template = jpg.solution red = Solution(components=[ { "classification": { "color": "red" }, "concentration": 100 * ureg.percent }, { "classification": { "color": "green" }, "concentration": 0 * ureg.percent }, { "classification": { "color": "blue" }, "concentration": 0 * ureg.percent }, ], volume=5 * ureg.milliliters, container={"location": "red"}) green = Solution(components=[ { "classification": { "color": "red" }, "concentration": 100 * ureg.percent }, { "classification": { "color": "green" }, "concentration": 0 * ureg.percent }, { "classification": { "color": "blue" }, "concentration": 0 * ureg.percent }, ], volume=5 * ureg.milliliters, container={"location": "green"}) blue = Solution(components=[ { "classification": { "color": "red" }, "concentration": 100 * ureg.percent }, { "classification": { "color": "green" }, "concentration": 0 * ureg.percent }, { "classification": { "color": "blue" }, "concentration": 0 * ureg.percent }, ], volume=5 * ureg.milliliters, container={"location": "blue"}) water = Solution(components=[ { "classification": { "color": "red" }, "concentration": 0 * ureg.percent }, { "classification": { "color": "green" }, "concentration": 0 * ureg.percent }, { "classification": { "color": "blue" }, "concentration": 0 * ureg.percent }, ], volume=5 * ureg.milliliters, container={"location": "water"}) with open(rxn.params.colorsfile, 'r') as f: colors = json.loads(f.read())['colors'] # colors as fractions, in json for c in colors: c = 100 * np.array(c, dtype=float) / 255 splan = SolutionPlan(target_solution=Solution(components=[ { "classification": { "color": "red" }, "concentration": c[0] * ureg.percent }, { "classification": { "color": "green" }, "concentration": c[1] * ureg.percent }, { "classification": { "color": "blue" }, "concentration": c[2] * ureg.percent }, ], volume=150 * ureg.microliter)) splan.solutions = [red, green, blue, water] splan.solve() splan.compile(env) #c = np.array(c, dtype=float) #dest = walloc(env, template) #volumes = (c / 255.0) * template.volume #for source, vol in zip((red,green,blue), volumes): # pipette(env, source, vol, dest) #pipette(env, water, (template.volume - sum(volumes)), dest) return 1
def __init__(self): testdir = os.path.expanduser(os.path.join('~/.hyper', 'test')) json_path = os.path.join(testdir, 'proto_config.json') self.json_path = json_path os.system('mkdir -p ' + testdir) # This should be loaded from a file... with open(os.path.expanduser(json_path), 'w') as f: f.write( json.dumps({ "reactions": [{ "meta": [ "type:enzymatic", "sensitivity:temperature,ph", "amplifies:dna", "named:pcr" ], "params": { "reagent_thaw_time": "10:minute", "reagent_thaw_temp": "ambient", "initial_temp": "94:celsius", "initial_time": "120:second", "extension_temp": "72:celsius", "extension_time": "90:second", "annealing_temp": "55:celsius", "annealing_time": "60:second", "melting_temp": "94:celsius", "melting_time": "45:second", "final_step_temp": "72:celsius", "final_step_time": "600:second", "hold_temp": "8:celsius", "hold_time": "600:second", "cycles": 30 }, "solution": { "components": [{ "_reference": "primer_f", "classification": { "CHEBI": "double-stranded_dna", "target": "515:16s", "orientation": "f" }, "concentration": "200:nanomolar" }, { "_reference": "primer_r", "classification": { "CHEBI": "double-stranded_dna", "target": "806:16s", "orientation": "r" }, "concentration": "200:nanomolar" }, { "_reference": "template_dna", "concentration": "2:ng/microliter", "_type": "user_specified", "classification": { "CHEBI": "double-stranded_dna" } }, { "_reference": "pcr_master_mix", "classification": { "model": "11306-016", "supplier": "invitrogen" }, "concentration": "0.9:x" }, { "classification": { "CHEBI": "water" }, "concentration": "55:mol/liter", "_ignore": "True" }], "volume": "55:microliter" }, "constraints": [ "glycerol:concentration:<:0.1:nM", "ph:range:6.5:7.5", ":auto_constraints" ], "inputs": [{ "_reference": "template_dna", "container": { "location": "ct177en2w6ggxv:transcriptic" }, "name": "seadna_oct" }] }] })) self.reactions = simplejson.loads( open(json_path, 'r').read().decode("utf-8")) self.env = Environment(self.reactions) self.diluent = Solution( **{ "components": [{ "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore_concentration": True }], "container": { "ctype": "micro-1.5", "location": "321:transcriptic" }, "volume": 200 * ureg.microliter }) self.rxn2 = { "meta": [ "type:enzymatic", "sensitivity:temperature,ph", "amplifies:dna", "named:pcr" ], "params": { "reagent_thaw_time": "10:minute", "reagent_thaw_temp": "ambient", "initial_temp": "94:celsius", "initial_time": "120:second", "extension_temp": "72:celsius", "extension_time": "90:second", "annealing_temp": "55:celsius", "annealing_time": "60:second", "melting_temp": "94:celsius", "melting_time": "45:second", "final_step_temp": "72:celsius", "final_step_time": "600:second", "hold_temp": "8:celsius", "hold_time": "600:second", "cycles": 30 }, "solution": { "components": [{ "_reference": "primer_f", "classification": { "CHEBI": "double-stranded_dna", "target": "515:16s", "orientation": "f" }, "concentration": 200 * ureg.nanomolar }, { "_reference": "primer_r", "classification": { "CHEBI": "double-stranded_dna", "target": "806:16s", "orientation": "r" }, "concentration": 200 * ureg.nanomolar }, { "_reference": "template_dna", "concentration": 2 * ureg.ng / ureg.microliter, "_type": "user_specified", "classification": { "CHEBI": "double-stranded_dna" } }, { "_reference": "pcr_master_mix", "classification": { "model": "11306-016", "supplier": "invitrogen" }, "concentration": 0.9 * ureg.x }, { "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore": True }], "volume": 200 * ureg.microliter }, "constraints": [ "glycerol:concentration:<:0.1:nM", "ph:range:6.5:7.5", ":auto_constraints" ], "inputs": [{ "container": { "location": "ct177en2w6ggxv:transcriptic" }, "classification": "double-stranded_DNA" }] } self.target_solution = Solution(**self.rxn2['solution']) self.input_solution_1 = Solution( **{ "components": [ { "_reference": "primer_f", "classification": { "CHEBI": "double-stranded_dna", "target": "515:16s", "orientation": "f" }, "concentration": 1000 * ureg.nanomolar }, ], "container": { "ctype": "micro-1.5", "location": "1234:transcriptic" }, "volume": 55 * ureg.microliter }) self.input_solution_2 = Solution( **{ "components": [{ "_reference": "primer_r", "classification": { "CHEBI": "double-stranded_dna", "target": "806:16s", "orientation": "r" }, "concentration": 1000 * ureg.nanomolar }], "container": { "ctype": "micro-1.5", "location": "456:transcriptic" }, "volume": 55 * ureg.microliter }) ''' self.input_solution_3 = Solution(**{"components": [{ "_reference": "template_dna", "concentration": 4*ureg.nanograms/ureg.microliter, "classification": {"CHEBI":"double-stranded_dna"} } ], "container":{"ctype":"micro-1.5", "location":"789:transcriptic"}, "volume": 55*ureg.microliter}) ''' self.input_solution_4 = Solution( **{ "components": [{ "_reference": "pcr_master_mix", "classification": { "model": "11306-016", "supplier": "invitrogen" }, "concentration": 4 * ureg.x }], "container": { "ctype": "micro-1.5", "location": "654:transcriptic" }, "volume": 55 * ureg.microliter }) self.diluent = Solution( **{ "components": [{ "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore_concentration": True }], "container": { "ctype": "micro-1.5", "location": "321:transcriptic" }, "volume": 200 * ureg.microliter }) self.diluent2 = Solution( **{ "components": [{ "classification": { "CHEBI": "water" }, "concentration": 55 * ureg.mol / ureg.liter, "_ignore_concentration": True }], "container": { "ctype": "micro-1.5", "location": "321:transcriptic" }, "volume": 200 * ureg.microliter }) self.sample = Solution( **{ "components": [{ "classification": { "CHEBI": "double-stranded_dna" }, "concentration": 40 * ureg.nanograms / ureg.ul, }], "container": { "ctype": "micro-1.5", "location": "987:transcriptic" }, "volume": 55 * ureg.microliter }) self.solution_set = [ self.input_solution_1, self.input_solution_2, #self.input_solution_3, self.input_solution_4, self.sample, self.diluent, self.diluent2 ]
def test_init_from_dict(self): s = Solution(components=[]) image = Solution(**self.d).to_dict() assert image == self.d
def test_build_component_index(self): s = Solution(**self.d) s.build_component_index() assert s.comp_index == {'CHEBI:1234': 0, 'CHEBI:9123': 2, 'CHEBI:5678': 1}
def test_dist(self): #A distance measure for comparing solution objects, specifically #for use in the non-constraint, component-only portion of solution #optimization. s1 = Solution(**self.d) s2 = Solution(**self.d1) s3 = Solution(**self.d2) # Coincidence, non-negativity assert s1.dist(s2) == 0 assert s1.dist(s1) == 0 s1.add(s1, 1*ureg.microliter) assert s1.dist(s2) < 0.00001 s2.add(s3, 1 * ureg.microliter) assert s1.dist(s2) > 0 # Symmetry assert (s1.dist(s2) - s2.dist(s1)) < 0.00001 # Triangle inequality s3.add(s1, 10 * ureg.microliter) s3.add(s2, 10 * ureg.microliter) assert s3.dist(s2) <= s3.dist(s1) + s1.dist(s2)
def test_remove(self): s = Solution(**self.d) s.volume=10*ureg.microliter s.remove(1*ureg.microliter) assert s.volume == 9*ureg.microliter
def test_dist(self): #A distance measure for comparing solution objects, specifically #for use in the non-constraint, component-only portion of solution #optimization. s1 = Solution(**self.d) s2 = Solution(**self.d1) s3 = Solution(**self.d2) # Coincidence, non-negativity assert s1.dist(s2) == 0 assert s1.dist(s1) == 0 s1.add(s1, 1 * ureg.microliter) assert s1.dist(s2) < 0.00001 s2.add(s3, 1 * ureg.microliter) assert s1.dist(s2) > 0 # Symmetry assert (s1.dist(s2) - s2.dist(s1)) < 0.00001 # Triangle inequality s3.add(s1, 10 * ureg.microliter) s3.add(s2, 10 * ureg.microliter) assert s3.dist(s2) <= s3.dist(s1) + s1.dist(s2)
def test_remove(self): s = Solution(**self.d) s.volume = 10 * ureg.microliter s.remove(1 * ureg.microliter) assert s.volume == 9 * ureg.microliter