Skip to content

Commit 93e254a

Browse files
committed
initial commit for "experiment" entity
1 parent fc21be0 commit 93e254a

File tree

5 files changed

+271
-0
lines changed

5 files changed

+271
-0
lines changed

taurus/entity/experiment/__init__.py

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from taurus.entity.base_entity import BaseEntity
2+
3+
from taurus.entity.template.base_template import BaseTemplate
4+
from taurus.entity.object.base_object import BaseObject
5+
6+
7+
class BaseExperiment(BaseEntity):
8+
"""An experiment is a collection of Taurus objects, with defined connections between them.
9+
"""
10+
11+
def __init__(self, objects, connections, uids, tags):
12+
BaseEntity.__init__(self, uids=uids, tags=tags)
13+
self._objects = None
14+
self._connections = None
15+
16+
self.objects = objects
17+
self.connections = connections
18+
19+
@property
20+
def objects(self):
21+
return self._objects
22+
23+
@objects.setter
24+
def objects(self, objects):
25+
for obj in objects.values():
26+
assert isinstance(obj, (BaseTemplate, BaseObject))
27+
self._objects = objects
28+
29+
@property
30+
def connections(self):
31+
return self._connections
32+
33+
@connections.setter
34+
def connections(self, connections):
35+
self._connections = connections # TODO: check all str in objects mapping
36+
37+
def visualize(self):
38+
"""Graphs the objects in this data model."""
39+
from dagre_py.core import plot
40+
nodes = [{"label": p} for p in self.templates.keys()]
41+
edges = [{"source": s, "target": t} for s, t in self.connections]
42+
plot({"nodes": nodes, "edges": edges})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from taurus.entity.experiment.base_experiment import BaseExperiment
2+
3+
4+
class ExperimentRun(BaseExperiment):
5+
"""An experiment run is a collection of Taurus run objects, with connections between them.
6+
"""
7+
8+
def __init__(self, objects, connections, uids, tags, spec):
9+
BaseExperiment.__init__(
10+
self, objects=objects, connections=connections, uids=uids, tags=tags
11+
)
12+
self._spec = None
13+
self.spec = spec
14+
15+
@property
16+
def spec(self):
17+
return self._spec
18+
19+
@spec.setter
20+
def spec(self, spec):
21+
from taurus.entity.experiment.spec import ExperimentSpec
22+
assert isinstance(spec, ExperimentSpec)
23+
self._spec = spec
24+
25+
@property
26+
def objects(self):
27+
return self._objects
28+
29+
@objects.setter
30+
def objects(self, objects):
31+
self._objects = objects # TODO: check all objects are runs
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from taurus.entity.experiment.base_experiment import BaseExperiment
2+
3+
4+
class ExperimentSpec(BaseExperiment):
5+
"""An experiment spec is a collection of Taurus spec objects, with connections between them.
6+
"""
7+
8+
def __init__(self, objects, connections, uids, tags, template):
9+
BaseExperiment.__init__(
10+
self, objects=objects, connections=connections, uids=uids, tags=tags
11+
)
12+
self._template = None
13+
self.template = template
14+
15+
@property
16+
def template(self):
17+
return self._template
18+
19+
@template.setter
20+
def template(self, template):
21+
from taurus.entity.experiment.template import ExperimentTemplate
22+
assert isinstance(template, ExperimentTemplate)
23+
self._template = template
24+
25+
@property
26+
def objects(self):
27+
return self._objects
28+
29+
@objects.setter
30+
def objects(self, objects):
31+
self._objects = objects # TODO: check all objects are specs
32+
33+
def __call__(self):
34+
"""Create a run state of this spec experiment."""
35+
from taurus.entity.experiment.run_experiment import ExperimentRun
36+
37+
runs = dict()
38+
connections = list()
39+
40+
return ExperimentRun(
41+
objects=runs,
42+
connections=connections,
43+
uids=self.uids,
44+
tags=self.tags,
45+
spec_experiment=self,
46+
)
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
from taurus.entity.template.base_template import BaseTemplate
2+
from taurus.entity.template.material_template import MaterialTemplate
3+
from taurus.entity.template.measurement_template import MeasurementTemplate
4+
from taurus.entity.template.process_template import ProcessTemplate
5+
6+
from taurus.entity.object.ingredient_spec import IngredientSpec
7+
8+
from taurus.entity.experiment.base_experiment import BaseExperiment
9+
10+
11+
class ExperimentTemplate(BaseExperiment):
12+
"""An experiment template is a collection of Taurus templates, with connections between them.
13+
"""
14+
15+
def __init__(self, objects, connections, uids, tags):
16+
BaseExperiment.__init__(
17+
self, objects=objects, connections=connections, uids=uids, tags=tags
18+
)
19+
20+
@property
21+
def objects(self):
22+
return self._objects
23+
24+
@objects.setter
25+
def objects(self, objects):
26+
for obj in objects.values():
27+
assert isinstance(obj, BaseTemplate)
28+
self._objects = objects
29+
30+
def __call__(self):
31+
"""Create a spec state of this template model."""
32+
from taurus.entity.experiment.experiment_spec import ExperimentSpec
33+
34+
specs = dict()
35+
connections = list()
36+
37+
# first, add processes to the specs collection
38+
for key, template in self.objects.items():
39+
if isinstance(template, ProcessTemplate):
40+
specs[key] = template() # creates a spec from template
41+
42+
# second, add materials which are linked to process specs
43+
for key, template in self.objects.items():
44+
if isinstance(template, MaterialTemplate):
45+
creating_process = [
46+
source for source, destination in self.connections if destination == key
47+
][0]
48+
specs[key] = template(process=specs[creating_process])
49+
connections.append((creating_process, key))
50+
51+
# third, add ingredients that feed into processes
52+
infered_ingredients = []
53+
for source, destination in self.connections:
54+
if isinstance(self.objects[source], MaterialTemplate) & isinstance(
55+
self.objects[destination], ProcessTemplate
56+
):
57+
infered_ingredients.append((source, destination))
58+
for material, process in infered_ingredients:
59+
ingredient_name = "ingredient: {}".format(material)
60+
specs[ingredient_name] = IngredientSpec(
61+
name=ingredient_name, material=specs[material], process=specs[process]
62+
)
63+
connections.append((material, ingredient_name))
64+
connections.append((ingredient_name, process))
65+
66+
# fourth, add measurements attached to materials
67+
for key, template in self.objects.items():
68+
if isinstance(template, MeasurementTemplate):
69+
specs[key] = template()
70+
71+
return ExperimentSpec(
72+
objects=specs,
73+
connections=connections,
74+
uids=self.uids,
75+
tags=self.tags,
76+
template_model=self,
77+
)
78+
79+
80+
if __name__ == "__main__":
81+
from taurus.entity.template.property_template import PropertyTemplate
82+
from taurus.entity.template.condition_template import ConditionTemplate
83+
from taurus.entity.template.parameter_template import ParameterTemplate
84+
85+
from taurus.entity.bounds.categorical_bounds import CategoricalBounds
86+
from taurus.entity.bounds.real_bounds import RealBounds
87+
88+
from taurus.util.impl import flatten
89+
90+
# property templates
91+
conductivity = PropertyTemplate(
92+
name="conductivity",
93+
bounds=RealBounds(lower_bound=0, upper_bound=100000, default_units="S/m"),
94+
)
95+
seebeck = PropertyTemplate(
96+
name="Seebeck", bounds=RealBounds(lower_bound=-500, upper_bound=500, default_units="uV/K"),
97+
)
98+
99+
# condition templates
100+
atmosphere = ConditionTemplate(name="atmosphere", bounds=CategoricalBounds(["air", "argon"]))
101+
pressure = ConditionTemplate(
102+
name="pressure", bounds=RealBounds(lower_bound=0, upper_bound=1, default_units="atm")
103+
)
104+
day_of_the_week = ConditionTemplate(
105+
name="day of the week", bounds=CategoricalBounds(["M", "T", "W", "Th", "F"])
106+
)
107+
108+
# parameter templates
109+
vendor = ParameterTemplate(
110+
name="vendor", bounds=CategoricalBounds(["alpha-aesar", "sigma-aldrich"])
111+
)
112+
field_strength = ParameterTemplate(
113+
name="field_strength", bounds=RealBounds(lower_bound=0, upper_bound=5, default_units="T"),
114+
)
115+
temperature = ParameterTemplate(
116+
name="temperaure", bounds=RealBounds(lower_bound=300, upper_bound=1000, default_units="K")
117+
)
118+
119+
# object templates
120+
material = MaterialTemplate(name="test material", properties=[conductivity, seebeck])
121+
measurement = MeasurementTemplate(
122+
name="test measurement",
123+
properties=[conductivity, seebeck],
124+
conditions=[atmosphere, pressure],
125+
parameters=[field_strength],
126+
)
127+
procure = ProcessTemplate(name="procure", conditions=[day_of_the_week], parameters=[vendor])
128+
heat_treat = ProcessTemplate(
129+
name="heat treat", conditions=[atmosphere], parameters=[temperature]
130+
)
131+
132+
templates = {
133+
"procure": procure,
134+
"initial_sample": material,
135+
"initial_measurement": measurement,
136+
"heat_treat": heat_treat,
137+
"treated_sample": material,
138+
"treated_measurement": measurement,
139+
}
140+
connections = [
141+
("procure", "initial_sample"),
142+
("initial_sample", "initial_measurement"),
143+
("initial_sample", "heat_treat"),
144+
("heat_treat", "treated_sample"),
145+
("treated_sample", "treated_measurement"),
146+
]
147+
148+
data_model = TemplateModel(templates=templates, connections=connections)
149+
data_model.visualize()
150+
151+
specs, connections = data_model.spec
152+
print(flatten(specs["treated_sample"]))

0 commit comments

Comments
 (0)