def test_timed_small_protocol(self): ############################################# # set up the document print('Setting up document') doc = sbol3.Document() sbol3.set_namespace('https://bbn.com/scratch/') ############################################# # Create the Protocol print('Creating Protocol') protocol = paml.Protocol('test_protocol') # Protocol starts at time zero start = pamlt.startTime(protocol, 0, units=tyto.OM.hour) # Protocol lasts 10 - 15 hours duration = pamlt.duration(protocol, [10, 15], units=tyto.OM.hour) time_constraints = pamlt.TimeConstraints("small_protocol_constraints", constraints=pamlt.And( [start, duration]), protocols=[protocol]) doc.add(protocol) doc.add(time_constraints) ######################################## # Validate and write the document print('Validating and writing time') v = doc.validate() assert not v.errors and not v.warnings, "".join( str(e) for e in doc.validate().errors)
def test_activity_bad_inflows(self): """Test whether validator can detect error due to excess or missing inflows""" # set up the document print('Setting up document') doc = sbol3.Document() sbol3.set_namespace('https://bbn.com/scratch/') # Create the protocol print('Creating protocol') protocol = paml.Protocol('broken') doc.add(protocol) # call order backwards, to make an edge from the final to the initial protocol.order(protocol.final(), protocol.initial()) # access a parameter node and order it backwards too p = uml.ActivityParameterNode() protocol.nodes.append(p) protocol.order(protocol.final(), p) # Validate the document, which should produce two errors print('Validating and writing protocol') v = doc.validate() assert len(v) == 3, f'Expected 3 validation issues, but found {len(v)}' expected = [ 'https://bbn.com/scratch/broken/ActivityParameterNode1: Too few values for property parameter. Expected 1, found 0', 'https://bbn.com/scratch/broken/InitialNode1: InitialNode must have no incoming edges, but has 1', 'https://bbn.com/scratch/broken/FlowFinalNode1: Node has no incoming edges, so cannot be executed' ] observed = [str(e) for e in v] assert observed == expected, f'Unexpected error content: {observed}'
def test_activity_multiflow(self): """Test whether validator can detect nondeterminism due to activity multiple outflows""" # set up the document print('Setting up document') doc = sbol3.Document() sbol3.set_namespace('https://bbn.com/scratch/') paml.import_library('sample_arrays') # Create the protocol print('Creating protocol') protocol = paml.Protocol('broken') doc.add(protocol) # get a plate plate = protocol.primitive_step('EmptyContainer', specification='placeholder') # use it in three places s1 = protocol.primitive_step('PlateCoordinates', coordinates='A1:D1') protocol.edges.append( uml.ObjectFlow(source=plate.output_pin('samples'), target=s1.input_pin('source'))) s2 = protocol.primitive_step('PlateCoordinates', coordinates='A2:D2') protocol.edges.append( uml.ObjectFlow(source=plate.output_pin('samples'), target=s2.input_pin('source'))) s3 = protocol.primitive_step('PlateCoordinates', coordinates='A3:D3') protocol.edges.append( uml.ObjectFlow(source=plate.output_pin('samples'), target=s3.input_pin('source'))) # Validate the document, which should produce one error print('Validating and writing protocol') v = doc.validate() assert len(v.errors) == 0, f'Expected zero errors, but found {len(v)}' assert len( v.warnings ) == 1, f'Expected precisely one warning, but found {len(v)}' assert str(v.warnings[0]) == \ 'https://bbn.com/scratch/broken/CallBehaviorAction1/OutputPin1: ' \ 'ActivityNode has 3 outgoing edges: multi-edges can cause nondeterministic flow', \ f'Unexpected warning content: {str(v.warnings[0])}'
# this should really get pulled into a common library somewhere rpm = sbol3.UnitDivision('rpm', name='rpm', symbol='rpm', label='revolutions per minute', numerator=tyto.OM.revolution, denominator=tyto.OM.minute) doc.add(rpm) ############################################# # Create the protocols print('Constructing measurement sub-protocols') # This will be used 10 times generating "OD_Plate_1" .. "OD_Plate_9" split_and_measure = paml.Protocol('SplitAndMeasure', name="Split samples, dilute, and measure") split_and_measure.description = ''' Subprotocol to split a portion of each sample in a plate into another plate, diluting with PBS, then measure OD and fluorescence from that other plate ''' doc.add(split_and_measure) # plate for split-and-measure subroutine od_plate = paml.Container(name='OD Plate', type=tyto.NCIT.Microplate, max_coordinate='H12') split_and_measure.locations = {od_plate} # Inputs: collection of samples, pbs_source samples = split_and_measure.add_input( name='samples',
############################################# # Import the primitive libraries print('Importing libraries') paml.import_library('liquid_handling') print('... Imported liquid handling') paml.import_library('plate_handling') print('... Imported plate handling') paml.import_library('spectrophotometry') print('... Imported spectrophotometry') paml.import_library('sample_arrays') print('... Imported sample arrays') ############################################# # Create the protocol print('Creating protocol') protocol = paml.Protocol('GoldenGate_assembly') protocol.name = "Golden Gate Assembly" protocol.description = ''' This protocol is for Golden Gate Assembly of pairs of DNA fragments into plasmids using the New England Biolabs Golden Gate Assembly Kit (BsaI-HFv2), product ID NEB #E1601. Protocol implements the specific case of two part assembly for the NEB-provided protocol: https://www.neb.com/protocols/2018/10/02/golden-gate-assembly-protocol-for-using-neb-golden-gate-assembly-mix-e1601 ''' doc.add(protocol) # create the materials to be provisioned nf_h2o = sbol3.Component('nuclease_free_H2O', 'https://identifiers.org/pubchem.compound:962') nf_h2o.name = 'Nuclease-free Water' doc.add(nf_h2o)
def create_protocol() -> paml.Protocol: logger.info('Creating protocol') protocol: paml.Protocol = paml.Protocol('samplemap_demo_protocol') protocol.name = "Protocol with a SampleMap Primitive" protocol.description = protocol.name return protocol
def create_protocol() -> paml.Protocol: logger.info('Creating protocol') protocol: paml.Protocol = paml.Protocol('iGEM_LUDOX_OD_calibration_2018') protocol.name = "iGEM 2018 LUDOX OD calibration protocol" protocol.description = DOCSTRING return protocol
def test_create_timed_protocol(self): ############################################# # set up the document print('Setting up document') doc = sbol3.Document() sbol3.set_namespace('https://bbn.com/scratch/') ############################################# # Import the primitive libraries print('Importing libraries') paml.import_library('liquid_handling') print('... Imported liquid handling') paml.import_library('plate_handling') print('... Imported plate handling') paml.import_library('spectrophotometry') print('... Imported spectrophotometry') paml.import_library('sample_arrays') print('... Imported sample arrays') ############################################# # Create the protocol print('Creating protocol') protocol = paml.Protocol('iGEM_LUDOX_OD_calibration_2018') protocol.name = "iGEM 2018 LUDOX OD calibration protocol" protocol.description = ''' With this protocol you will use LUDOX CL-X (a 45% colloidal silica suspension) as a single point reference to obtain a conversion factor to transform absorbance (OD600) data from your plate reader into a comparable OD600 measurement as would be obtained in a spectrophotometer. This conversion is necessary because plate reader measurements of absorbance are volume dependent; the depth of the fluid in the well defines the path length of the light passing through the sample, which can vary slightly from well to well. In a standard spectrophotometer, the path length is fixed and is defined by the width of the cuvette, which is constant. Therefore this conversion calculation can transform OD600 measurements from a plate reader (i.e. absorbance at 600 nm, the basic output of most instruments) into comparable OD600 measurements. The LUDOX solution is only weakly scattering and so will give a low absorbance value. ''' doc.add(protocol) # create the materials to be provisioned ddh2o = sbol3.Component( 'ddH2O', 'https://identifiers.org/pubchem.substance:24901740') ddh2o.name = 'Water, sterile-filtered, BioReagent, suitable for cell culture' # TODO get via tyto doc.add(ddh2o) ludox = sbol3.Component( 'LUDOX', 'https://identifiers.org/pubchem.substance:24866361') ludox.name = 'LUDOX(R) CL-X colloidal silica, 45 wt. % suspension in H2O' doc.add(ludox) # actual steps of the protocol # get a plate plate = protocol.primitive_step( 'EmptyContainer', specification=tyto.NCIT.get_uri_by_term( 'Microplate')) # replace with container ontology # put ludox and water in selected wells c_ddh2o = protocol.primitive_step('PlateCoordinates', source=plate, coordinates='A1:D1') provision_ludox = protocol.primitive_step( 'Provision', resource=ludox, destination=c_ddh2o.output_pin('samples'), amount=sbol3.Measure(100, tyto.OM.microliter)) c_ludox = protocol.primitive_step('PlateCoordinates', source=plate, coordinates='A2:D2') provision_ddh2o = protocol.primitive_step( 'Provision', resource=ddh2o, destination=c_ludox.output_pin('samples'), amount=sbol3.Measure(100, tyto.OM.microliter)) # measure the absorbance c_measure = protocol.primitive_step('PlateCoordinates', source=plate, coordinates='A1:D2') measure = protocol.primitive_step('MeasureAbsorbance', samples=c_measure, wavelength=sbol3.Measure( 600, tyto.OM.nanometer)) protocol.add_output('absorbance', measure.output_pin('measurements')) # Set protocol timepoints # protocol starts at time 0 protocol_start_time = pamlt.startTime(protocol, 0, units=tyto.OM.hour) provision_ludox_duration = pamlt.duration(provision_ludox, 60, units=tyto.OM.second) provision_ddh2o_duration = pamlt.duration(provision_ddh2o, 60, units=tyto.OM.second) execute_measurement_duration = pamlt.duration(measure, 60, units=tyto.OM.minute) ludox_before_ddh2o_constraint = pamlt.precedes(provision_ludox, [10, 15], provision_ddh2o, units=tyto.OM.hour) time_constraints = pamlt.TimeConstraints( "ludox_protocol_constraints", constraints=[ pamlt.And([ protocol_start_time, provision_ludox_duration, provision_ddh2o_duration, execute_measurement_duration, ludox_before_ddh2o_constraint ]) ], protocols=[protocol]) doc.add(time_constraints) ######################################## # Validate and write the document print('Validating and writing protocol') v = doc.validate() assert not v.errors and not v.warnings, "".join( str(e) for e in doc.validate().errors) # assert check_doc(doc) # Is the protocol consistent? # assert get_minimum_duration(doc) # What is the minimum duration for each protocol in doc temp_name = os.path.join(tempfile.gettempdir(), 'igem_ludox_time_test.nt') doc.write(temp_name, sbol3.SORTED_NTRIPLES) print(f'Wrote file as {temp_name}') comparison_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'testfiles', 'igem_ludox_time_test.nt') # doc.write(comparison_file, sbol3.SORTED_NTRIPLES) print(f'Comparing against {comparison_file}') assert filecmp.cmp(temp_name, comparison_file), "Files are not identical" print('File identical with test file')