libSBOL
2.3.3
|
This beginner’s guide introduces the basic principles of libSBOL for new users.
This guide is not meant to be a comprehensive documentation of the library or the SBOL standard. Refer to documentation about specific Classes for detailed information about the API. In addition, refer to the specification document for a complete description of the SBOL data standard. For help configuring a client project, see Creating a Visual Studio project on Windows or Creating an XCode project on Mac OSX. For example code see the Sequence Assembly and Biosystem Design tutorials or the example directory of the project source.
In a previous era, engineers might sit at a drafting board and draft a design by hand. The engineer's drafting sheet in LibSBOL is called a Document
. The Document
serves as a container, initially empty, for SBOL data objects. All file I/O operations are performed on the Document
to populate it with SBOL objects representing design elements. Usually the first step is to create a Document
in which to put your objects. This can be done by calling the Document
constructor. The read
and write
methods are used for reading and writing files in SBOL format.
Reading a Document will wipe its contents clean before import. However, you can import objects from multiple files into a single Document
object using doc.append("file.xml")
. This can be advantageous when you want to integrate multiple ComponentDefinitions
from multiple files into a single design. (Experienced C++ programmers may find that returning a reference from a new operator is an unusual idiomatic choice. See A Note on our Idiomatic Use of References for a discussion about this stylistic preference in this tutorial.)
A Document
may contain different types of SBOL objects, including ComponentDefinitions
, ModuleDefinitions
, Sequences
, SequenceAnnotations
, and Models
. These objects are collectively referred to as TopLevel
objects because they can be referenced directly from a Document
. To determine the total number of objects in a Document, use the size
method:
In order to review the ComponentDefinitions
contained in a Document
:
Similarly, you can iterate through a Document's moduleDefinitions, sequences, sequenceAnnotations
, and models
.
Memory management of pointers is encapsulated with the close
method. Pointers to a Document
and all SBOL objects contained therein may be deleted by calling doc.close()
.
Both structural and functional details of biological designs can be described with SBOL data objects. The principle classes for describing the structure and primary sequence of a design are ComponentDefinitions, Components, and Sequences, SequenceAnnotations. The principle classes for describing the function of a design are ModuleDefinitions, Modules, and Interactions. In the official SBOL specification document, these classes and their properties are represented as Unified Modeling Language (UML) diagrams. For example, following is the diagram for a ComponentDefinition which will be referred to in later sections.
When a new object is created, it must be assigned a unique identity, or uniform resource identifier (URI). A typical URI consists of a scheme, a namespace, and an identifier, although other forms of URI's are allowed. In this tutorial, we use URI's of the type http://sys-bio.org/my_design
, where the scheme is indicated by http://
, the namespace is sys-bio.org
and the identifier is my_design
.
Objects can be created by calling their respective constructors. The following constructs a ModuleDefinition:
LibSBOL provides a few global configuration options that make URI construction easy. The first configuration option allows you to specify a default namespace for new object creation. If the default namespace is set, then only an identifier needs to be passed to the constructor. This identifier will be automatically appended to the default namespace. Setting the default namespace is like signing your homework and claims ownership of an object.
Another configuration option enables automatic construction of SBOL-compliant URIs. These URIs consist of a namespace, an identifier, AND a Maven version number. In addition, SBOL-compliance simplifies autoconstruction of certain types of SBOL objects, as we will see later. LibSBOL operates in SBOL-compliant mode by default. However, some RDF power users will prefer to operate in "open-world" mode and provide the full raw URI when constructing objects. To disable URI construction, SBOL-compliance use toggleSBOLCompliance()
.
Some constructors have required fields. In the specification document, required fields are indicated as properties with a cardinality of 1 or more. For example, a ComponentDefinition (see the UML diagram above) has only one required field, the type, which specifies the molecular type of a component. Arguments to a constructor are always determined by whether the official SBOL specification document indicates if it is required. Required fields SHOULD be specified when calling a constructor. If they are not, then they will be assigned default values. The following creates a protein component. If the BioPAX term for protein were not specified, then the constructor would create a ComponentDefinition of DNA by default.
Notice the type is specified using a predefined constant. The ComponentDefinition::type property is one of many SBOL properties that use standard ontology terms as property values. The ComponentDefinition::type property uses the Sequence Ontology to be specific. Many commonly used ontological terms are provided by libSBOL as predefined constants in the constants.h header. See the help page for the sbol::ComponentDefinition class or other specific class to find a table that lists the available terms.
In some cases a developer may want to use SBOL objects as intermediate data structures in a computational biology workflow. In this case the user is free to manipulate objects independently of a Document. However, if the user wishes to write out a file with all the information contained in their object, they must first add it to the Document. This is done using a templated add method.
Only TopLevel objects need to be added to a Document. These top level objects include ComponentDefinitions, ModuleDefinitions, Sequences, Models. Child objects are automatically associated with the parent object's Document.
Objects may also include optional fields. These are indicated in UML as properties having a cardinality of 0 or more. Except for the molecular type field, all properties of a ComponentDefinition are optional. Optional properties can only be set after the object is created. The following code creates a DNA component which is designated as a promoter:
All properties have a set and a get method. To view the value of a property:
This returns the string "http://identifiers.org/so/SO:0000167" which is the Sequence Ontology term for a promoter.
Note also that some properties support a list of values. A property with a cardinality indicated by an asterisk symbol indicates that the property may hold an arbitrary number of values. For example, a ComponentDefinition may be assigned multiple roles. To add a new role:
Some SBOL objects can be composed into hierarchical parent-child relationships. In the specification diagrams, these relationshipss are indicated by black diamond arrows. In the UML diagram above, the black diamond indicates that ComponentDefinitions are parents of SequenceAnnotations. Properties of this type can be modified using the add method and passing the child object as the argument.
If you are operating in SBOL-compliant mode, you may prefer to take a shortcut:
The create method captures the construction and addition of the SequenceAnnotation in a single function call. Another advantage of the create method is the construction of SBOL-compliant URIs. If operating in SBOL-compliant mode, you will almost always want to use the create method. The create method ALWAYS takes one argument–the URI of the new object. All other values are initialized with default values. You can change these values after object creation, however. When operating in open-world mode, it is preferable to follow the first example and use the constructor and add method.
Some SBOL objects point to other objects by way of references. For example, ComponentDefinitions point to their corresponding Sequences. Properties of this type should be set with the URI of the related object.
Some properties can contain multiple values or objects. As mentioned under Getting, Setting, and Editing Optional Fields additional values can be specified with the add method. In addition you may iterate over lists of objects or values.
Numerical indexing of lists works as well:
This concludes the basic methods for manipulating SBOL data structures. Now that you're familiar with these basic methods, you are ready to learn about libSBOL's high-level design interface for synthetic biology. See Sequence Assembly.
In C++ creating a reference to an object using the new operator is a matter of stylistic controversy. For one thing, mixing references with the new operator can make low level memory management confusing for some developers. The reason this isn't an issue here is because libSBOL encapsulates memory management within the Document object. Pointers to all the objects in a Document are freed when the Document::close method is called. Coming from a Python background to C++, we wanted to maximize the object-oriented experience using the library and minimize the use of pointers. Rest assured however, that if you disagree with this idiomatic style, you can still work with pointers in the more traditional way.
The libSBOL repository contains example Xcode (for Mac) and Visual Studio (for Windows) project files. In Xcode open the example.xcodeproj file included in the example/Xcode directory. This project assumes that you have already installed libSBOL via an installer executable or have run make install
, assuming you have built libSBOL from source. (See Introduction for build instructions) Running make install
places the headers in /usr/local/include/sbol/ and the library in /usr/local/lib. This project targets OS 10.9 and later. If you have an older system you will have to change the Build Settings > Deployment > OS X Deployment Target (eg, from 10.9 to 10.8) depending on your system version
If you have installed libSBOL to a custom location and you would like to configure your Xcode project from scratch:
Now link and run your client application:
Here, -I flags specify paths to include folders with necessary header files. -L flag specifies path to the libSBOL library. -o flag specifies the file name of the output. Change the values according to your setup.
It is strongly recommended to use Visual Studio 2015
1) RUN THE INSTALLER
2) CREATE A NEW PROJECT IN VISUAL STUDIO
3) SPECIFY DEPENDENCIES
To specify link libraries, navigate to 'Configuration Properties > Linker > Input'. Select the 'Additional Dependencies' field and edit it. Enter the following libraries:
sbol.lib; raptor2.lib; libxml2.lib; libiconv.lib; libz.lib; jsoncpp.lib; libcurl.lib
4) INCLUDE SBOL HEADER AND NAMESPACE IN THE CLIENT APP
5) If you want to build using 64 bit libraries, make sure you target 'x64' and follow the above steps.