def __init__(self, name: str, uids: Optional[Dict[str, str]] = None, tags: Optional[List[str]] = None, notes: Optional[str] = None, conditions: Optional[List[Condition]] = None, parameters: Optional[List[Parameter]] = None, template: Optional[TaurusMeasurementTemplate] = None, file_links: Optional[List[FileLink]] = None): DataConcepts.__init__(self, TaurusMeasurementSpec.typ) TaurusMeasurementSpec.__init__(self, name=name, uids=set_default_uid(uids), tags=tags, conditions=conditions, parameters=parameters, template=template, file_links=file_links, notes=notes)
def test_template_access(): """A measurement run's template should be equal to its spec's template.""" template = MeasurementTemplate("measurement template", uids={'id': str(uuid4())}) spec = MeasurementSpec("A spec", uids={'id': str(uuid4())}, template=template) meas = MeasurementRun("A run", uids={'id': str(uuid4())}, spec=spec) assert meas.template == template meas.spec = LinkByUID.from_entity(spec) assert meas.template is None
def test_measurement_spec(): """Test the measurement spec/run connection survives ser/de.""" condition = Condition(name="Temp condition", value=NominalReal(nominal=298, units='kelvin')) parameter = Parameter(name="Important parameter") spec = MeasurementSpec(name="Precise way to do a measurement", parameters=parameter, conditions=condition) # Create a measurement run from this measurement spec measurement = MeasurementRun(conditions=condition, spec=spec) copy = loads(dumps(measurement)) assert dumps(copy.spec) == dumps(measurement.spec), \ "Measurement spec should be preserved if measurement run is serialized"
def test_make_instance(): """Build up several linked objects and test their properties.""" msr_spec = MeasurementSpec() assert isinstance(make_instance(msr_spec), MeasurementRun) mat_spec = MaterialSpec(name='Mat name') mat_spec.process = ProcessSpec(name='Pro name') IngredientSpec(name='Ing label', process=mat_spec.process) mat_spec.process.ingredients[0].material = MaterialSpec(name='Baby mat name') mat_run = make_instance(mat_spec) assert isinstance(mat_run, MaterialRun) assert isinstance(mat_run.process, ProcessRun) assert isinstance(mat_run.process.ingredients[0], IngredientRun) assert isinstance(mat_run.process.ingredients[0].material, MaterialRun) assert mat_run.process.spec == mat_run.spec.process ingredient = mat_run.process.ingredients[0] assert ingredient.spec == mat_run.spec.process.ingredients[0] assert ingredient.material.spec == mat_run.spec.process.ingredients[0].material
def make_strehlow_objects(table=None): """Make a table with Strehlow & Cook data.""" tmpl = make_templates() if table is None: table = import_table() # Specs msr_spec = MeasurementSpec(name='Band gap', template=tmpl["Band gap measurement"]) def real_mapper(prop): """Mapping methods for RealBounds.""" if 'uncertainty' in prop['scalars'][0]: val = NormalReal(mean=float(prop['scalars'][0]['value']), units=prop['units'], std=float(prop['scalars'][0]['uncertainty'])) else: val = NominalReal(nominal=float(prop['scalars'][0]['value']), units=prop['units']) return val content_map = { RealBounds: real_mapper, CategoricalBounds: lambda prop: NominalCategorical(category=prop['scalars'][0]['value']), type(None): lambda bnd: 'Label' } datapoints = [] compounds = dict() for row in table: formula = formula_clean(row['chemicalFormula']) spec = compounds.get( formula, MaterialSpec(name=formula_latex(formula), template=tmpl["Chemical"], process=ProcessSpec( name="Sample preparation", template=tmpl["Sample preparation"]))) run = make_instance(spec) datapoints.append(run) if not spec.properties: spec.properties.append( PropertyAndConditions(property=Property( name=spec.template.properties[0][0].name, value=EmpiricalFormula(formula=formula), template=spec.template.properties[0][0]))) msr = make_instance(msr_spec) msr.material = run # 2 categories in the PIF need to be split to avoid repeat Attribute Templates in a Run name_map = {'Phase': 'Crystal system', 'Transition': 'Bands'} origin_map = { 'EXPERIMENTAL': Origin.MEASURED, 'COMPUTATIONAL': Origin.COMPUTED } seen = set( ) # Some conditions come in from multiple properties on the same object for prop in row['properties']: origin = origin_map.get(prop.get('dataType', None), Origin.UNKNOWN) if 'method' in prop: method = 'Method: ' + prop['method']['name'] else: method = 'Method: unreported' for attr in [prop] + prop.get('conditions', []): if attr['name'] in seen: # Early return if it's a repeat continue seen.add(attr['name']) template = tmpl[attr['name']] # Figure out if we need to split this column if attr['name'] in name_map: value = attr['scalars'][0]['value'] if value not in template.bounds.categories: template = tmpl[name_map[attr['name']]] # Move into GEMD structure if type(template) == PropertyTemplate: msr.properties.append( Property(name=template.name, template=template, value=content_map[type( template.bounds)](attr), origin=origin, notes=method)) elif type(template) == ConditionTemplate: msr.conditions.append( Condition(name=template.name, template=template, value=content_map[type( template.bounds)](attr), origin=origin, notes=method)) return datapoints
def make_cake(seed=None): """Define all objects that go into making a demo cake.""" if seed is not None: random.seed(seed) ###################################################################### # Parent Objects tmpl = make_cake_templates() cake_spec = make_cake_spec() ###################################################################### # Objects cake = make_instance(cake_spec) operators = ['gwash', 'jadams', 'thomasj', 'jmadison', 'jmonroe'] cake.process.source = PerformedSource(performed_by=random.choice(operators), performed_date='2015-03-14') # Replace Abstract/In General queue = [cake] while queue: item = queue.pop(0) item.name = item.name.replace('Abstract ', '').replace(', in General', '') if item.spec.tags is not None: item.tags = list(item.spec.tags) if item.spec.notes: # None or empty string item.notes = 'The spec says "{}"'.format(item.spec.notes) if isinstance(item, MaterialRun): queue.append(item.process) elif isinstance(item, ProcessRun): queue.extend(item.ingredients) if item.template.name == "Procurement": item.source = PerformedSource(performed_by='hamilton', performed_date='2015-02-17') else: item.source = cake.process.source elif isinstance(item, IngredientRun): queue.append(item.material) fuzz = 0.95 + 0.1 * random.random() if item.spec.absolute_quantity is not None: item.absolute_quantity = \ NormalReal(mean=fuzz * item.spec.absolute_quantity.nominal, std=0.05 * item.spec.absolute_quantity.nominal, units=item.spec.absolute_quantity.units) if item.spec.volume_fraction is not None: item.volume_fraction = \ NormalReal(mean=fuzz * item.spec.volume_fraction.nominal, std=0.05 * item.spec.volume_fraction.nominal, units=item.spec.volume_fraction.units) if item.spec.mass_fraction is not None: item.mass_fraction = \ UniformReal(lower_bound=(fuzz - 0.05) * item.spec.mass_fraction.nominal, upper_bound=(fuzz + 0.05) * item.spec.mass_fraction.nominal, units=item.spec.mass_fraction.units) if item.spec.number_fraction is not None: item.number_fraction = \ NormalReal(mean=fuzz * item.spec.number_fraction.nominal, std=0.05 * item.spec.number_fraction.nominal, units=item.spec.number_fraction.units) else: raise TypeError("Unexpected object in the queue") frosting = \ next(x.material for x in cake.process.ingredients if 'rosting' in x.name) baked = \ next(x.material for x in cake.process.ingredients if 'aked' in x.name) # Add measurements cake_taste = MeasurementRun(name='Final Taste', material=cake) cake_appearance = MeasurementRun(name='Final Appearance', material=cake) frosting_taste = MeasurementRun(name='Frosting Taste', material=frosting) frosting_sweetness = MeasurementRun(name='Frosting Sweetness', material=frosting) # and spec out the measurements cake_taste.spec = MeasurementSpec(name='Taste') cake_appearance.spec = MeasurementSpec(name='Appearance') frosting_taste.spec = cake_taste.spec # Taste frosting_sweetness.spec = MeasurementSpec(name='Sweetness') ###################################################################### # Let's add some attributes baked.process.conditions.append(Condition(name='Cooking time', template=tmpl['Cooking time'], origin=Origin.MEASURED, value=NominalReal(nominal=48, units='min'))) baked.spec.process.conditions.append(Condition(name='Cooking time', template=tmpl['Cooking time'], origin=Origin.SPECIFIED, value=NormalReal(mean=50, std=5, units='min'))) baked.process.conditions.append(Condition(name='Oven temperature', origin="measured", value=NominalReal(nominal=362, units='degF'))) baked.spec.process.parameters.append(Parameter(name='Oven temperature setting', template=tmpl['Oven temperature setting'], origin="specified", value=NominalReal(nominal=350, units='degF'))) cake_taste.properties.append(Property(name='Tastiness', origin=Origin.MEASURED, template=tmpl['Tastiness'], value=NominalInteger(nominal=5))) cake_appearance.properties.append(Property(name='Visual Appeal', origin=Origin.MEASURED, value=NominalInteger(nominal=5))) frosting_taste.properties.append(Property(name='Tastiness', origin=Origin.MEASURED, template=tmpl['Tastiness'], value=NominalInteger(nominal=4))) frosting_sweetness.properties.append(Property(name='Sweetness (Sucrose-basis)', origin=Origin.MEASURED, value=NominalReal(nominal=1.7, units=''))) baked.process.spec.template = tmpl['Baking in an oven'] cake_taste.spec.template = tmpl['Taste test'] frosting_taste.spec.template = tmpl['Taste test'] cake.spec.template = tmpl['Dessert'] frosting.spec.template = tmpl['Dessert'] # Code to force all scopes to 'id' set_uuids([cake, cake_taste, cake_appearance, frosting_taste, frosting_sweetness], name='id') id_queue = [x for x in cake.process.ingredients] while id_queue: x = id_queue.pop(0) set_uuids([x], name='id') id_queue += x.material.process.ingredients return cake