def test_is_limiting(self): self.assertTrue( message_helpers.build_compound(is_limiting=True).is_limiting) self.assertFalse( message_helpers.build_compound(is_limiting=False).is_limiting) self.assertFalse( message_helpers.build_compound().HasField('is_limiting'))
def test_set_solute_moles(self): solute = message_helpers.build_compound(name='Solute') solvent2 = message_helpers.build_compound(name='Solvent', amount='100 mL') message_helpers.set_solute_moles(solute, [solvent2], '1 molar') self.assertEqual(solute.amount.moles, reaction_pb2.Moles(units='MILLIMOLE', value=100)) solvent3 = message_helpers.build_compound(name='Solvent', amount='75 uL') message_helpers.set_solute_moles(solute, [solvent3], '3 mM', overwrite=True) self.assertEqual(solute.amount.moles, reaction_pb2.Moles(units='NANOMOLE', value=225)) solvent4 = message_helpers.build_compound(name='Solvent', amount='0.2 uL') message_helpers.set_solute_moles(solute, [solvent4], '30 mM', overwrite=True) self.assertEqual(solute.amount.moles, reaction_pb2.Moles(units='NANOMOLE', value=6)) solvent5 = message_helpers.build_compound(name='Solvent', amount='0.8 uL') message_helpers.set_solute_moles(solute, [solvent4, solvent5], '30 mM', overwrite=True) self.assertEqual(solute.amount.moles, reaction_pb2.Moles(units='NANOMOLE', value=30))
def test_set_solute_moles_should_fail(self): solute = message_helpers.build_compound(name='Solute') solvent = message_helpers.build_compound(name='Solvent') with self.assertRaisesRegex(ValueError, 'defined volume'): message_helpers.set_solute_moles(solute, [solvent], '10 mM') solute = message_helpers.build_compound(name='Solute', amount='1 mol') solvent = message_helpers.build_compound(name='Solvent', amount='1 L') with self.assertRaisesRegex(ValueError, 'overwrite'): message_helpers.set_solute_moles(solute, [solvent], '10 mM')
def test_is_limiting(self): self.assertTrue( message_helpers.unconvert_boolean( message_helpers.build_compound(is_limiting=True).is_limiting)) self.assertFalse( message_helpers.unconvert_boolean( message_helpers.build_compound(is_limiting=False).is_limiting)) self.assertEqual( message_helpers.unconvert_boolean( message_helpers.build_compound().is_limiting), None)
def test_smiles_and_name(self): compound = message_helpers.build_compound(smiles='c1ccccc1', name='benzene') expected = reaction_pb2.Compound(identifiers=[ reaction_pb2.CompoundIdentifier(value='c1ccccc1', type='SMILES'), reaction_pb2.CompoundIdentifier(value='benzene', type='NAME') ]) self.assertEqual(compound, expected)
def resolve_input(input_string): """Resolve a text-based description of an input in one of the following formats: (1) [AMOUNT] of [NAME] (2) [AMOUNT] of [CONCENTRATION] [SOLUTE] in [SOLVENT] Args: input_string: String describing the input. Returns: ReactionInput message. Raises: ValueError: if the string cannot be parsed properly. """ reaction_input = reaction_pb2.ReactionInput() if ' of ' not in input_string: raise ValueError('String does not match template!') amount_string, description = input_string.split(' of ') if ' in ' not in description: component_name = description component = reaction_input.components.add() component.CopyFrom( message_helpers.build_compound(name=component_name.strip(), amount=amount_string)) resolve_names(reaction_input) return reaction_input pattern = re.compile(r'(\d+.?\d*)\s?(\w+)\s(.+)\sin\s(.+)') match = pattern.fullmatch(description.strip()) if not match: raise ValueError('String did not match template!') conc_value, conc_units, solute_name, solvent_name = match.groups() solute = reaction_input.components.add() solvent = reaction_input.components.add() solute.CopyFrom(message_helpers.build_compound(name=solute_name.strip())) solvent.CopyFrom( message_helpers.build_compound(name=solvent_name.strip(), amount=amount_string)) if solvent.amount.WhichOneof('kind') != 'volume': raise ValueError('Total amount of solution must be a volume!') solvent.amount.volume_includes_solutes = True message_helpers.set_solute_moles(solute, [solvent], f'{conc_value} {conc_units}') resolve_names(reaction_input) return reaction_input
def test_get_compound_mol(self): mol = Chem.MolFromSmiles('c1ccccc1') compound = message_helpers.build_compound(smiles='c1ccccc1', name='benzene') identifier = compound.identifiers.add() identifier.type = identifier.RDKIT_BINARY identifier.bytes_value = mol.ToBinary() self.assertEqual( Chem.MolToSmiles(mol), Chem.MolToSmiles(message_helpers.get_compound_mol(compound)))
def reaction() -> reaction_pb2.Reaction: resolver = units.UnitResolver() reaction = reaction_pb2.Reaction() reaction.setup.is_automated = True reaction.inputs["dummy_input"].components.add().CopyFrom( message_helpers.build_compound( name="n-hexane", smiles="CCCCCC", role="reactant", amount="1 milliliters", ) ) reaction.inputs["dummy_input"].components.add().CopyFrom( message_helpers.build_compound( name="THF", smiles="C1OCCC1", role="solvent", amount="40 liters", ) ) reaction.inputs["dummy_input2"].components.add().CopyFrom( message_helpers.build_compound( name="Pd", smiles="[Pd]", role="catalyst", amount="catalytic", ) ) reaction.conditions.pressure.atmosphere.type = reaction_pb2.PressureConditions.Atmosphere.OXYGEN reaction.conditions.stirring.rate.rpm = 100 reaction.conditions.temperature.control.type = reaction_pb2.TemperatureConditions.TemperatureControl.OIL_BATH reaction.conditions.temperature.setpoint.CopyFrom( reaction_pb2.Temperature(value=100, units=reaction_pb2.Temperature.CELSIUS) ) outcome = reaction.outcomes.add() outcome.reaction_time.CopyFrom(resolver.resolve("40 minutes")) outcome.products.add().identifiers.extend( message_helpers.build_compound(name="hexanone", smiles="CCCCC(=O)C").identifiers ) yield reaction
def setUp(self): super().setUp() self.test_subdirectory = tempfile.mkdtemp(dir=flags.FLAGS.test_tmpdir) self._resolver = units.UnitResolver() reaction = reaction_pb2.Reaction() reaction.setup.is_automated = True reaction.inputs['dummy_input'].components.add().CopyFrom( message_helpers.build_compound( name='n-hexane', smiles='CCCCCC', role='reactant', amount='1 milliliters', )) reaction.inputs['dummy_input'].components.add().CopyFrom( message_helpers.build_compound( name='THF', smiles='C1OCCC1', role='solvent', amount='40 liters', )) reaction.conditions.pressure.atmosphere.type = ( reaction_pb2.PressureConditions.Atmosphere.OXYGEN) reaction.conditions.stirring.rate.rpm = 100 reaction.conditions.temperature.control.type = ( reaction_pb2.TemperatureConditions.TemperatureControl.OIL_BATH) reaction.conditions.temperature.setpoint.CopyFrom( reaction_pb2.Temperature(value=100, units=reaction_pb2.Temperature.CELSIUS)) outcome = reaction.outcomes.add() outcome.reaction_time.CopyFrom(self._resolver.resolve('40 minutes')) outcome.products.add().identifiers.extend( message_helpers.build_compound( name='hexanone', smiles='CCCCC(=O)C', ).identifiers) reaction.reaction_id = 'dummy_reaction_id' self._reaction = reaction self._input = os.path.join(self.test_subdirectory, 'reaction.pbtxt') message_helpers.write_message(self._reaction, self._input)
def setUp(self): super().setUp() self._resolver = units.UnitResolver() reaction = reaction_pb2.Reaction() reaction.setup.is_automated = reaction_pb2.Boolean.TRUE reaction.inputs['dummy_input'].components.add().CopyFrom( message_helpers.build_compound( name='n-hexane', smiles='CCCCCC', role='reactant', amount='1 milliliters', )) reaction.inputs['dummy_input'].components.add().CopyFrom( message_helpers.build_compound( name='C1OCCC1', smiles='THF', role='solvent', amount='40 liters', )) reaction.conditions.pressure.atmosphere.type = ( reaction_pb2.PressureConditions.Atmosphere.OXYGEN) reaction.conditions.stirring.rate.rpm = 100 reaction.conditions.temperature.control.type = ( reaction_pb2.TemperatureConditions.TemperatureControl.OIL_BATH) reaction.conditions.temperature.setpoint.CopyFrom( reaction_pb2.Temperature(value=100, units=reaction_pb2.Temperature.CELSIUS)) outcome = reaction.outcomes.add() outcome.reaction_time.CopyFrom(self._resolver.resolve('40 minutes')) outcome.products.add().compound.CopyFrom( message_helpers.build_compound( name='hexanone', smiles='CCCCC(=O)C', role='product', )) reaction.reaction_id = 'dummy_reaction_id' self._reaction = reaction
def test_bad_role(self): with self.assertRaisesRegex(KeyError, 'not a supported type'): message_helpers.build_compound(role='flavorant')
def test_get_compound_smiles(self): compound = message_helpers.build_compound(smiles='c1ccccc1', name='benzene') self.assertEqual(message_helpers.get_compound_smiles(compound), 'c1ccccc1')
def test_vendor(self): self.assertEqual( message_helpers.build_compound(vendor='Sally').source.vendor, 'Sally')
def test_custom_prep_without_details(self): with self.assertRaisesRegex(ValueError, 'prep_details must be provided'): message_helpers.build_compound(prep='custom')
def test_prep_details_without_prep(self): with self.assertRaisesRegex(ValueError, 'prep must be provided'): message_helpers.build_compound(prep_details='rinsed gently')
def test_bad_prep(self): with self.assertRaisesRegex(KeyError, 'not a supported type'): message_helpers.build_compound(prep='shaken')
def test_prep(self, prep, details, expected): compound = message_helpers.build_compound(prep=prep, prep_details=details) self.assertEqual(compound.preparations[0], expected)
def test_amount(self, amount, expected): compound = message_helpers.build_compound(amount=amount) self.assertEqual( getattr(compound.amount, compound.amount.WhichOneof('kind')), expected)
def test_role(self): compound = message_helpers.build_compound(role='solvent') self.assertEqual(compound.reaction_role, reaction_pb2.ReactionRole.SOLVENT)
def test_bad_amount(self, amount): with self.assertRaises((KeyError, ValueError)): message_helpers.build_compound(amount=amount)