Skip to content

Commit

Permalink
First Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
palibhasataolamang committed Jan 27, 2022
1 parent 8900692 commit 51a7dcb
Show file tree
Hide file tree
Showing 90 changed files with 29,136 additions and 0 deletions.
7 changes: 7 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2022 Smart Information Flow Technologies and Raytheon BBN

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 changes: 36 additions & 0 deletions doc/generate_specification_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import glob

from sbol_factory import UMLFactory
import os
from shutil import copy
from pathlib import Path

print('Warning: this script is fragile and assumes that PAML and PAML-specification are sibling directories on Mac or Unix.')

print('Loading UML')
uml_module = UMLFactory(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../uml/uml.ttl'), 'http://bioprotocols.org/uml#')
print('Generating UML specification materials')
uml_module.generate('uml_classes')

print('Moving UML to specification folder')
copy('umlDataModel.tex', '../PAML-specification/umlDataModel.tex')
os.remove('umlDataModel.tex')
Path('../PAML-specification/uml_classes/').mkdir(parents=True, exist_ok=True)
for file in glob.glob('uml_classes/*'):
copy(file, '../PAML-specification/uml_classes/')
os.remove(file)

print('Loading PAML')
paml_module = UMLFactory(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../paml/paml.ttl'),
'http://bioprotocols.org/paml#')
print('Generating PAML specification materials')
paml_module.generate('paml_classes')

print('Moving PAML to specification folder')
copy('pamlDataModel.tex', '../PAML-specification/pamlDataModel.tex')
os.remove('pamlDataModel.tex')
Path('../PAML-specification/paml_classes/').mkdir(parents=True, exist_ok=True)
for file in glob.glob('paml_classes/*'):
copy(file, '../PAML-specification/paml_classes/')
os.remove(file)
print('Update complete')
173 changes: 173 additions & 0 deletions examples/LUDOX_protocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import json
import logging
import os
from typing import Tuple

import rdflib as rdfl
import sbol3
import tyto
from sbol3 import Document

import paml

logger: logging.Logger = logging.Logger("LUDOX_protocol")

CONT_NS = rdfl.Namespace('https://sift.net/container-ontology/container-ontology#')
OM_NS = rdfl.Namespace('http://www.ontology-of-units-of-measure.org/resource/om-2/')


def prepare_document() -> Document:
logger.info('Setting up document')
doc = sbol3.Document()
sbol3.set_namespace('https://bbn.com/scratch/')
return doc


def import_paml_libraries() -> None:
logger.info('Importing libraries')
paml.import_library('liquid_handling')
logger.info('... Imported liquid handling')
paml.import_library('plate_handling')
logger.info('... Imported plate handling')
paml.import_library('spectrophotometry')
logger.info('... Imported spectrophotometry')
paml.import_library('sample_arrays')
logger.info('... Imported sample arrays')


DOCSTRING = \
'''
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.
'''


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 create_h2o() -> sbol3.Component:
ddh2o = sbol3.Component('ddH2O', 'https://identifiers.org/pubchem.substance:24901740')
ddh2o.name = 'Water, sterile-filtered, BioReagent, suitable for cell culture' # TODO get via tyto
return ddh2o


def create_ludox() -> sbol3.Component:
ludox = sbol3.Component('LUDOX', 'https://identifiers.org/pubchem.substance:24866361')
ludox.name = 'LUDOX(R) CL-X colloidal silica, 45 wt. % suspension in H2O'
return ludox


PLATE_SPECIFICATION = \
"""cont:ClearPlate and
cont:SLAS-4-2004 and
(cont:wellVolume some
((om:hasUnit value om:microlitre) and
(om:hasNumericalValue only xsd:decimal[>= "200"^^xsd:decimal])))"""

PREFIX_MAP = json.dumps({"cont": CONT_NS, "om": OM_NS})


def create_plate(protocol: paml.Protocol):
# graph: rdfl.Graph = protocol._other_rdf
# plate_spec_uri = \
# "https://bbn.com/scratch/iGEM_LUDOX_OD_calibration_2018/container_requirement#RequiredPlate"
# graph.add((plate_spec_uri, CONT_NS.containerOntologyQuery, PLATE_SPECIFICATION))
# plate_spec = sbol3.Identified(plate_spec_uri,
# "foo", name="RequiredPlate")
spec = paml.ContainerSpec(queryString=PLATE_SPECIFICATION, prefixMap=PREFIX_MAP, name='plateRequirement')
plate = protocol.primitive_step('EmptyContainer',
specification=spec)
plate.name = 'calibration plate'
return plate


def provision_h2o(protocol: paml.Protocol, plate, ddh2o) -> None:
c_ddh2o = protocol.primitive_step('PlateCoordinates', source=plate.output_pin('samples'), coordinates='A1:D1')
protocol.primitive_step('Provision', resource=ddh2o, destination=c_ddh2o.output_pin('samples'),
amount=sbol3.Measure(100, tyto.OM.microliter))


def provision_ludox(protocol: paml.Protocol, plate, ludox) -> None:
c_ludox = protocol.primitive_step('PlateCoordinates', source=plate.output_pin('samples'), coordinates='A2:D2')
protocol.primitive_step('Provision', resource=ludox, destination=c_ludox.output_pin('samples'),
amount=sbol3.Measure(100, tyto.OM.microliter))


def measure_absorbance(protocol: paml.Protocol, plate, wavelength_param):
c_measure = protocol.primitive_step('PlateCoordinates', source=plate.output_pin('samples'), coordinates='A1:D2')
return protocol.primitive_step(
'MeasureAbsorbance',
samples=c_measure.output_pin('samples'),
wavelength=wavelength_param,
)


def ludox_protocol() -> Tuple[paml.Protocol, Document]:
#############################################
# set up the document
doc: Document = prepare_document()

#############################################
# Import the primitive libraries
import_paml_libraries()

#############################################
# Create the protocol
protocol: paml.Protocol = create_protocol()
doc.add(protocol)

# create the materials to be provisioned
ddh2o = create_h2o()
doc.add(ddh2o)

ludox = create_ludox()
doc.add(ludox)

# add an optional parameter for specifying the wavelength
wavelength_param = protocol.input_value('wavelength', sbol3.OM_MEASURE, optional=True,
default_value=sbol3.Measure(600, tyto.OM.nanometer))

# actual steps of the protocol
# get a plate
plate = create_plate(protocol)

# put ludox and water in selected wells
provision_h2o(protocol, plate, ddh2o)
provision_ludox(protocol, plate, ludox)

# measure the absorbance
measure = measure_absorbance(protocol, plate, wavelength_param)

output = protocol.designate_output('absorbance', sbol3.OM_MEASURE,
measure.output_pin('measurements'))
protocol.order(protocol.get_last_step(), output)
return protocol, doc


if __name__ == '__main__':
new_protocol: paml.Protocol
new_protocol, doc = ludox_protocol()
print('Validating and writing protocol')
v = doc.validate()
assert len(v) == 0, "".join(f'\n {e}' for e in v)

rdf_filename = os.path.join(os.path.dirname(__file__), 'iGEM 2018 LUDOX OD calibration protocol.nt')
doc.write(rdf_filename, sbol3.SORTED_NTRIPLES)
print(f'Wrote file as {rdf_filename}')

# render and view the dot
dot = new_protocol.to_dot()
dot.render(f'{new_protocol.name}.gv')
dot.view()
131 changes: 131 additions & 0 deletions examples/OT2TestGen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
import tempfile
import sbol3
import paml
import tyto
import uml
import json
import rdflib as rdfl
from typing import Dict

from paml.execution_engine import ExecutionEngine
from paml_check.paml_check import check_doc
from paml_convert.ot2.ot2_specialization import OT2Specialization

# Dev Note: This is a test of the initial version of the OT2 specialization. Any specs shown here can be changed in the future. Use at your own risk. Here be dragons.


#############################################
# 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')
paml.import_library('wait')
print('... Imported wait')


# Example of how to generate a template for a new protocol step

#print(primitives["https://bioprotocols.org/paml/primitives/liquid_handling/Dispense"].template())

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
CONT_NS = rdfl.Namespace('https://sift.net/container-ontology/container-ontology#')
OM_NS = rdfl.Namespace('http://www.ontology-of-units-of-measure.org/resource/om-2/')

PREFIX_MAP = json.dumps({"cont": CONT_NS, "om": OM_NS})


ddh2o = sbol3.Component('ddH2O', 'https://identifiers.org/pubchem.substance:24901740')
ddh2o.name = 'Water, sterile-filtered, BioReagent, suitable for cell culture'
ddh2o.OT2SpecificProps = sbol3.TextProperty(ddh2o,'',0,1)
#indicate where ddh2o is loaded, use JSON to set OT2 Specific parameters; might be cleaner and more pythonesque using a dictionary but this should do for now
#water is in well A1 of reservoir and declaring that the left pipette should be used when pipetting from this reservoir
#since no coordinates were issued its assumed to be loaded into well A1
ddh2o.OT2SpecificProps = '{"deck":"1", "source":"reservoir", "type":"nest_12_reservoir_15ml"}'
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'
ludox.OT2SpecificProps = sbol3.TextProperty(ludox,'',0,1)
#indicate where ludox is loaded, use JSON to set OT2 Specific parameters; might be cleaner and more pythonesque using a dictionary but this should do for now
#ludox is in well A2 of reservoir and declaring that the right pipette should be used when pipetting from this reservoir
#no need to redeclare source type as long as it was declared before
ludox.OT2SpecificProps = '{"coordinates":"A2", "source":"reservoir", "pipette":"right"}'
doc.add(ludox)


# actual steps of the protocol
# get a plate
platespec1 = paml.ContainerSpec(queryString="corning_48_wellplate_1.6ml_flat", prefixMap=PREFIX_MAP, name='plate1')
platespec1.OT2SpecificProps = sbol3.TextProperty(platespec1,"https://bioprotocols.org/paml/primitives/sample_arrays/EmptyContainer/OT2/Deck",0,1)
platespec1.OT2SpecificProps = '{"deck":"2"}'
plate1 = protocol.primitive_step('EmptyContainer', specification=platespec1) # declare a plate loaded in the second deck

platespec2 = paml.ContainerSpec(queryString="corning_48_wellplate_1.6ml_flat", prefixMap=PREFIX_MAP, name='plate2')
platespec2.OT2SpecificProps = sbol3.TextProperty(platespec2,"https://bioprotocols.org/paml/primitives/sample_arrays/EmptyContainer/OT2/Deck",0,1)
platespec2.OT2SpecificProps = '{"deck":"3"}'
plate2 = protocol.primitive_step('EmptyContainer', specification=platespec2) # declare a plate loaded in the third deck

# identify wells to use
c_ddh2o = protocol.primitive_step('PlateCoordinates', source=plate1.output_pin('samples'), coordinates="plate1['A1:D1']")
# put water in selected wells
provision_ddh2o = protocol.primitive_step('Provision', resource=ddh2o, destination=c_ddh2o.output_pin('samples'),amount=sbol3.Measure(80, tyto.OM.microliter))
#identify wells to use
c_ludox = protocol.primitive_step('PlateCoordinates', source=plate1.output_pin('samples'), coordinates="plate1['A2:D2']")
# put ludox in selected wells
provision_ludox = protocol.primitive_step('Provision', resource=ludox, destination=c_ludox.output_pin('samples'),amount=sbol3.Measure(90, tyto.OM.microliter))
protocol.primitive_step('WaitForTime', amount=sbol3.Measure(25, tyto.OM.second)) #Experimental: Errors out if you stick it in some places
# identify wells to use
c_ddh2o2 = protocol.primitive_step('PlateCoordinates', source=plate2.output_pin('samples'), coordinates="plate2['A1:D1']")
# put water in selected wells
provision_ddh2o2 = protocol.primitive_step('Provision', resource=ddh2o, destination=c_ddh2o2.output_pin('samples'),amount=sbol3.Measure(100, tyto.OM.microliter))
#identify wells to use
c_ludox2 = protocol.primitive_step('PlateCoordinates', source=plate2.output_pin('samples'), coordinates="plate2['A2:D2']")
# put ludox in selected wells
provision_ludox2 = protocol.primitive_step('Provision', resource=ludox, destination=c_ludox2.output_pin('samples'),amount=sbol3.Measure(110, tyto.OM.microliter))





leftTiprackSettingJSON = '{"pipette":"p1000_single_gen2","tipracks":[{"id":"geb_96_tiprack_1000ul","deck":4},{"id":"geb_96_tiprack_1000ul","deck":5}]}'
rightTiprackSettingJSON = '{"pipette":"p20_single_gen2","tipracks":[{"id":"opentrons_96_tiprack_20ul","deck":6},{"id":"opentrons_96_tiprack_20ul","deck":7}]}'


filename="ludox_ot2.py"
agent = sbol3.Agent("test_agent")
ee = ExecutionEngine(specializations=[OT2Specialization("2.11",leftTiprackSettingJSON,rightTiprackSettingJSON)])
parameter_values = []
execution = ee.execute(protocol, agent, id="test_execution")
with open(filename, 'w') as f:
print(ee.specializations[0].script,file=f)
print(f"All done. Script dumped to {filename}.")


Loading

0 comments on commit 51a7dcb

Please sign in to comment.