+
+
+
+
+
+## Table of Contents
+
+* [About the Project](#about-the-project)
+ * [Built With](#built-with)
+* [Getting Started](#getting-started)
+ * [Prerequisites](#prerequisites)
+ * [Installation](#installation)
+* [Usage](#usage)
+* [Roadmap](#roadmap)
+* [Contribute](#contribute)
+* [License](#license)
+* [Contact](#contact)
+* [Acknowledgements](#acknowledgements)
+
+
+
+
+## About The Project
+
+
+
+
+
+**SPiRA** is the next-generation object-oriented script-based PCell design environment.
+The framework leverages the Python programming language to effectively generate circuit layouts,
+while simultaneously checking for design violations, through a novel methodology called *validate-by-design*.
+Creating PCells and extracting a model from a layout requires data from the fabrication process.
+A new PDK scheme is introduced, called the Rule Deck Database (RDD), that effectively connects
+process data to the SPiRA framework. The design of the **RDD** revolves around the principle that
+a PDK cannot be created, but rather that it evolves as our understanding of physical layout design evolves.
+
+### Benefits of using SPiRA
+
+* Create a PCell framework that is easy to use by designers with the focus falling on Superconducting and Quantum Integrated Circuits.
+* Effectively connect process data to layout elements in a generic process-independent fashion.
+* No specific programming knowledge is required.
+* Easily share designs between colleagues.
+* Created PCells can easily be included in a hand-designed layout.
+
+### Features
+
+* Define layout elements in a templated environment.
+* Ability to leverage object-oriented inheritance to simply complex designs.
+* Comprehensive set of commands for shape generation.
+* Use port objects to connect different layout elements.
+* Use routing algorithms to generate polygonal paths between devices.
+* Meticulously define a technology process using Python.
+
+A list of used resources that was helpful in the development of the SPiRA framework.
+
+### Built With
+
+Love
+
+
+
+
+## Getting Started
+
+This is an example of how you may give instructions on setting up your project locally.
+To get a local copy up and running follow these simple example steps.
+
+### Prerequisites
+
+This is an example of how to list things you need to use the software and how to install them in Fedora:
```bash
sudo dnf install redhat-rpm-config
@@ -19,12 +112,9 @@ sudo dnf install tkinter
sudo dnf install gmsh
```
-Documentation for other Linux systems can be found in [installation](https://spira.readthedocs.io/en/latest/installation.html)
-
-## Installation
+### Installation
-You can install SPiRA directly from the Python package manager *pip* using.
-First create a virtual environment:
+You can install SPiRA directly from the Python package manager *pip* using and remember to create a *virtual environment*:
```bash
python3 -m venv env
@@ -40,15 +130,137 @@ pip install .
pip install -e .
```
-## Documentation
-The complete framework [documentation](https://spira.readthedocs.io/en/latest/overview.html) explains the basics of the RDD and PCell API. Note that the DRC and LVS modules are still being developed.
-Examples of using the PCell implementation is given in [examples](https://github.com/rubenvanstaden/spira/tree/master/demo).
-
+
+## Usage
+
+_For examples, please refer to the [Documentation](https://spira.readthedocs.io/en/latest/)_
+
+All examples can be ran from the environment directory, which is the home directory of your ``spira`` folder.
+For the basic tutorial samples:
+
+```python
+python tutorials/basic/_9_stretch_1.py
+```
+
+For the more advanced example with their own defined Rule Deck Database, as
+explained [here](https://spira.readthedocs.io/en/latest/).
+
+```python
+python spira/technologies/default/circuits/ytron_circuit.py
+```
+
+
+
+## Roadmap
+
+See the [open issues](https://github.com/rubenvanstaden/spira/issues) for a list of proposed features (and known issues).
+As a short overview here is the project focus over the next 12 month:
+
+* Complete netlist extraction and device detection from a native GDSII layout.
+* Add graph isomorphic checks for differences between the extracted layout netlist and that of the designed SPICE netlist.
+* Implement DRC algorithms and integration support with parameter extraction engines.
+
+
+
+## Contribute
+
+Contributions are what make the open source community such an amazing place to be learn, inspire, and create.
+Any contributions you make are **greatly appreciated**.
+
+1. Fork the Project
+2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
+3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
+4. Push to the Branch (`git push origin feature/AmazingFeature`)
+5. Open a Pull Request
+
+
+
+
+## License
+
+Distributed under the MIT License. See `LICENSE` for more information.
+
+
+
+
+## Contact
+
+* Ruben van Staden - rubenvanstaden@gmail.com
+* Coenrad Fourie - coenradf@gmail.com
+* Kyle Jackman - kylejack1@gmail.com
+* Joey Delport - joeydelp@gmail.com
+
+
+
+## Acknowledgements
+
+* [Gdspy](https://github.com/heitzmann/gdspy)
+* [Phidl](https://github.com/amccaugh/phidl)
+* [Clippers](http://www.angusj.com/delphi/clipper.php)
+
+
+
+
## History of changes
+### Version 0.2.0 (October 4, 2019)
+* Added layout netlist extraction and viewing.
+* Added electrical rule checking (ERC).
+* Added **filters** for advanced layout manipulation.
+* Updated ports for more information descriptions. Terminals can now be separated from port definitions.
+* A new concept, called **virtual modeling** (VModel) is introduced. This allows you to create multiple, virtual versions of a single layout for either debugging or fabrication purposes.
+* Routing algorithms have been updated to leverage speed improvements made in the Gdspy library.
+* The GDSII parser has been updated for better code structure and faster read/write operations.
+
+### Version 0.1.1 (July 16, 2019)
+* Updated the advanced tutorial documentation.
+* Added developers documentations.
+* Updated the expand transform algorithms, which fixes a lot of known issues.
+* Updated the GDSII input parser to use new transformation parameters.
+* Changed the ``ref`` parameter to ``reference`` in ``SRef``.
+
+### Version 0.1.0 (July 10, 2019)
+* Added first version of documentation.
+* Renamed ``Fields`` to ``Parameters`` to overcome confusion.
+* Renamed ``elemental`` to ``elements``, since ``spira.Cell`` does not inherit from ``gdspy.Cell`` anymore.
+* Added parameter restrictions and preprocessing capabilities.
+* Updated parameters to accept an extra restriction argument.
+* Introduces ``Vector``, ``Line``, and ``Coord`` classes.
+* Depricated locked ports. Instead different port purposes can now be defined.
+* Introduces *process* and *purpose* parameters to layer elements.
+* Introduces *derived layers* to allow for layer boolean operations. This makes the RDD more flexible for future technology changes.
+* Updated the edge generation algorithms to include both an outside and inside edge.
+* Updated the routing algorithms to use new ``gdspy`` features.
+* Added stretching operations.
+* Extended the RDD to include *display resources*.
+* Fix issues with writing to a GDSII file.
+* Added snap to grid functionality.
+* Implemented parameters caching.
+* Added port alignment operations.
+* Added `PortList` class for special port filtering functionality.
+* Created layer mappers.
+* Changed the default coordinate system to improve port transformations.
+* Updates shapes and polygons to only include single polygons. Multiple polygons are now moved to the ``PolygonGroup`` class.
+* Updated ports to extend from the ``Vector``.
+* Added a custom ``LayerList`` class that compares already added layers.
+* Updated mixins to a single ``MixinBowl`` meta-configuration.
+* Updated the datatype parameter of ports that represents primitive connects.
+* Added ``NumberParameter`` which supports 'int' and 'float' parameters.
+* Added ``ComplexParameter`` which supports 'int', 'float' and 'complex' parameters.
+* Added automatic docstring generation.
+
+### Version 0.0.3 (March 12, 2019)
+* Added Dummy ports for crossing nodes in netlist.
+* Automatically generate terminal edges for metal polygons.
+* Added shape for yTron.
+* Added path routing between two terminals.
+* Define a route using a list of terminals.
+* Device cell detection (Junction, Via, etc).
+* Basic LVS implementation.
+
### Version 0.0.2 (Jan 11, 2019)
* Implemented Manhattan routing between terminals.
* Integrated circleci.
@@ -61,3 +273,30 @@ Examples of using the PCell implementation is given in [examples](https://github
### Version 0.0.1 (Dec 01, 2018)
* Initial release.
+
+
+
+
+
+[version-shield]: https://img.shields.io/badge/version-0.2.0-blue
+[version-url]: https://github.com/rubenvanstaden/spira/blob/master/spira/settings.py
+[contributors-shield]: https://img.shields.io/github/contributors/othneildrew/Best-README-Template.svg?style=flat-square
+[contributors-url]: https://github.com/rubenvanstaden/spira/graphs/contributors
+[forks-shield]: https://img.shields.io/github/forks/othneildrew/Best-README-Template.svg?style=flat-square
+[forks-url]: https://github.com/rubenvanstaden/spira/network/members
+[issues-shield]: https://img.shields.io/github/issues/othneildrew/Best-README-Template.svg?style=flat-square
+[issues-url]: https://github.com/rubenvanstaden/spira/issues`
+[license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=flat-square
+[license-url]: https://github.com/rubenvanstaden/spira/blob/master/LICENSE
+[product-screenshot]: images/screenshot.png
+
+
+
\ No newline at end of file
diff --git a/demo/pdks/components/jtl.py b/demo/pdks/components/jtl.py
deleted file mode 100644
index 9d94af9e..00000000
--- a/demo/pdks/components/jtl.py
+++ /dev/null
@@ -1,136 +0,0 @@
-import spira
-import numpy as np
-from spira import param, shapes
-from spira.rdd import get_rule_deck
-from demo.pdks.components.junction import Junction
-from spira.lgm.route.manhattan_base import RouteManhattan
-from spira.lgm.route.basic import RouteShape, RouteBasic, Route
-
-
-RDD = get_rule_deck()
-
-
-class Jtl(spira.Cell):
-
- m1 = param.MidPointField(default=(0,0))
- m2 = param.MidPointField(default=(0,0))
- rotation = param.FloatField(default=0)
-
- jj1 = param.DataField(fdef_name='create_junction_one')
- jj2 = param.DataField(fdef_name='create_junction_two')
- quadrant = param.DataField(fdef_name='create_quadrant')
-
- def create_quadrant(self):
- quadrant = None
- if (self.m2[1] > self.m1[1]) and (self.m2[0] > self.m1[0]):
- quadrant = 'Q1'
- if (self.m2[1] > self.m1[1]) and (self.m2[0] < self.m1[0]):
- quadrant = 'Q2'
- if (self.m2[1] < self.m1[1]) and (self.m2[0] < self.m1[0]):
- quadrant = 'Q3'
- if (self.m2[1] < self.m1[1]) and (self.m2[0] > self.m1[0]):
- quadrant = 'Q4'
- return quadrant
-
- def create_junction_one(self):
- jj = Junction()
- jj.center = (0,0)
- return spira.SRef(jj, midpoint=self.m1, rotation=self.rotation)
-
- def create_junction_two(self):
- jj = Junction()
- jj.center = (0,0)
- return spira.SRef(jj, midpoint=self.m2, rotation=-self.rotation)
-
- def create_elementals(self, elems):
-
- s1 = self.jj1
- s2 = self.jj2
-
- if self.quadrant in ['Q1', 'Q4']:
- route = RouteManhattan(
- port1=s1.ports['Output'],
- port2=s2.ports['Input'],
- radius=3, length=1,
- gdslayer=RDD.COU.LAYER
- )
- if self.quadrant in ['Q2', 'Q3']:
- route = RouteManhattan(
- port1=s2.ports['Output'],
- port2=s1.ports['Input'],
- radius=3, length=1,
- gdslayer=RDD.COU.LAYER
- )
-
- s3 = spira.SRef(route)
- s3.move(midpoint=s3.ports['T1'], destination=route.port1)
-
- r1 = Route(
- port1=self.term_ports['T1'],
- port2=s1.ports['Input'],
- player=RDD.PLAYER.COU
- )
- elems += spira.SRef(r1)
-
- r2 = Route(
- port1=self.term_ports['T2'],
- port2=s2.ports['Output'],
- player=RDD.PLAYER.COU
- )
- elems += spira.SRef(r2)
-
- elems += [s1, s2, s3]
-
- return elems
-
- def create_ports(self, ports):
-
- if self.quadrant in ['Q1', 'Q4']:
- ports += spira.Term(
- name='T1',
- midpoint=self.jj1.ports['Input'] + [-10,0],
- orientation=-90
- )
- ports += spira.Term(
- name='T2',
- midpoint=self.jj2.ports['Output'] + [10,0],
- orientation=90
- )
-
- if self.quadrant in ['Q2', 'Q3']:
- ports += spira.Term(
- name='T1',
- midpoint=self.jj1.ports['Input'] + [10,0],
- orientation=-90
- )
- ports += spira.Term(
- name='T2',
- midpoint=self.jj2.ports['Output'] + [-10,0],
- orientation=90
- )
-
- return ports
-
-
-if __name__ == '__main__':
-
- name = 'JTL PCell'
- spira.LOG.header('Running example: {}'.format(name))
-
- jtl = spira.Cell(name='JTL')
-
- # jj_q1 = Jtl(m2=(30,30), rotation=0)
- # jj_q2 = Jtl(m2=(-30,30), rotation=0)
- # jj_q3 = Jtl(m2=(-30,-30), rotation=0)
- jj_q4 = Jtl(m2=(30,-30), rotation=0)
-
- # jtl += spira.SRef(jj_q1, midpoint=(0,0))
- # jtl += spira.SRef(jj_q2, midpoint=(100,0))
- # jtl += spira.SRef(jj_q3, midpoint=(100,0))
- jtl += spira.SRef(jj_q4, midpoint=(100,0))
-
- jtl.output(name=name)
-
- spira.LOG.end_print('JTL example finished')
-
-
diff --git a/demo/pdks/components/junction.py b/demo/pdks/components/junction.py
deleted file mode 100644
index 90e34597..00000000
--- a/demo/pdks/components/junction.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import spira
-from spira import param
-from spira import shapes
-from spira.rdd import get_rule_deck
-from spira.rdd.technology import ProcessTree
-from demo.pdks import ply
-
-
-RDD = get_rule_deck()
-
-
-class Junction(spira.Cell):
- """ Josephon Junction component for the AIST process. """
-
- metals = param.DataField(fdef_name='create_metal_layers')
- contacts = param.DataField(fdef_name='create_contact_layers')
-
- def create_metal_layers(self):
- metals = spira.ElementList()
- metals += ply.Box(player=RDD.PLAYER.COU, center=(1.95, 5.76), w=1.9, h=6.7)
- metals += ply.Box(player=RDD.PLAYER.BAS, center=(1.95, 2.6), w=3.9, h=5.2)
- metals += ply.Box(player=RDD.PLAYER.BAS, center=(1.95, 7.7), w=1.9, h=2.8)
- metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 7.2), w=1.5, h=1.5)
- metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 5.76), w=1.5, h=2.0)
- metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 3.55), w=3.4, h=2.8)
- return metals
-
- def create_contact_layers(self):
- elems = spira.ElementList()
- elems += ply.Box(player=RDD.PLAYER.GC, center=(1.95, 1.1), w=2.9, h=1.2)
- elems += ply.Box(player=RDD.PLAYER.BC, center=(1.95, 8.5), w=1.4, h=1.0)
- elems += ply.Box(player=RDD.PLAYER.RC, center=(1.95, 7.2), w=0.9, h=1.0)
- elems += ply.Box(player=RDD.PLAYER.RC, center=(1.95, 3.55), w=2.9, h=2.3)
- elems += ply.Box(player=RDD.PLAYER.JC, center=(1.95, 3.55), w=1.4, h=1.0)
- elems += ply.Box(player=RDD.PLAYER.JJ, center=(1.95, 3.55), w=1.9, h=1.3)
- return elems
-
- def create_elementals(self, elems):
- for e in self.metals:
- elems += e
- for e in self.contacts:
- elems += e
-
- for key in RDD.VIAS.keys:
- RDD.VIAS[key].PCELL.create_elementals(elems)
-
- return elems
-
- def create_ports(self, ports):
- ports += spira.Term(name='Input', midpoint=(0.25, 3.5), orientation=90, width=2)
- ports += spira.Term(name='Output', midpoint=(3.6, 3.5), orientation=-90)
- return ports
-
-
-if __name__ == '__main__':
-
- name = 'Junction PCell'
- spira.LOG.header('Running example: {}'.format(name))
-
- jj = Junction()
- jj.output(name=name)
-
- spira.LOG.end_print('Junction example finished')
-
-
-
-
-
-
-
-
diff --git a/demo/pdks/components/squid.py b/demo/pdks/components/squid.py
deleted file mode 100644
index 66487ccb..00000000
--- a/demo/pdks/components/squid.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import spira
-from spira import param, shapes
-from spira.rdd import get_rule_deck
-from demo.pdks.components.junction import Junction
-from spira.lgm.route.manhattan_base import RouteManhattan
-
-
-RDD = get_rule_deck()
-
-
-class Squid(spira.Cell):
-
- m1 = param.MidPointField(default=(0,0))
- m2 = param.MidPointField(default=(0,0))
- rotation = param.FloatField(default=0)
-
- def create_elementals(self, elems):
-
- jj = Junction()
-
- jj.center = (0,0)
-
- s1 = spira.SRef(jj, midpoint=self.m1, rotation=self.rotation)
- s2 = spira.SRef(jj, midpoint=self.m2, rotation=-self.rotation)
-
- r1 = RouteManhattan(
- port1=s1.ports['Output'],
- port2=s2.ports['Output'],
- radius=1, length=1
- )
- r2 = RouteManhattan(
- port1=s1.ports['Input'],
- port2=s2.ports['Input'],
- radius=1, length=1
- )
-
- s3 = spira.SRef(r1)
- elems += s3
-
- s4 = spira.SRef(r2)
- elems += s4
-
- elems += [s1, s2]
-
- return elems
-
-
-if __name__ == '__main__':
-
- name = 'SQUID PCell'
- spira.LOG.header('Running example: {}'.format(name))
-
- squid = spira.Cell(name='SQUID')
-
- # s5 = Squid(m2=(30,30), rotation=0)
- # s6 = Squid(m2=(-30,30), rotation=0)
- s7 = Squid(m2=(30,-30), rotation=0)
-
- # squid += spira.SRef(s5, midpoint=(0,0))
- # squid += spira.SRef(s6, midpoint=(50,0))
- squid += spira.SRef(s7, midpoint=(100,0))
-
- squid.output(name=name)
-
- spira.LOG.end_print('SQUID example finished')
-
-
-
diff --git a/demo/pdks/ply/__init__.py b/demo/pdks/ply/__init__.py
deleted file mode 100644
index 87063384..00000000
--- a/demo/pdks/ply/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .box import Box
\ No newline at end of file
diff --git a/demo/pdks/ply/base.py b/demo/pdks/ply/base.py
deleted file mode 100644
index 3aee2caa..00000000
--- a/demo/pdks/ply/base.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import spira
-from spira import param
-from spira.rdd import get_rule_deck
-
-
-RDD = get_rule_deck()
-
-
-class Base(spira.Cell):
-
- player = param.PhysicalLayerField()
- polygon = param.DataField(fdef_name='create_polygon')
-
- def create_polygon(self):
- return None
-
- def create_elementals(self, elems):
- elems += self.polygon
- return elems
-
- def create_ports(self, ports):
- if self.player.purpose in (RDD.PURPOSE.PRIM.VIA, RDD.PURPOSE.PRIM.JUNCTION):
- ports += spira.Port(name='P1', midpoint=self.center)
- ports += spira.Port(name='P2', midpoint=self.center)
- return ports
-
diff --git a/demo/pdks/ply/box.py b/demo/pdks/ply/box.py
deleted file mode 100644
index 1fcea9c1..00000000
--- a/demo/pdks/ply/box.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import spira
-from spira import param
-from spira import shapes
-from demo.pdks.ply.base import Base
-
-
-class Box(Base):
-
- w = param.FloatField(default=1)
- h = param.FloatField(default=1)
- center = param.PointField()
-
- def validate_parameters(self):
- if self.w < self.player.data.WIDTH:
- return False
- if self.h < self.player.data.WIDTH:
- return False
- return True
-
- def create_polygon(self):
- shape = shapes.BoxShape(center=self.center, width=self.w, height=self.h)
- ply = spira.Polygons(shape=shape, gdslayer=self.player.layer)
- return ply
-
diff --git a/demo/pdks/process/aist_pdk/database.py b/demo/pdks/process/aist_pdk/database.py
deleted file mode 100644
index eb3b6790..00000000
--- a/demo/pdks/process/aist_pdk/database.py
+++ /dev/null
@@ -1,181 +0,0 @@
-from spira.rdd.technology import DataTree
-from spira.rdd.technology import ProcessTree
-from spira.rdd.technology import PhysicalTree
-from spira.rdd.technology import DynamicDataTree
-from spira.gdsii.layer import Layer
-from spira.rdd.layer import PhysicalLayer
-from spira.rdd import RULE_DECK_DATABASE as RDD
-
-# -------------------------------- Initialize ------------------------------------
-
-RDD.name = 'AiST'
-RDD.desc = 'Process fabrication data for the AIST process from Japan.'
-
-# ---------------------------------- GDSII ---------------------------------------
-
-RDD.GDSII = DataTree()
-RDD.GDSII.TEXT = 64
-RDD.GDSII.UNIT = 1e-6
-RDD.GDSII.PRECISION = 1e-9
-
-# --------------------------------- Metals ---------------------------------------
-
-RDD.LAYER = ProcessTree()
-
-RDD.GP = ProcessTree()
-RDD.GP.LAYER = Layer(name='GP', number=1)
-RDD.GP.COLOR = '#49CEC1'
-
-RDD.RES = ProcessTree()
-RDD.RES.LAYER = Layer(name='RES', number=3)
-RDD.RES.COLOR = '#7FDCD3'
-
-RDD.BAS = ProcessTree()
-RDD.BAS.LAYER = Layer(name='BAS', number=4)
-RDD.BAS.COLOR = '#91E1D9'
-
-RDD.COU = ProcessTree()
-RDD.COU.LAYER = Layer(name='COU', number=8)
-RDD.COU.COLOR = '#A4E6E0'
-
-RDD.CTL = ProcessTree()
-RDD.CTL.LAYER = Layer(name='CTL', number=12)
-RDD.CTL.COLOR = '#B6EBE6'
-
-RDD.JP = ProcessTree()
-RDD.JP.LAYER = Layer(name='JP', number=5)
-RDD.JP.WIDTH = 0.5
-RDD.JP.M5_METAL = 1.0
-
-# --------------------------------- Vias ----------------------------------------
-
-RDD.RC = ProcessTree()
-RDD.RC.LAYER = Layer(name='RC', number=9)
-RDD.RC.WIDTH = 0.5
-RDD.RC.M5_METAL = 1.0
-
-RDD.GC = ProcessTree()
-RDD.GC.LAYER = Layer(name='GC', number=2)
-RDD.GC.WIDTH = 0.5
-RDD.GC.M5_METAL = 1.0
-
-RDD.JJ = ProcessTree()
-RDD.JJ.LAYER = Layer(name='JJ', number=6)
-RDD.JJ.WIDTH = 0.5
-RDD.JJ.M5_METAL = 1.0
-
-RDD.BC = ProcessTree()
-RDD.BC.WIDTH = 0.5
-RDD.BC.LAYER = Layer(name='BC', number=7)
-RDD.BC.WIDTH = 0.5
-RDD.BC.M5_METAL = 1.0
-
-RDD.JC = ProcessTree()
-RDD.JC.LAYER = Layer(name='JC', number=10)
-RDD.JC.WIDTH = 0.5
-RDD.JC.M5_METAL = 1.0
-
-RDD.CC = ProcessTree()
-RDD.CC.LAYER = Layer(name='CC', number=11)
-RDD.CC.WIDTH = 0.5
-RDD.CC.M5_METAL = 1.0
-
-# ------------------------------- Physical Metals -------------------------------
-
-RDD.PLAYER = PhysicalTree()
-RDD.PLAYER.GP = PhysicalLayer(layer=RDD.GP.LAYER, purpose=RDD.PURPOSE.GROUND)
-RDD.PLAYER.RES = PhysicalLayer(layer=RDD.RES.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.BAS = PhysicalLayer(layer=RDD.BAS.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.COU = PhysicalLayer(layer=RDD.COU.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.CTL = PhysicalLayer(layer=RDD.CTL.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.JP = PhysicalLayer(layer=RDD.JP.LAYER, purpose=RDD.PURPOSE.PROTECTION)
-RDD.PLAYER.JJ = PhysicalLayer(layer=RDD.JJ.LAYER, purpose=RDD.PURPOSE.PRIM.JUNCTION)
-
-# --------------------------------- Physical Vias ------------------------------------
-
-RDD.PLAYER.RC = PhysicalLayer(layer=RDD.RC.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.GC = PhysicalLayer(layer=RDD.GC.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.BC = PhysicalLayer(layer=RDD.BC.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.JC = PhysicalLayer(layer=RDD.JC.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.CC = PhysicalLayer(layer=RDD.CC.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-
-# --------------------------------- Primitive TCells ---------------------------------
-
-RDD.VIAS = ProcessTree()
-
-class TCellRC(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'RC',
- via_layer = RDD.RC.LAYER,
- layer1 = RDD.BAS.LAYER,
- layer2 = RDD.RES.LAYER
- )
-
-RDD.VIAS.RC = TCellRC()
-
-class TCellGC(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'GC',
- via_layer = RDD.GC.LAYER,
- layer1 = RDD.GP.LAYER,
- layer2 = RDD.BAS.LAYER
- )
-
-RDD.VIAS.GC = TCellGC()
-
-class TCellBC(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'BC',
- via_layer = RDD.BC.LAYER,
- layer1 = RDD.BAS.LAYER,
- layer2 = RDD.COU.LAYER
- )
-
-RDD.VIAS.BC = TCellBC()
-
-class TCellJC(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'JC',
- via_layer = RDD.JC.LAYER,
- layer1 = RDD.JJ.LAYER,
- layer2 = RDD.COU.LAYER
- )
-
-RDD.VIAS.JC = TCellJC()
-
-class TCellCC(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'CC',
- via_layer = RDD.CC.LAYER,
- layer1 = RDD.COU.LAYER,
- layer2 = RDD.CTL.LAYER
- )
-
-RDD.VIAS.CC = TCellCC()
-
-# --------------------------------- Device TCells ---------------------------------
-
-RDD.DEVICES = ProcessTree()
-
-class TCellJunction(DynamicDataTree):
- def initialize(self):
- from spira.templates.templates import JunctionTemplate
- self.PCELL = JunctionTemplate(pcell=False)
-
-RDD.DEVICES.JJ = TCellJunction()
-
-# --------------------------------- Finished -------------------------------------
-
-
-
-
diff --git a/demo/pdks/process/general.py b/demo/pdks/process/general.py
deleted file mode 100644
index be6e6ec7..00000000
--- a/demo/pdks/process/general.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from spira.rdd import get_rule_deck
-from spira.rdd.technology import DataTree
-from spira.rdd.technology import ProcessTree
-from spira.rdd.layer import PurposeLayer
-from spira.rdd import RULE_DECK_DATABASE as RDD
-
-# ---------------------------------- Purpose Layers ----------------------------------
-
-RDD.PURPOSE = ProcessTree()
-RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', datatype=20, symbol='METAL')
-RDD.PURPOSE.HOLE = PurposeLayer(name='Polygon holes', datatype=21, symbol='HOLE')
-RDD.PURPOSE.GROUND = PurposeLayer(name='Ground plane polygons', datatype=21, symbol='GND')
-RDD.PURPOSE.SKY = PurposeLayer(name='Sky plane polygons', datatype=21, symbol='SKY')
-RDD.PURPOSE.DUMMY = PurposeLayer(name='Sky plane polygons', datatype=21, symbol='DUM')
-RDD.PURPOSE.KINETIC = PurposeLayer(name='Sky plane polygons', datatype=21, symbol='KIN')
-RDD.PURPOSE.TERM = PurposeLayer(name='Terminal ports specified by the designer', datatype=21, symbol='TERM')
-RDD.PURPOSE.PROTECTION = PurposeLayer(name='Protection layer for via structures', datatype=21, symbol='PRO')
-
-# ---------------------------------- Primitive Layers --------------------------------
-
-RDD.PURPOSE.PRIM = ProcessTree()
-RDD.PURPOSE.PRIM.VIA = PurposeLayer(name='Via layer', datatype=21, symbol='VIA')
-RDD.PURPOSE.PRIM.JUNCTION = PurposeLayer(name='Junction layer', datatype=21, symbol='JJ')
-RDD.PURPOSE.PRIM.NTRON = PurposeLayer(name='nTron layer', datatype=21, symbol='NTRON')
-
-# ---------------------------------- Error Layers ------------------------------------
-
-RDD.PURPOSE.ERROR = ProcessTree()
-RDD.PURPOSE.ERROR.SPACING = PurposeLayer(name='nTron layer', datatype=21, symbol='SP')
-RDD.PURPOSE.ERROR.MIN_WIDTH = PurposeLayer(name='nTron layer', datatype=21, symbol='MAXW')
-RDD.PURPOSE.ERROR.MAX_WIDTH = PurposeLayer(name='nTron layer', datatype=21, symbol='MINW')
-RDD.PURPOSE.ERROR.ENCLOSURE = PurposeLayer(name='nTron layer', datatype=21, symbol='ENC')
-RDD.PURPOSE.ERROR.OVERLAP = PurposeLayer(name='nTron layer', datatype=21, symbol='OVR')
-RDD.PURPOSE.ERROR.DENSITY = PurposeLayer(name='nTron layer', datatype=21, symbol='OVR')
-
-
-
-
diff --git a/demo/pdks/process/mitll_pdk/database.py b/demo/pdks/process/mitll_pdk/database.py
deleted file mode 100644
index d4714caa..00000000
--- a/demo/pdks/process/mitll_pdk/database.py
+++ /dev/null
@@ -1,217 +0,0 @@
-from spira.rdd.technology import DataTree
-from spira.rdd.technology import ProcessTree
-from spira.rdd.technology import PhysicalTree
-from spira.rdd.technology import DynamicDataTree
-from spira.gdsii.layer import Layer
-from spira.rdd.layer import PhysicalLayer
-from spira.rdd import RULE_DECK_DATABASE as RDD
-
-# -------------------------------- Initialize ------------------------------------
-
-RDD.name = 'MiTLL'
-RDD.desc = 'Process fabrication data for the MiTLL process from the USA.'
-
-# ---------------------------------- GDSII ---------------------------------------
-
-RDD.GDSII = DataTree()
-RDD.GDSII.TEXT = 64
-RDD.GDSII.UNITS = 1e-6
-
-# --------------------------------- Metals ---------------------------------------
-
-RDD.LAYER = ProcessTree()
-
-RDD.L0 = ProcessTree()
-RDD.L0.LAYER = Layer(name='L0', number=3)
-RDD.L0.COLOR = '#B6EBE6'
-
-RDD.M0 = ProcessTree()
-RDD.M0.LAYER = Layer(name='M0', number=1)
-RDD.M0.COLOR = '#B6EBE6'
-
-RDD.M1 = ProcessTree()
-RDD.M1.LAYER = Layer(name='M1', number=10)
-RDD.M1.COLOR = '#B6EBE6'
-
-RDD.M2 = ProcessTree()
-RDD.M2.LAYER = Layer(name='M2', number=20)
-RDD.M2.COLOR = '#B6EBE6'
-
-RDD.M3 = ProcessTree()
-RDD.M3.LAYER = Layer(name='M3', number=30)
-RDD.M3.COLOR = '#B6EBE6'
-
-RDD.M4 = ProcessTree()
-RDD.M4.LAYER = Layer(name='M4', number=40)
-RDD.M4.COLOR = '#B6EBE6'
-
-RDD.M5 = ProcessTree()
-RDD.M5.LAYER = Layer(name='M5', number=50)
-RDD.M5.COLOR = '#7FDCD3'
-
-RDD.M6 = ProcessTree()
-RDD.M6.LAYER = Layer(name='M6', number=60)
-RDD.M6.COLOR = '#91E1D9'
-
-RDD.M7 = ProcessTree()
-RDD.M7.LAYER = Layer(name='M7', number=70)
-RDD.M7.COLOR = '#A4E6E0'
-
-RDD.M8 = ProcessTree()
-RDD.M8.LAYER = Layer(name='M8', number=80)
-RDD.M8.COLOR = '#B6EBE6'
-
-RDD.R5 = ProcessTree()
-RDD.R5.LAYER = Layer(name='R5', number=52)
-RDD.R5.COLOR = '#B6EBE6'
-
-# --------------------------------- Vias ----------------------------------------
-
-RDD.C0 = ProcessTree()
-RDD.C0.LAYER = Layer(name='C0', number=4)
-RDD.C0.WIDTH = 0.5
-RDD.C0.M5_METAL = 1.0
-
-RDD.I0 = ProcessTree()
-RDD.I0.LAYER = Layer(name='I0', number=2)
-RDD.I0.WIDTH = 0.5
-RDD.I0.M5_METAL = 1.0
-
-RDD.I1 = ProcessTree()
-RDD.I1.LAYER = Layer(name='I1', number=11)
-RDD.I1.WIDTH = 0.5
-RDD.I1.M5_METAL = 1.0
-
-RDD.I2 = ProcessTree()
-RDD.I2.WIDTH = 0.5
-RDD.I2.LAYER = Layer(name='I2', number=21)
-RDD.I2.WIDTH = 0.5
-RDD.I2.M5_METAL = 1.0
-
-RDD.I3 = ProcessTree()
-RDD.I3.LAYER = Layer(name='I3', number=31)
-RDD.I3.WIDTH = 0.5
-RDD.I3.M5_METAL = 1.0
-
-RDD.I4 = ProcessTree()
-RDD.I4.LAYER = Layer(name='I4', number=41)
-RDD.I4.WIDTH = 0.5
-RDD.I4.M5_METAL = 1.0
-
-RDD.I5 = ProcessTree()
-RDD.I5.LAYER = Layer(name='I5', number=54)
-RDD.I5.WIDTH = 0.5
-RDD.I5.M5_METAL = 1.0
-
-RDD.I6 = ProcessTree()
-RDD.I6.LAYER = Layer(name='I6', number=61)
-RDD.I6.WIDTH = 0.5
-RDD.I6.M5_METAL = 1.0
-
-RDD.I7 = ProcessTree()
-RDD.I7.LAYER = Layer(name='I7', number=71)
-RDD.I7.WIDTH = 0.5
-RDD.I7.M5_METAL = 1.0
-
-RDD.C5 = ProcessTree()
-RDD.C5.LAYER = Layer(name='C5', number=53)
-RDD.C5.WIDTH = 0.5
-RDD.C5.M5_METAL = 1.0
-
-RDD.J5 = ProcessTree()
-RDD.J5.LAYER = Layer(name='J5', number=51)
-RDD.J5.WIDTH = 0.5
-RDD.J5.M5_METAL = 1.0
-
-# ------------------------------- Physical Layers -------------------------------
-
-RDD.PLAYER = PhysicalTree()
-RDD.PLAYER.M0 = PhysicalLayer(layer=RDD.M0.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M1 = PhysicalLayer(layer=RDD.M1.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M2 = PhysicalLayer(layer=RDD.M2.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M3 = PhysicalLayer(layer=RDD.M3.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M4 = PhysicalLayer(layer=RDD.M4.LAYER, purpose=RDD.PURPOSE.GROUND)
-RDD.PLAYER.M5 = PhysicalLayer(layer=RDD.M5.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M6 = PhysicalLayer(layer=RDD.M6.LAYER, purpose=RDD.PURPOSE.METAL)
-RDD.PLAYER.M7 = PhysicalLayer(layer=RDD.M7.LAYER, purpose=RDD.PURPOSE.SKY)
-RDD.PLAYER.M8 = PhysicalLayer(layer=RDD.M8.LAYER, purpose=RDD.PURPOSE.METAL)
-
-# --------------------------------- Vias ----------------------------------------
-
-RDD.PLAYER.C0 = PhysicalLayer(layer=RDD.C0.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I0 = PhysicalLayer(layer=RDD.I0.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I1 = PhysicalLayer(layer=RDD.I1.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I2 = PhysicalLayer(layer=RDD.I2.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I3 = PhysicalLayer(layer=RDD.I3.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I4 = PhysicalLayer(layer=RDD.I4.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I5 = PhysicalLayer(layer=RDD.I5.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I6 = PhysicalLayer(layer=RDD.I6.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.I7 = PhysicalLayer(layer=RDD.I7.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.C5 = PhysicalLayer(layer=RDD.C5.LAYER, purpose=RDD.PURPOSE.PRIM.VIA)
-RDD.PLAYER.J5 = PhysicalLayer(layer=RDD.J5.LAYER, purpose=RDD.PURPOSE.PRIM.JUNCTION)
-
-# --------------------------------- TCells --------------------------------------
-
-RDD.VIAS = ProcessTree()
-
-class TCellI4(DynamicDataTree):
- def initialize(self):
- from ...templates.contact import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'I4',
- via_layer = RDD.I4.LAYER,
- layer1 = RDD.M4.LAYER,
- layer2 = RDD.M5.LAYER
- )
-
-RDD.VIAS.I4 = TCellI4()
-
-class TCellI5(DynamicDataTree):
- def initialize(self):
- from ...templates.contact import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'I5',
- via_layer = RDD.I5.LAYER,
- layer1 = RDD.M5.LAYER,
- layer2 = RDD.M6.LAYER
- )
-
-RDD.VIAS.I5 = TCellI5()
-
-class TCellC5(DynamicDataTree):
- def initialize(self):
- from ...templates.contact import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'C5',
- via_layer = RDD.C5.LAYER,
- layer1 = RDD.R5.LAYER,
- layer2 = RDD.M6.LAYER
- )
-
-RDD.VIAS.C5 = TCellC5()
-
-class TCellJ5(DynamicDataTree):
- def initialize(self):
- from ...templates.contact import ViaTemplate
- self.PCELL = ViaTemplate(
- name = 'J5',
- via_layer = RDD.J5.LAYER,
- layer1 = RDD.M5.LAYER,
- layer2 = RDD.M6.LAYER
- )
-
-RDD.VIAS.J5 = TCellJ5()
-
-# --------------------------------- Device TCells ---------------------------------
-
-RDD.DEVICES = ProcessTree()
-
-class TCellJunction(DynamicDataTree):
- def initialize(self):
- from ...templates.junction import JunctionTemplate
- self.PCELL = JunctionTemplate()
-
-RDD.DEVICES.JJ = TCellJunction()
-
-# --------------------------------- Finished -------------------------------------
-
diff --git a/demo/pdks/templates/contact.py b/demo/pdks/templates/contact.py
deleted file mode 100644
index ece6cc14..00000000
--- a/demo/pdks/templates/contact.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import spira
-from spira import param
-from copy import copy, deepcopy
-
-
-RDD = spira.get_rule_deck()
-
-
-class __TemplateCell__(spira.Cell):
- pass
-
-
-class __TempatePrimitive__(__TemplateCell__):
- pass
-
-
-class ViaTemplate(__TempatePrimitive__):
-
- layer1 = param.LayerField(number=3)
- layer2 = param.LayerField(number=8)
- via_layer = param.LayerField(number=9)
-
- def create_elementals(self, elems):
- M1 = spira.ElementList()
- M2 = spira.ElementList()
- contacts = spira.ElementList()
-
- for e in elems:
- if e.player.purpose == RDD.PURPOSE.METAL:
- if e.player.layer == self.layer1:
- M1 += e
- elif e.player.layer == self.layer2:
- M2 += e
- if e.player.purpose == RDD.PURPOSE.PRIM.VIA:
- if e.player.layer == self.via_layer:
- contacts += e
-
- for D in contacts:
- for M in M1:
- if D.polygon | M.polygon:
- pp = D.polygon | M.polygon
- # TODO: Apply DRC enclosure rule here.
- D.ports[0]._update(name=D.name, layer=M.player.layer)
- for M in M2:
- if D.polygon | M.polygon:
- pp = D.polygon | M.polygon
- # TODO: Apply DRC enclosure rule here.
- D.ports[1]._update(name=D.name, layer=M.player.layer)
- return elems
-
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/database-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/database-checkpoint.ipynb
deleted file mode 100644
index fcd572f7..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/database-checkpoint.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Connect to Database\n",
- "\n",
- "One the most powerful functionalities of SPiRA is effectively connecting data to \n",
- "cell instances. This examples shows how data from the defined RDD are connected\n",
- "to a class using parameters. By connecting parameters to a class through a \n",
- "field allows the given data to be intersepted and manipulated before fully \n",
- "commiting it to the class instance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to link process data from the RDD to default parameter values.\n",
- "2. How to change parameters when creating an instance.\n",
- "3. How to switch to a different RDD by simply importing a new database file.\n",
- "4. Add documentation to a specific parameter."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The Rule Deck Database has to be imported before use. Importing a specific \n",
- "RDD script will initialize and create the data tree. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a pcell using data from the currently set fabrication process."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[SPiRA: Layer] ('', layer 4, datatype 0)\n",
- "1.5\n"
- ]
- }
- ],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number, doc='Layer for the first polygon.')\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH, doc='Box shape width.')\n",
- "\n",
- "pcell = PCell()\n",
- "print(pcell.layer)\n",
- "print(pcell.width)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Switch to a different database."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "< RDD SPiRA-default>\n",
- "\n",
- "---------------------------------------------\n",
- "[RDD] AiST\n",
- "< RDD AiST>\n"
- ]
- }
- ],
- "source": [
- "print(RDD)\n",
- "from demo.pdks.process.aist_pdk import database\n",
- "print(RDD)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Display parameter documentation."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Layer for the first polygon.\n",
- "Box shape width.\n"
- ]
- }
- ],
- "source": [
- "print(PCell.layer.__doc__)\n",
- "print(PCell.width.__doc__)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/elementals-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/elementals-checkpoint.ipynb
deleted file mode 100644
index 966236a1..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/elementals-checkpoint.ipynb
+++ /dev/null
@@ -1,135 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Elementals\n",
- "\n",
- "Now that we have a basic understanding of creating a cell and connecting data to an instance,\n",
- "we have to add layout elementals to represent GDSII primitives. All elementals defined in the \n",
- "`create_elementals` method are automatically added to the instance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to add elementals to a cell using the `create_elementals` method.\n",
- "2. Create a polygon using the framework and add it to the cell.\n",
- "3. How to use the parameters when creating elementals.\n",
- "4. How to write to a GDSII file.\n",
- "\n",
- "Depicted in this example is the three different ways of creating a polygon."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "from spira import LOG\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add polygon elementals to a cell using three different methods."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number)\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " p1 = [[[0,0], [3,0], [3,1], [0,1]]]\n",
- " p2 = [[[4,0], [7,0], [7,1], [4,1]]]\n",
- " p3 = [[[8,0], [11,0], [11,1], [8,1]]]\n",
- "\n",
- " # Create polygon using class parameters.\n",
- " elems += spira.Polygons(p1, gdslayer=self.layer)\n",
- "\n",
- " # Create polygon using new layer number.\n",
- " elems += spira.Polygons(\n",
- " shape=p2,\n",
- " gdslayer=spira.Layer(number=77)\n",
- " )\n",
- "\n",
- " # Create polygon using new shape, number and datatype.\n",
- " elems += spira.Polygons(\n",
- " shape=shapes.Shape(points=p3),\n",
- " gdslayer=spira.Layer(number=51, datatype=1)\n",
- " )\n",
- "\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "View the generated layout."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "pcell = PCell()\n",
- "pcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/ex7_route-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/ex7_route-checkpoint.ipynb
deleted file mode 100644
index f5ec7ae2..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/ex7_route-checkpoint.ipynb
+++ /dev/null
@@ -1,116 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Routing\n",
- "\n",
- "A route is defined as a path polygon with terminal connections. This example creates a new route shape by inheriting from the `spira.Route` class. This route class extends from `shapes.Shape`."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Creating a new custom route curve.\n",
- "2. Adding terminals to the route.\n",
- "3. Using the segment and arc function inherited from `gdspy`.\n",
- "4. Auto connect two terminals via a route."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "import numpy as np\n",
- "from spira.lgm.route.path import __Path__"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a new route curve by defining points as with a typical shape."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "class RouteCurve(spira.Route):\n",
- " \"\"\" Create a path elemental by extending gdspy.Path\n",
- " to include dynamic parameter bindings. \"\"\"\n",
- "\n",
- " def create_points(self, points):\n",
- " spec = {'layer': 1, 'datatype': 1}\n",
- " self.segment(3, '+x', **spec)\n",
- " self.arc(2, -np.pi / 2.0, np.pi / 6.0, **spec)\n",
- " self.segment(4, **spec)\n",
- " self.turn(2, -2.0 * np.pi / 3.0, **spec)\n",
- " points = self.polygons\n",
- " return points\n",
- "\n",
- " def create_ports(self, ports):\n",
- " # TODO: Define the ports connected \n",
- " # to the points here.\n",
- " return ports"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='Route')\n",
- "\n",
- "curve = RouteCurve(width=2, initial_point=(0,0))\n",
- "cell += spira.Polygons(shape=curve)\n",
- "\n",
- "cell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/hierarchy-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/hierarchy-checkpoint.ipynb
deleted file mode 100644
index b3b6073f..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/hierarchy-checkpoint.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Hierarchy\n",
- "\n",
- "This example follows from the `ports` example and shows how the framework can be used to create hierarchical structures."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Create a polygon structure that can be inherited for multiple use.\n",
- "2. Create a cell containing both a terminal and a port."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "General polygon cell, which can be extended,"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PolygonGenerator(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with terminals."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TerminalExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Term(name='P1', midpoint=(0,0), width=self.height)\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with ports."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PortExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += spira.Port(name='P2', midpoint=(10,0))\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with a terminal and port."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TermPortExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can manipulate the generated cells as shown below."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "topcell = spira.Cell('TopCell')\n",
- "\n",
- "t1 = spira.SRef(TerminalExample())\n",
- "p1 = spira.SRef(PortExample(), midpoint=(0, 10))\n",
- "tp = spira.SRef(TermPortExample(), midpoint=(0, 20))\n",
- "\n",
- "t1.rotate(angle=45)\n",
- "t1.translate(dx=-10, dy=0)\n",
- "t1.reflect()\n",
- "\n",
- "p1.rotate(angle=510)\n",
- "p1.translate(dx=5, dy=20)\n",
- "p1.reflect()\n",
- "\n",
- "topcell += t1\n",
- "topcell += p1\n",
- "topcell += tp\n",
- "\n",
- "topcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/ports-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/ports-checkpoint.ipynb
deleted file mode 100644
index c1aa19dd..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/ports-checkpoint.ipynb
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Ports\n",
- "\n",
- "Defining ports in a layout is done using the `create_ports` class method. \n",
- "Ports are objects that connect vertically, such as vias, and terminals \n",
- "are ports that connect horizontally. In this example a basic transmissionline \n",
- "is created with two ports connected to the endpoints."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How ports are added to a cell.\n",
- "2. How terminals are added to a cell.\n",
- "3. Creating a box shape and converting it to a polygon elemental.\n",
- "4. Extend a cell using inheritance.\n",
- "\n",
- "Example `run_ports_1.py` shows how a cell can be extending using inheritance.\n",
- "This is one of the functamental reasons for implementing the `create_` methods\n",
- "in the SPiRA framework. It allows us to effectively segragate data members."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create cell containing a box polygon and two terminals."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TerminalExample(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems\n",
- "\n",
- " def create_ports(self, ports):\n",
- " t1 = spira.Term(name='P1', midpoint=(0,0), width=self.height)\n",
- " ports += t1\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create cell containing a box polygon and two ports."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PortExample(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems\n",
- "\n",
- " def create_ports(self, ports):\n",
- " p1 = spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += p1\n",
- " p2 = spira.Port(name='P2', midpoint=(10,0))\n",
- " ports += p2\n",
- " print(p1)\n",
- " print(p2)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add to the two cells to a single cell."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[SPiRA: Port] (name P1, number 64, midpoint [0, 0], radius 0.25, orientation 0)\n",
- "[SPiRA: Port] (name P2, number 64, midpoint [10, 0], radius 0.25, orientation 0)\n"
- ]
- }
- ],
- "source": [
- "topcell = spira.Cell('TopCell')\n",
- "\n",
- "t1 = spira.SRef(TerminalExample())\n",
- "p1 = spira.SRef(PortExample(), midpoint=(0, 10))\n",
- "\n",
- "t1.rotate(angle=45)\n",
- "t1.translate(dx=-10, dy=0)\n",
- "t1.reflect()\n",
- "\n",
- "topcell += t1\n",
- "topcell += p1\n",
- "\n",
- "topcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/shapes-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/shapes-checkpoint.ipynb
deleted file mode 100644
index abaf4c74..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/shapes-checkpoint.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Shapes\n",
- "\n",
- "In this example a basic arrow shape is created. The shape can \n",
- "be decomposed into a triangle and a box shape."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to extend a shape by inheriting and calling `super()`.\n",
- "2. How to move and rorate a shape.\n",
- "3. How to merge the polygons in a shape.\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "import numpy as np\n",
- "from spira import param\n",
- "from spira import shapes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a basic rectangular triangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class BasicTriangle(shapes.Shape):\n",
- "\n",
- " a = param.FloatField(default=2)\n",
- " b = param.FloatField(default=0.5)\n",
- " c = param.FloatField(default=1)\n",
- "\n",
- " def create_points(self, points):\n",
- " p1 = [0, 0]\n",
- " p2 = [p1[0]+self.b, p1[1]]\n",
- " p3 = [p1[0], p1[1]+self.a]\n",
- " pts = np.array([p1, p2, p3])\n",
- " points = [pts]\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Use two rectangular triangles to create a full triangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TriangleShape(BasicTriangle):\n",
- "\n",
- " def create_points(self, points):\n",
- " points = super().create_points(points)\n",
- " triangle = BasicTriangle(a=self.a, b=self.b, c=self.c)\n",
- " triangle.reflect()\n",
- " points.extend(triangle.points)\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create an arrow by extending a triangle with a rectangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "class ArrowShape(TriangleShape):\n",
- "\n",
- " # TODO: Implement point_list properties.\n",
- " def create_points(self, points):\n",
- " points = super().create_points(points)\n",
- " box = shapes.BoxShape(width=self.b/2, height=3*self.c)\n",
- " box.move(pos=(0,-self.c/2))\n",
- " points.extend(box.points)\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Merge the arrow polygons into a single arrow."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='TriangleCell')\n",
- "\n",
- "s1 = ArrowShape()\n",
- "s1.apply_merge\n",
- "p1 = spira.Polygons(shape=s1, gdslayer=spira.Layer(number=13))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a second rotates and translated arrow."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [],
- "source": [
- "s2 = ArrowShape(a=4)\n",
- "s2.apply_merge\n",
- "s2.rotate(angle=180)\n",
- "s2.move(pos=(10,0))\n",
- "p2 = spira.Polygons(shape=s2, gdslayer=spira.Layer(number=15))\n",
- "\n",
- "cell += p1\n",
- "cell += p2\n",
- "\n",
- "cell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/subcells-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/subcells-checkpoint.ipynb
deleted file mode 100644
index 7fc6ea3a..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/subcells-checkpoint.ipynb
+++ /dev/null
@@ -1,119 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Subcells\n",
- "\n",
- "Cell references can be added to a cell using the `SRef` class. Created elementals can \n",
- "also be wrapped with another class and commited to a cell as a subcell."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to create subcells in a pcell.\n",
- "2. How to wrap elementals in a different cell what will \n",
- " merge similar intersecting polygons.\n",
- "\n",
- "The following example creates three polygons and then merges them using \n",
- "the functionality implicit in another defined class."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a cell containing a rectangular polygon."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PolygonPCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number)\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " p0 = [[[0.3, 0.3], [3.6, 3]],\n",
- " [[1.45, 2.8], [2.45, 5]],\n",
- " [[1.25, 4.75], [2.65, 6]]]\n",
- " for points in p0:\n",
- " shape = shapes.RectangleShape(\n",
- " p1=points[0],\n",
- " p2=points[1],\n",
- " gdslayer=self.layer\n",
- " )\n",
- " ply = spira.Polygons(shape=shape)\n",
- " elems += ply\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add the polygon as a cell reference."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " ply = PolygonPCell()\n",
- " elems += spira.SRef(ply)\n",
- " return elems\n",
- " \n",
- "pcell = PCell()\n",
- "pcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/.ipynb_checkpoints/vanilla-checkpoint.ipynb b/demo/projects/tutorials/.ipynb_checkpoints/vanilla-checkpoint.ipynb
deleted file mode 100644
index 84aacc66..00000000
--- a/demo/projects/tutorials/.ipynb_checkpoints/vanilla-checkpoint.ipynb
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Vanilla Examples\n",
- "\n",
- "Layout elementals can be generated using the native scripting approach, similar to \n",
- "that of the gdspy library. This approach can be used for quick layout experiments, \n",
- "were the connected parameters are not of critical importance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Creating a vanilla layout elemental.\n",
- "2. Connecting parameters to a cell using Python's dynamic nature."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Problems\n",
- "\n",
- "1. Constraints cannot be placed on parameters.\n",
- "2. There is no overview places on the parameters that can or should\n",
- " connected to a specific instance.\n",
- "3. Creating hierarchical layouts becomes syntactically tedious."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import LOG\n",
- "from spira import param\n",
- "from spira import shapes"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "pcell = spira.Cell(name='PCell')\n",
- "pcell.layer = 4\n",
- "pcell.width = 1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a cell and dynamically add parameters without type checking or constraints."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "-> PCell instance\n",
- "[SPiRA: Cell('PCell')] (1 elementals: 0 sref, 1 polygons, 0 labels, 0 ports)\n",
- "4\n",
- "1\n"
- ]
- }
- ],
- "source": [
- "LOG.section('PCell instance')\n",
- "print(pcell)\n",
- "print(pcell.layer)\n",
- "print(pcell.width)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a shape and add it to a cell."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "-> Creating shapes\n",
- "[SPiRA: BoxShape]\n"
- ]
- }
- ],
- "source": [
- "LOG.section('Creating shapes')\n",
- "shape = shapes.BoxShape(center=(5,0), width=1, height=1)\n",
- "pcell += spira.Polygons(shape=shape, gdslayer=spira.Layer(number=46))\n",
- "print(shape)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add cell as a cell reference and plot the layout."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='Multi-cell')\n",
- "cell += spira.SRef(pcell)\n",
- "cell.output()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex0_vanilla.ipynb b/demo/projects/tutorials/ex0_vanilla.ipynb
deleted file mode 100644
index 84aacc66..00000000
--- a/demo/projects/tutorials/ex0_vanilla.ipynb
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Vanilla Examples\n",
- "\n",
- "Layout elementals can be generated using the native scripting approach, similar to \n",
- "that of the gdspy library. This approach can be used for quick layout experiments, \n",
- "were the connected parameters are not of critical importance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Creating a vanilla layout elemental.\n",
- "2. Connecting parameters to a cell using Python's dynamic nature."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Problems\n",
- "\n",
- "1. Constraints cannot be placed on parameters.\n",
- "2. There is no overview places on the parameters that can or should\n",
- " connected to a specific instance.\n",
- "3. Creating hierarchical layouts becomes syntactically tedious."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import LOG\n",
- "from spira import param\n",
- "from spira import shapes"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "pcell = spira.Cell(name='PCell')\n",
- "pcell.layer = 4\n",
- "pcell.width = 1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a cell and dynamically add parameters without type checking or constraints."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "-> PCell instance\n",
- "[SPiRA: Cell('PCell')] (1 elementals: 0 sref, 1 polygons, 0 labels, 0 ports)\n",
- "4\n",
- "1\n"
- ]
- }
- ],
- "source": [
- "LOG.section('PCell instance')\n",
- "print(pcell)\n",
- "print(pcell.layer)\n",
- "print(pcell.width)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a shape and add it to a cell."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "-> Creating shapes\n",
- "[SPiRA: BoxShape]\n"
- ]
- }
- ],
- "source": [
- "LOG.section('Creating shapes')\n",
- "shape = shapes.BoxShape(center=(5,0), width=1, height=1)\n",
- "pcell += spira.Polygons(shape=shape, gdslayer=spira.Layer(number=46))\n",
- "print(shape)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add cell as a cell reference and plot the layout."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='Multi-cell')\n",
- "cell += spira.SRef(pcell)\n",
- "cell.output()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex1_database.ipynb b/demo/projects/tutorials/ex1_database.ipynb
deleted file mode 100644
index fcd572f7..00000000
--- a/demo/projects/tutorials/ex1_database.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Connect to Database\n",
- "\n",
- "One the most powerful functionalities of SPiRA is effectively connecting data to \n",
- "cell instances. This examples shows how data from the defined RDD are connected\n",
- "to a class using parameters. By connecting parameters to a class through a \n",
- "field allows the given data to be intersepted and manipulated before fully \n",
- "commiting it to the class instance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to link process data from the RDD to default parameter values.\n",
- "2. How to change parameters when creating an instance.\n",
- "3. How to switch to a different RDD by simply importing a new database file.\n",
- "4. Add documentation to a specific parameter."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The Rule Deck Database has to be imported before use. Importing a specific \n",
- "RDD script will initialize and create the data tree. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a pcell using data from the currently set fabrication process."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[SPiRA: Layer] ('', layer 4, datatype 0)\n",
- "1.5\n"
- ]
- }
- ],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number, doc='Layer for the first polygon.')\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH, doc='Box shape width.')\n",
- "\n",
- "pcell = PCell()\n",
- "print(pcell.layer)\n",
- "print(pcell.width)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Switch to a different database."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "< RDD SPiRA-default>\n",
- "\n",
- "---------------------------------------------\n",
- "[RDD] AiST\n",
- "< RDD AiST>\n"
- ]
- }
- ],
- "source": [
- "print(RDD)\n",
- "from demo.pdks.process.aist_pdk import database\n",
- "print(RDD)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Display parameter documentation."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Layer for the first polygon.\n",
- "Box shape width.\n"
- ]
- }
- ],
- "source": [
- "print(PCell.layer.__doc__)\n",
- "print(PCell.width.__doc__)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex2_elementals.ipynb b/demo/projects/tutorials/ex2_elementals.ipynb
deleted file mode 100644
index 966236a1..00000000
--- a/demo/projects/tutorials/ex2_elementals.ipynb
+++ /dev/null
@@ -1,135 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Elementals\n",
- "\n",
- "Now that we have a basic understanding of creating a cell and connecting data to an instance,\n",
- "we have to add layout elementals to represent GDSII primitives. All elementals defined in the \n",
- "`create_elementals` method are automatically added to the instance."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to add elementals to a cell using the `create_elementals` method.\n",
- "2. Create a polygon using the framework and add it to the cell.\n",
- "3. How to use the parameters when creating elementals.\n",
- "4. How to write to a GDSII file.\n",
- "\n",
- "Depicted in this example is the three different ways of creating a polygon."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "from spira import LOG\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add polygon elementals to a cell using three different methods."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number)\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " p1 = [[[0,0], [3,0], [3,1], [0,1]]]\n",
- " p2 = [[[4,0], [7,0], [7,1], [4,1]]]\n",
- " p3 = [[[8,0], [11,0], [11,1], [8,1]]]\n",
- "\n",
- " # Create polygon using class parameters.\n",
- " elems += spira.Polygons(p1, gdslayer=self.layer)\n",
- "\n",
- " # Create polygon using new layer number.\n",
- " elems += spira.Polygons(\n",
- " shape=p2,\n",
- " gdslayer=spira.Layer(number=77)\n",
- " )\n",
- "\n",
- " # Create polygon using new shape, number and datatype.\n",
- " elems += spira.Polygons(\n",
- " shape=shapes.Shape(points=p3),\n",
- " gdslayer=spira.Layer(number=51, datatype=1)\n",
- " )\n",
- "\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "View the generated layout."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "pcell = PCell()\n",
- "pcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex3_shapes.ipynb b/demo/projects/tutorials/ex3_shapes.ipynb
deleted file mode 100644
index abaf4c74..00000000
--- a/demo/projects/tutorials/ex3_shapes.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Shapes\n",
- "\n",
- "In this example a basic arrow shape is created. The shape can \n",
- "be decomposed into a triangle and a box shape."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to extend a shape by inheriting and calling `super()`.\n",
- "2. How to move and rorate a shape.\n",
- "3. How to merge the polygons in a shape.\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "import numpy as np\n",
- "from spira import param\n",
- "from spira import shapes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a basic rectangular triangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class BasicTriangle(shapes.Shape):\n",
- "\n",
- " a = param.FloatField(default=2)\n",
- " b = param.FloatField(default=0.5)\n",
- " c = param.FloatField(default=1)\n",
- "\n",
- " def create_points(self, points):\n",
- " p1 = [0, 0]\n",
- " p2 = [p1[0]+self.b, p1[1]]\n",
- " p3 = [p1[0], p1[1]+self.a]\n",
- " pts = np.array([p1, p2, p3])\n",
- " points = [pts]\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Use two rectangular triangles to create a full triangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TriangleShape(BasicTriangle):\n",
- "\n",
- " def create_points(self, points):\n",
- " points = super().create_points(points)\n",
- " triangle = BasicTriangle(a=self.a, b=self.b, c=self.c)\n",
- " triangle.reflect()\n",
- " points.extend(triangle.points)\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create an arrow by extending a triangle with a rectangle."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "class ArrowShape(TriangleShape):\n",
- "\n",
- " # TODO: Implement point_list properties.\n",
- " def create_points(self, points):\n",
- " points = super().create_points(points)\n",
- " box = shapes.BoxShape(width=self.b/2, height=3*self.c)\n",
- " box.move(pos=(0,-self.c/2))\n",
- " points.extend(box.points)\n",
- " return points"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Merge the arrow polygons into a single arrow."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='TriangleCell')\n",
- "\n",
- "s1 = ArrowShape()\n",
- "s1.apply_merge\n",
- "p1 = spira.Polygons(shape=s1, gdslayer=spira.Layer(number=13))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a second rotates and translated arrow."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [],
- "source": [
- "s2 = ArrowShape(a=4)\n",
- "s2.apply_merge\n",
- "s2.rotate(angle=180)\n",
- "s2.move(pos=(10,0))\n",
- "p2 = spira.Polygons(shape=s2, gdslayer=spira.Layer(number=15))\n",
- "\n",
- "cell += p1\n",
- "cell += p2\n",
- "\n",
- "cell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex4_subcells.ipynb b/demo/projects/tutorials/ex4_subcells.ipynb
deleted file mode 100644
index 7fc6ea3a..00000000
--- a/demo/projects/tutorials/ex4_subcells.ipynb
+++ /dev/null
@@ -1,119 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Subcells\n",
- "\n",
- "Cell references can be added to a cell using the `SRef` class. Created elementals can \n",
- "also be wrapped with another class and commited to a cell as a subcell."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How to create subcells in a pcell.\n",
- "2. How to wrap elementals in a different cell what will \n",
- " merge similar intersecting polygons.\n",
- "\n",
- "The following example creates three polygons and then merges them using \n",
- "the functionality implicit in another defined class."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a cell containing a rectangular polygon."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PolygonPCell(spira.Cell):\n",
- "\n",
- " layer = param.LayerField(number=RDD.BAS.LAYER.number)\n",
- " width = param.FloatField(default=RDD.BAS.WIDTH)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " p0 = [[[0.3, 0.3], [3.6, 3]],\n",
- " [[1.45, 2.8], [2.45, 5]],\n",
- " [[1.25, 4.75], [2.65, 6]]]\n",
- " for points in p0:\n",
- " shape = shapes.RectangleShape(\n",
- " p1=points[0],\n",
- " p2=points[1],\n",
- " gdslayer=self.layer\n",
- " )\n",
- " ply = spira.Polygons(shape=shape)\n",
- " elems += ply\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add the polygon as a cell reference."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PCell(spira.Cell):\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " ply = PolygonPCell()\n",
- " elems += spira.SRef(ply)\n",
- " return elems\n",
- " \n",
- "pcell = PCell()\n",
- "pcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex5_ports.ipynb b/demo/projects/tutorials/ex5_ports.ipynb
deleted file mode 100644
index c1aa19dd..00000000
--- a/demo/projects/tutorials/ex5_ports.ipynb
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Ports\n",
- "\n",
- "Defining ports in a layout is done using the `create_ports` class method. \n",
- "Ports are objects that connect vertically, such as vias, and terminals \n",
- "are ports that connect horizontally. In this example a basic transmissionline \n",
- "is created with two ports connected to the endpoints."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. How ports are added to a cell.\n",
- "2. How terminals are added to a cell.\n",
- "3. Creating a box shape and converting it to a polygon elemental.\n",
- "4. Extend a cell using inheritance.\n",
- "\n",
- "Example `run_ports_1.py` shows how a cell can be extending using inheritance.\n",
- "This is one of the functamental reasons for implementing the `create_` methods\n",
- "in the SPiRA framework. It allows us to effectively segragate data members."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create cell containing a box polygon and two terminals."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TerminalExample(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems\n",
- "\n",
- " def create_ports(self, ports):\n",
- " t1 = spira.Term(name='P1', midpoint=(0,0), width=self.height)\n",
- " ports += t1\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create cell containing a box polygon and two ports."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PortExample(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems\n",
- "\n",
- " def create_ports(self, ports):\n",
- " p1 = spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += p1\n",
- " p2 = spira.Port(name='P2', midpoint=(10,0))\n",
- " ports += p2\n",
- " print(p1)\n",
- " print(p2)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Add to the two cells to a single cell."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[SPiRA: Port] (name P1, number 64, midpoint [0, 0], radius 0.25, orientation 0)\n",
- "[SPiRA: Port] (name P2, number 64, midpoint [10, 0], radius 0.25, orientation 0)\n"
- ]
- }
- ],
- "source": [
- "topcell = spira.Cell('TopCell')\n",
- "\n",
- "t1 = spira.SRef(TerminalExample())\n",
- "p1 = spira.SRef(PortExample(), midpoint=(0, 10))\n",
- "\n",
- "t1.rotate(angle=45)\n",
- "t1.translate(dx=-10, dy=0)\n",
- "t1.reflect()\n",
- "\n",
- "topcell += t1\n",
- "topcell += p1\n",
- "\n",
- "topcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex6_hierarchy.ipynb b/demo/projects/tutorials/ex6_hierarchy.ipynb
deleted file mode 100644
index b3b6073f..00000000
--- a/demo/projects/tutorials/ex6_hierarchy.ipynb
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Hierarchy\n",
- "\n",
- "This example follows from the `ports` example and shows how the framework can be used to create hierarchical structures."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Create a polygon structure that can be inherited for multiple use.\n",
- "2. Create a cell containing both a terminal and a port."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [],
- "source": [
- "import spira\n",
- "from spira import param\n",
- "from spira import shapes\n",
- "\n",
- "RDD = spira.get_rule_deck()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "General polygon cell, which can be extended,"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PolygonGenerator(spira.Cell):\n",
- "\n",
- " width = param.FloatField(default=10)\n",
- " height = param.FloatField(default=1)\n",
- "\n",
- " def create_elementals(self, elems):\n",
- " shape = shapes.BoxShape(center=(5,0), width=self.width, height=self.height)\n",
- " elems += spira.Polygons(shape=shape)\n",
- " return elems"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with terminals."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TerminalExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Term(name='P1', midpoint=(0,0), width=self.height)\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with ports."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "class PortExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += spira.Port(name='P2', midpoint=(10,0))\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Extend polygon with a terminal and port."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "class TermPortExample(PolygonGenerator):\n",
- "\n",
- " def create_ports(self, ports):\n",
- " ports += spira.Port(name='P1', midpoint=(0,0))\n",
- " ports += spira.Term(name='P2', midpoint=(10,0), width=self.height, orientation=180)\n",
- " return ports"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can manipulate the generated cells as shown below."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "topcell = spira.Cell('TopCell')\n",
- "\n",
- "t1 = spira.SRef(TerminalExample())\n",
- "p1 = spira.SRef(PortExample(), midpoint=(0, 10))\n",
- "tp = spira.SRef(TermPortExample(), midpoint=(0, 20))\n",
- "\n",
- "t1.rotate(angle=45)\n",
- "t1.translate(dx=-10, dy=0)\n",
- "t1.reflect()\n",
- "\n",
- "p1.rotate(angle=510)\n",
- "p1.translate(dx=5, dy=20)\n",
- "p1.reflect()\n",
- "\n",
- "topcell += t1\n",
- "topcell += p1\n",
- "topcell += tp\n",
- "\n",
- "topcell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/demo/projects/tutorials/ex7_route.ipynb b/demo/projects/tutorials/ex7_route.ipynb
deleted file mode 100644
index f5ec7ae2..00000000
--- a/demo/projects/tutorials/ex7_route.ipynb
+++ /dev/null
@@ -1,116 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Routing\n",
- "\n",
- "A route is defined as a path polygon with terminal connections. This example creates a new route shape by inheriting from the `spira.Route` class. This route class extends from `shapes.Shape`."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Demonstrates\n",
- "\n",
- "1. Creating a new custom route curve.\n",
- "2. Adding terminals to the route.\n",
- "3. Using the segment and arc function inherited from `gdspy`.\n",
- "4. Auto connect two terminals via a route."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "---------------------------------------------\n",
- "[RDD] SPiRA-default\n",
- "\n",
- "[SPiRA] Version 0.0.2-Auron - MIT License\n",
- "---------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "import spira\n",
- "import numpy as np\n",
- "from spira.lgm.route.path import __Path__"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Create a new route curve by defining points as with a typical shape."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "class RouteCurve(spira.Route):\n",
- " \"\"\" Create a path elemental by extending gdspy.Path\n",
- " to include dynamic parameter bindings. \"\"\"\n",
- "\n",
- " def create_points(self, points):\n",
- " spec = {'layer': 1, 'datatype': 1}\n",
- " self.segment(3, '+x', **spec)\n",
- " self.arc(2, -np.pi / 2.0, np.pi / 6.0, **spec)\n",
- " self.segment(4, **spec)\n",
- " self.turn(2, -2.0 * np.pi / 3.0, **spec)\n",
- " points = self.polygons\n",
- " return points\n",
- "\n",
- " def create_ports(self, ports):\n",
- " # TODO: Define the ports connected \n",
- " # to the points here.\n",
- " return ports"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "cell = spira.Cell(name='Route')\n",
- "\n",
- "curve = RouteCurve(width=2, initial_point=(0,0))\n",
- "cell += spira.Polygons(shape=curve)\n",
- "\n",
- "cell.output()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.1"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/docs/_0_methodology.rst b/docs/_0_methodology.rst
new file mode 100644
index 00000000..8ed97ad7
--- /dev/null
+++ b/docs/_0_methodology.rst
@@ -0,0 +1,92 @@
+###########
+Methodology
+###########
+
+Using general mathematics and science as an analogy, a basic understanding
+can be constructed of the importance of software in IC design: *Mathematics is
+the discipline of proving provable statements true and science is the discipline
+of proving provable statements false*.
+
+***************************************
+The Importance of Software in IC Design
+***************************************
+
+In software development, testing shows the presence of bugs and not the absence thereof. Software development is not
+a mathematical endeavour, even though it seems to manipulate mathematical
+constructs. Rather, software is more connected to science in the sense that it
+shows correctness by failing to show incorrectness. Therefore, IC design is to
+some extent only as good as the software systems that can prove the design
+incorrect. Circuit verification software only shows the engineer where
+mistakes are made, if any.
+
+Structured programming elicits a design architect that recursively decomposes
+a program into a set of small provable functions. Unit tests can be
+used to try and prove these small provable functions incorrect. If such tests
+fail to prove incorrectness, then the functions are deemed to be correct enough
+for all intents and purposes. Superconducting Electronic Design Automation
+(S-EDA) tools from a macro view can be thought of as a set of unit tests for
+a hardware design engineer to stress test their circuit layouts.
+
+***********************************
+The Development Psychology of SPiRA
+***********************************
+
+The development history of SPiRA can be broken down into four phases. First,
+a rudimentary version that consisted of a collection of scripts. Second, a
+small project that assimilated a minimum set of functions and class objects.
+Third, a large systemic project with multiple coherently connected modules.
+Finally, a meticulously designed framework that uses special coding techniques
+to create dynamic binding, software pattern implementation, data abstraction
+and custom classes.
+
+Before understanding the reasoning behind developing a parameterized framework
+for *physical design verification* it is imporant to first categorize the type
+of problem we are dealing with:
+
+Deductive Logic
+===============
+
+Deductive logic implies applying general rules which hold over the entirety
+of a closed domain of discourse: Software solutions that will most likely not
+change in the near future, tend to solve problems that are implicit in the technology.
+The reading and parsing of GDSII layouts, and geometry modeling,
+are examples implemented, through solutions that use deductive reasoning.
+
+Inductive Logic
+===============
+
+Inductive logic is inherently uncertain; the results concluded from inductive reasoning are more nuanced than simply stating; if this, then that.
+Consequently, heuristics can be derived using inductive reasoning to develop a sufficient SDE verification tool:
+Implementing fabrication design rules must be done following inductive logic, since future technology changes in the superconductor
+electronics field are still speculative. For instance, currently there is no specific PDK setup for superconductor electronics, and consequently, it
+can either be assumed that the future PDK versions will be similar to that of semiconducting, or that it will prevail and create a new set of standards.
+Also, the rapid changes being made in the semiconductor field add to the uncertainty of future metadata in the field of superconductivity.
+
+The symmetries between the superconductor and the semiconductor field are not necessarily indicative of the future evolution of superconductor electronics.
+Therefore, a paradigmatic software system (not just a solution) has to be developed, which can accommodate for dynamic "meta-changes", while still being extendible and maintainable.
+Physical design verification is highly dependent on the modelling of design rules. Layout generators allows us to effectively create our own programmable
+circuit models. Only minor differences exist between different fabrication processes, which enables us to develop a general software verification package
+by focusing on creating solution heuristics, through inductive models, rather than trying to develop concrete deductive solutions.
+
+Metaprogramming
+===============
+
+Technical sophistication can, at some level, cause degradation.
+Metaprogramming forms the foundation of the SPiRA framework and therefore it becomes
+apparent to start with a more general explanation of a metamodel.
+A model is an abstraction of a real-world phenomena. A metamodel is an
+even higher level of abstraction, which coalesces the properties of the original
+model. A model conforms to its metamodel like a human conforms its understanding to the sophistication of its internal dictionary (language)—or lack thereof.
+Metamodeling is the construction of a collection of concepts within a certain domain. Metamodeling involves defining the output and input relationships and
+then fitting the correct metamodels to represent the desired behaviour.
+Analogously, binding generic data to a layout has to be done by developing
+a metamodel of the system. The inherit purpose of the base metaclasses in
+the SPiRA framework is to bind data to a class object depending on the
+class composition. This has to be done after defining the class constituents
+(parameters), but before class creation. Hence, the use of metaclasses. In
+Python a class is an object that can be dynamically manipulated. Therefore,
+constraints have to be implemented on the class so as to overcome information
+overloading. In order to constrain the class, it has to be known which data to
+filter and which to process, which must then be added to the class as attributes.
+In doing this, the concept evolves that the accepted data itself can be restricted
+to a specific domain. This is the core principle behind the **validate-by-design** method
diff --git a/docs/_1_overview.rst b/docs/_1_overview.rst
new file mode 100644
index 00000000..3b52a40b
--- /dev/null
+++ b/docs/_1_overview.rst
@@ -0,0 +1,764 @@
+########
+Overview
+########
+
+This overview discusses the basic constituents of the **SPiRA** framework.
+This includes how data from the fabrication process is connected to the design environment,
+the basic design template for creating parameterized cells, and how different layout
+elements are defined.
+
+******************
+Process Design Kit
+******************
+
+The process design kit (PDK) is a set of technology files needed to implement
+the physical aspects of a layout design. Application-specific rules specified
+in the PDK controls how physical design applications work.
+
+A new PDK scheme is introduced. The Python programming language is used to
+bind PDK data to a set of classes, called data trees, that uniquely categorises
+PDK data. This new PDK scheme is called the Rule Deck Database (RDD), also
+refered to as the Rule Design Database. By having a native PDK in Python it
+becomes possible to use methods from the SPiRA framework to create a
+more descriptive PDK database. A design process typically contains the
+following aspects:
+
+* *GDSII Data*: Contains general settings required by the GDSII library, such as grid size.
+* *Process Data*: Contains the process layers, layer purposes, layer parameters, and layer mappings.
+* *Virtual Modelling*: Define derived layers that describes layer boolean operations.
+
+
+Initialization
+==============
+
+All caps are used to represent the *RDD* syntax. The reason being to make the
+script structure clearly distinguishable from the rest of the framework source
+code. First, the RDD object is initialized, followed by the process name and
+description, and then the GDSII related variables are defined.
+
+.. code-block:: python
+
+ RDD.GDSII = ParameterDatabase()
+ RDD.GDSII.UNIT = 1e-6
+ RDD.GDSII.GRID = 1e-12
+ RDD.GDSII.PRECISION = 1e-9
+
+
+Process Data
+============
+
+Process data relates to data provided by a specific fabrication technology.
+
+Process Layer
+-------------
+
+The first step in creating a layer is to define the process step that
+it represents in mask fabrication. The layer **process** defines a specific
+fabrciation function, for examples **metalization**. There can be multiple
+different drawing layers for a single process. A process database object
+is created that contains all the different process steps in a specific
+fabrication process:
+
+.. code-block:: python
+
+ RDD.PROCESS = ProcessLayerDatabase()
+
+ RDD.PROCESS.R1 = ProcessLayer(name='Resistor 1', symbol='R1')
+ RDD.PROCESS.M1 = ProcessLayer(name='Metal 1', symbol='M1')
+ RDD.PROCESS.C1 = ProcessLayer(name='Contact 1', symbol='C1')
+
+Each process has a name that describes the process function, and
+a *symbol* that is used to identify the process.
+
+Purpose Layer
+-------------
+
+The **purpose** indicates the use of the layer. Multiple layers with
+the same process but different purposes can be created.
+Similar to a process value each purpose contains a name and a unique symbol.
+Purposes are defined using a purpose database object:
+
+.. code-block:: python
+
+ RDD.PURPOSE = PurposeLayerDatabase()
+
+ RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', symbol='METAL')
+ RDD.PURPOSE.VIA = PurposeLayer(name='Contact', symbol='VIA')
+
+Process Parameters
+------------------
+
+Parameters are added to a process by creating a *parameter* database object
+that has a key value equal to the symbol of a pre-defined process:
+
+.. code-block:: python
+
+ RDD.M1 = ParameterDatabase()
+ RDD.M1.MIN_SIZE = 0.7
+ RDD.M1.MAX_WIDTH = 20.0
+ RDD.M1.J5_MIN_SURROUND = 0.5
+ RDD.M1.MIN_SURROUND_OF_I5 = 0.5
+
+Any number of variables can be added to the database using the dot operator.
+The code above defines a set of design parameters for the **M1 process**.
+
+Physical Layers
+---------------
+
+*Physical Layers* are unique to SPiRA and is defined as a layer that has a
+defined process and purpose. A physical layer (PLayer) defines the different
+purposes that a single process can be used for in a layout design.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1 = PhysicalLayerDatabase()
+ RDD.PLAYER.C1 = PhysicalLayerDatabase()
+
+ RDD.PLAYER.C1.VIA = PhysicalLayer(process=RDD.PROCESS.C1, purpose=RDD.PURPOSE.VIA)
+ RDD.PLAYER.M1.METAL = PhysicalLayer(process=RDD.PROCESS.M1, purpose=RDD.PURPOSE.METAL)
+
+The code above illustrates that the layer ``M1`` is a metal layer on process ``M1``,
+and layer ``C1`` is a contact via on process ``C1``.
+
+Virtual Modelling
+~~~~~~~~~~~~~~~~~
+
+*Derived Layers* are used to define different PLayer boolean operations.
+They are typically used for virtual modelling and polygon operations,
+such as merged polygons or polygon holes.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1.EDGE_CONNECTED = RDD.PLAYER.M1.METAL & RDD.PLAYER.M1.OUTSIDE_EDGE_DISABLED
+
+The code above defines a derived layer that is generated when a layer with process ``M1`` and
+purpose ``metal`` overlaps the outside edges of a ``M1`` layer.
+
+
+.. ---------------------------------------------------------------------------------------------------
+
+
+**********
+Parameters
+**********
+
+Designing a generated layout requires modeling its parameters. To create an effective design
+environment it becomes paramount to define parameter restrictions.
+SPiRA uses a meta-configuration to define object parameters, which enables the following features:
+
+* Default values can be set to each parameter.
+* Documentation for each parameter can be added.
+* Parameters can be cached to ensure they aren't calculated multiple times.
+
+Introduction
+============
+
+Parameters are derived from the :py:class:`spira.Parameter` class. The
+:py:class:`ParameterInitializer` is responsible for storing the parameters of an
+instance. To define parameters the class has to inherit from the :py:class:`ParameterInitializer`
+class. The following code creates a layer object with a number parameter.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter()
+
+ >>> layer = Layer(number=9)
+ >>> layer.number
+ 9
+
+At first glance this may not seem to add any value that Python by default does not already adds.
+The same example can be generated using native Python:
+
+.. code-block:: python
+
+ class Layer(object):
+ def __init__(self, number=0):
+ self.number = number
+
+The true value of the parameterized framework becomes clear when adding attributes to the parameter, such as the **default** value, **restrictions**, **preprocess** and **doc**.
+These attributes allow a parameter to be type-checked and documented.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.INTEGER,
+ preprocess=spira.ProcessorInt(),
+ doc='Advanced parameter.')
+
+The newly defined parameter has more advanced features that makes for
+a more powerful design framework:
+
+.. code-block:: python
+
+ # The default value of the parameter is 0.
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+
+ # The parameter can be updated with an integer.
+ >>> layer.number = 9
+ >>> layer.number
+ 9
+
+ # The string can be preprocessed to an interger.
+ >>> layer.number = '8'
+ >>> layer.number
+ 8
+
+ # The string cannot be preprocessed and throws an error.
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+
+Default
+=======
+
+When defining a parameter the default value can be explicitly set using the :py:data:`default` attribute.
+This is a simple method of declaring your parameter.
+For more complex functionality the default function attribute, :py:data:`fdef_name`, can be used.
+This attribute defines the name of a class method that will be used to derive the default value of the parameter.
+Advantages of this implementation is:
+
+* **Logic operations:** The default value can be derived from other defined parameters.
+* **Inheritance:** The default value can be overwritten using class inheritance.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0)
+ datatype = spira.Parameter(fdef_name='create_datatype')
+
+ def create_datatype(self):
+ return 2 + 3
+
+ >>> layer = Layer()
+ >>> (layer.number, layer.datatype)
+ (0, 5)
+
+
+Restrictions
+============
+
+The validity of a parameter value is calculated by the *restriction* attribute.
+In certain cases we want to restrict a parameter value to a certain type or range of values, for example:
+
+* Validate that the value has a specific type, such as a via PCell.
+* Validate that the value falls between a specified minimum and maximum.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, restrictions=spira.RestrictRange(2,5))
+
+The example above restricts the number parameter of the layer to be between 2 and 5:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number = 3
+ 3
+ >>> layer.number = 1
+ ValueError: Invalid parameter assignment 'number' of cell 'Layer' with value '1', which is not compatible with 'Range Restriction: [2, 5)'.
+
+Preprocessors
+=============
+
+The preprocess attribute converts a received value before assigning it to the parameter.
+Preprocessors are typically used to convert a value of invalid type to one of a valid type, such as converting a float to an integer.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, preprocess=spira.ProcessorInt())
+
+ >>> layer = Layer()
+ >>> layer.number = 1
+ 1
+ >>> layer.number = 2.1
+ 2
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+Documentation
+=============
+
+Documentation can be added to the parameter using the :py:data:`doc` attribute.
+The created class can also be documented using triple qoutation marks.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ """ This is a layer class. """
+ number = spira.Parameter(default=0, doc='Parameter documentation.')
+
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+ >>> layer.__doc__
+ This is a layer class.
+ >>> layer.number.__doc__
+ Parameter documentation.
+
+Cache
+=====
+
+SPiRA automatically caches parameters once they have been initialized.
+When using class methods to define default parameters using the :py:data:`fdef_name` attribute, the value is stored when called for the first time.
+Calling this value for the second time will not lead to a re-calculation, but rather the value will be retrieved from the cached dictionary.
+The cache is automatically cleared when **any** parameter in the instance is updated, since other parameters might be dependent on the changed parameters.
+
+.. ---------------------------------------------------------------
+
+*******************
+Parameterized Cells
+*******************
+
+GDSII layouts encapsulate element design in the visual domain.
+Parameterized cells encapsulates elements in the programming domain, and utilizes this domain to map external data to elements.
+This external data can be data from the PDK or values extracted from an already designed layout using simulation software, such as InductEx.
+The SPiRA framework uses a scripting framework approach to connect the visual domain with a programming domain.
+The implemented architecture of SPiRA mimics the physical layout patterns implicit in hand-designed layouts.
+This framework architecture evolved by developing code heuristics that emerged from the process of creating a PCell.
+
+Creating a PCell is done by defining the elements and parameters required to create the desired layout.
+The relationship between the elements and parameters are described in a template format.
+Template design is an innate feature of parameterizing cell layouts.
+This heuristic concludes to develop a framework to effectively describe the different constituents of a PCell, rather than developing an API.
+The SPiRA framework was built from the following concepts:
+
+1. **Defining Element Shapes** This step defines the geometrical shapes from which an element polygon is generated.
+The supported shapes are rectangles, triangles, circles, as well as regular and irregular polygons.
+Each of these shapes has a set of parameters that control the pattern dimensions, e.g. the parameterized rectangle has two parameters, ``width`` and ``length``, that defines its length and width, respectively.
+
+2. **Element Shape Transformations** This step describes the relation between the elements through a set of operations, that includes transformations of a shape in the x-y plane.
+Transforming an element involves: movement with a specific offset relative to its original location, rotation of a shape around its center with a specific angle,
+reflection of a shape around a idefined line, and aligning a shape to another shape with a specific offset and angle.
+
+3. **PDK Binding** The final step is binding data from the PDK to each created pattern. In SPiRA, process related data is defined in the RDD.
+From this database the required data can be linked to any specific pattern by defining parameters and their design restrictions.
+
+Shapes
+======
+
+A shape is a basic 2-dimentional geometric pattern that consists of a list of points.
+These points can be manipulated and transformed as required by the designer, before commiting it to a layout cell.
+
+.. code-block:: python
+
+ class ShapeExample(spira.Cell):
+
+ def create_points(self, points):
+ points = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ return points
+
+You can create your own shape by creating a class that inherits from :py:class:`spira.Shape`.
+The shape coordinates are calculated by the :py:data:`create_points` class method that is innate to any :py:class:`spira.Shape` derived instance.
+The :py:class:`spira.Shape` class offers a rich set of methods for basic and advanced shape manipulation:
+
+.. code-block:: python
+
+ >>> shape = ShapeExample()
+ >>> shape.points
+ [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ >>> shape.area
+ 88
+ >>> shape.move((10, 0))
+ [[10, 0], [12, 2], [12, 6], [4, 6], [4, -6], [6, -4], [6, 4], [10, 4]]
+ >>> shape.x_coords
+ [10 12 12 4 4 6 6 10]
+
+Elements
+========
+
+The purpose of elements are to wrap geometry data with GDSII layout data.
+In SPiRA the following elements are defined:
+
+* **Polygon**: Connects a shape object with layout data (layer number, datatype).
+* **Label**: Generates text data in a GDSII layout.
+* **SRef**: A structure references, or sometimes called a cell reference, refers to another cell object, but with difference transformations.
+
+There are other special objects, called *element groups* that can be used in the design environment.
+These objects are mainly a combination of polygons and relations between polygons.
+These special objects are referenced as if they represent a single shape, and its outline is determined by its bounding box dimensions.
+The following element groups are defined in the SPiRA framework:
+
+* **Cells**: Is the most generic group that binds different parameterized elements or clusters, while conserving the geometrical relations between these polygons or clusters.
+* **Group**: A set of elements can be grouped in a logical container.
+* **Ports**: A port is simply a polygon with a label on a dedicated process layer. Typically, port elements are placed on conducting metal layers.
+* **Routes**: A route is defined as a cell that consists of a polygon element and a set of edge ports, that resembles a path-like structure.
+
+The SPiRA design environment for creating a PCEll is broken down into the following basic templated steps:
+
+.. code-block:: python
+
+ class PCell(spira.Cell):
+ """ My first parameterized cell. """
+
+ # Define parameters here
+ number = spira.IntegerParameter(default=0, doc='Parameter example number.')
+
+ def create_elements(self, elems):
+ # Define elements here.
+ return elems
+
+ def create_ports(self, ports):
+ # Define ports here.
+ return ports
+
+The most basic SPiRA template to generate a PCell is shown above, and consists of three parts:
+
+1. Create a new cell by inheriting from :py:class:`spira.Cell`. This connects the class to the SPiRA framework when constructed.
+2. Define the PCell parameters as class attributes.
+3. Elements and ports are defined in the :py:data:`create_elements` and :py:data:`create_ports` class methods, which is automatically added to the cell instance.
+ The create methods are special SPiRA class methods that specify how the parameters are used to create the cell.
+
+.. code-block:: python
+
+ class PolygonExample(spira.Cell):
+
+ def create_elements(self, elems):
+ pts = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ shape = spira.Shape(points=pts)
+ elems += spira.Polygon(shape=shape, layer=spira.Layer(1))
+ return elems
+
+ >>> D = PolygonExample()
+ >>> D.gdsii_output()
+
+.. image:: _figures/_elements.png
+ :align: center
+
+The code above illustrates the creation of a polygon object, using the already defined shape.
+The polygon object connects the shape to a GDSII library with a GDSII layer number equal to :math:`1`.
+Once the polygon has been created it can be added to the cell instance using the ``+`` operator
+to increment the :py:data:`elems` list.
+
+Group
+=====
+
+Groups are used to apply an operation on a set of polygons, such a retrieving their combined bounding box.
+The following example illistrated the use of :py:class:`spira.Group` to generate a metal bounding box
+around a set of polygons:
+
+.. code-block:: python
+
+ class GroupExample(spira.Cell):
+
+ def create_elements(self, elems):
+
+ group = spira.Group()
+ group += spira.Rectangle(p1=(0,0), p2=(10,10), layer=spira.Layer(1))
+ group += spira.Rectangle(p1=(0,15), p2=(10,30), layer=spira.Layer(1))
+
+ elems += group
+
+ bbox_shape = group.bbox_info.bounding_box(margin=1)
+ elems += spira.Polygon(shape=bbox_shape, layer=spira.Layer(2))
+
+ return elems
+
+.. image:: _figures/_group.png
+ :align: center
+
+A group polygon is created around the two defined polygons with a marginal offset of 1 micrometer.
+
+Ports
+=====
+
+Port objects are unique to the SPiRA framework and are mainly used for connection purposes.
+
+.. code-block:: python
+
+ class Box(spira.Cell):
+
+ width = spira.NumberParameter(default=1)
+ height = spira.NumberParameter(default=1)
+ layer = spira.LayerParameter(default=spira.Layer(1))
+
+ def create_elements(self, elems):
+ shape = shapes.BoxShape(width=self.width, height=self.height)
+ elems += spira.Polygon(shape=shape, layer=self.layer)
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1_M1', midpoint=(-0.5,0), orientation=180, width=1)
+ ports += spira.Port(name='P2_M1', midpoint=(0.5,0), orientation=0, width=1)
+ return ports
+
+.. code-block:: python
+
+ >>> box = Box()
+ [SPiRA: Cell] (name ’Box ’, width 1, height 1, number 0, datatype 0)
+ >>> box.width
+ 1
+ >>> box. height
+ 1
+ >>> box. gds_layer
+ [SPiRA Layer] (name ’’, number 0, datatype 0)
+ >>> box.gdsii_output(name='Ports')
+
+.. image:: _figures/_ports.png
+ :align: center
+
+The above example illustrates constructing a parameterized box using the proposed framework:
+First, defining the parameters that the user would want to change when creating a box instance.
+Here, three parameter are given namely, the :py:data:`width`, the :py:data:`height` and the layer
+properties for GDSII construction. Second, a shape is generated from the defined parameters using the shape module.
+Third, this box shape is added as a polygon element to the cell instance. This polygon takes the shape and connects
+it to a set of methods responsible for converting it to a GDSII element. Fourth, two terminal ports are added to
+the left and right edges of the box, with their directions pointing away from the polygon interior.
+
+Routes
+======
+
+Most of the times in designing digital electronic circuit layouts it is required to define metal polygon connections between different *devices*.
+Defining the exact points connecting different devices can become a tedious task. **Routes** are polygon classes that automatically generates
+a polygon path between different devices. As previously explained, ports are used to define connection points to a cell instance.
+Therefore, routes can be defined as a **polygon** that connects to two **ports** through a path-dependent algorithm.
+SPiRA offers a variety of different route algorithms that can be generated depending on the relative port positions and the user requirements.
+
+.. code-block:: python
+
+ class RouteExample(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=self.ports, layer=spira.Layer(1))
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1', midpoint=(0,0), orientation=180)
+ ports += spira.Port(name='P2', midpoint=(20,10), orientation=0)
+ return ports
+
+.. image:: _figures/_routes.png
+ :align: center
+
+.. --------------------------------------------------------------------------------------
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Validate-by-Design
+.. ******************
+
+
+.. .. --------------------------------------------------------------------------------------
+
+*******
+Filters
+*******
+
+Filters are algorithms whos state can be toggled (enabled or disabled). These algorithms are
+typically used to add or remove extra information to an already working design, hence the name *filter*.
+
+Boolean
+=======
+
+Instead of individually looping through the entire tree hierarchy of a layout to apply
+boolean operations on all polygons, a *boolean filter* can be used to automate this process.
+
+
+Layer
+=====
+
+Sometimes we want to filter certain layers, since they only serve a temporary purpose, or
+because we only want to view layers in the design, for example a specific purpose type.
+In these cases we can use the *layer filter* to automatically filter certain layers in a cell.
+
+
+*******
+Netlist
+*******
+
+The netlist extraction algorithm consists of a chain of filtering methods.
+The basic algorithmic steps is divided into two categories:
+
+1. Extracting a netlist for each individual metal polygon.
+2. Chaining the metal netlists into a single mask netlist.
+
+For each of these steps there is a chain of filter algorithms applied to ensure the correct extraction:
+
+Polygon Netlist
+===============
+
+* Label all nodes in the netlist to the metal layer they represent.
+* Label the nodes that are represetative of detected devices.
+* Label the nodes that represents ERC connections between differenct metal polygons.
+* Calcaulte the cross-over nodes and determine the individual inductive branches.
+
+Mask Netlist
+============
+
+* Combine all metal netlists into a single netlist domain and connect shared nodes.
+* Calculate individual branches between device nodes.
+* Calculate cross-over nodes between different branches.
+* Recalcalate individual branches which includes the detected cross-over nodes.
+* Collapse all nodes belonging to the same branch into a single node representation.
+
+
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Virtual Modeelling
+.. ******************
+
+
+
+.. Derived Edges
+.. =============
+
+
+
+.. --------------------------------------------------------------------------------------
+
+************
+RDD Advanced
+************
+
+The goal of the advanced RDD tutorial is to discuss:
+
+* How to define filters.
+* How to define derived layers.
+* How to create a LVS database.
+
+Filters
+=======
+
+Filters leverages the *chain of responsiblity* design pattern to chain a number of
+algorithms that has to be executed in a sequential order on a specific layout object.
+
+.. code-block:: python
+
+ # First we create a filters database.
+ RDD.FILTERS = ParameterDatabase()
+
+ class PCellFilterDatabase(LazyDatabase):
+ """ Define the filters that will be used when creating a spira.PCell object. """
+
+ def initialize(self):
+ from spira.yevon import filters
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.DEVICE_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+ f += filters.ContactAttachFilter(name='contact_attach')
+
+ f['boolean'] = True
+ f['simplify'] = True
+ f['contact_attach'] = True
+
+ self.DEVICE = f
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.CIRCUIT_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+
+ f['boolean'] = True
+ f['simplify'] = True
+
+ self.CIRCUIT = f
+
+ f = filters.ToggledCompositeFilter(name='mask_filters', filters=[])
+ f += filters.ElectricalAttachFilter(name='erc')
+ f += filters.PinAttachFilter(name='pin_attach')
+ f += filters.DeviceMetalFilter(name='device_metal')
+
+ f['erc'] = True
+ f['pin_attach'] = True
+ f['device_metal'] = False
+
+ self.MASK = f
+
+ RDD.FILTERS.PCELL = PCellFilterDatabase()
+
+The code above shows the creation of three composite filter algorithms:
+
+* The **device filters** will only be applied on detected device cells.
+* The **circuit filters** will only be aplied on non-device cell.
+* The **mask filters** will be executed on the top-level layout cell.
+
+The PCell filter class inherits from the :py:data:`LazyDatabase` class to delay its construction.
+Therefore, the PCell filter database is only instantiated when a specific filter is called using
+the dot operator as shown below:
+
+.. code-block:: python
+
+ f = RDD.FILTERS.PCELL.DEVICE
+
+Derived Layers
+==============
+
+Defining **derived layers** forms the basis of creating the LVS database, since derived layers
+almost by definition defines via connections.
+
+.. code-block:: python
+
+ RDD.VIAS.C5R = ParameterDatabase()
+
+ RDD.VIAS.C5R.LAYER_STACK = {
+ 'BOT_LAYER' : RDD.PLAYER.R5.METAL,
+ 'TOP_LAYER' : RDD.PLAYER.M6.METAL,
+ 'VIA_LAYER' : RDD.PLAYER.C5R.VIA
+ }
+ RDD.PLAYER.C5R.CLAYER_CONTACT = RDD.PLAYER.R5.METAL & RDD.PLAYER.M6.METAL & RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M1 = RDD.PLAYER.R5.METAL ^ RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M2 = RDD.PLAYER.M6.METAL ^ RDD.PLAYER.C5R.VIA
+
+ class C5R_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.via import ViaC5RA, ViaC5RS
+ self.DEFAULT = ViaC5RA
+ self.STANDARD = ViaC5RS
+
+ RDD.VIAS.C5R.PCELLS = C5R_PCELL_Database()
+
+The example above defines a C5R via which connects layer M6 to R5 through a contact layer C5R.
+The logic steps for creating this coding snippet is as follow:
+
+1. A layer stack is created to defined the top, bottom, and via layers.
+2. The derived layers are create that specifies the boolean operations between different layers required in order to detect a via connection. Note, that the :py:data:`RDD.PLAYER.C5R.CLAYER_CONTACT` is the via derived layer that specifies the via connection, while the other two derived layers is used for debugging purposes.
+3. A set of different via PCell classes is added to the database. These classes will be constructed and used during the device detection run.
+
+LVS Database
+============
+
+Defining devices in the LVS database is done similarly to defining vias as already explained:
+
+.. code-block:: python
+
+ RDD.DEVICES = ParameterDatabase()
+
+ RDD.DEVICES.JUNCTION = ParameterDatabase()
+
+ class Junction_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.junction import Junction
+ self.DEFAULT = Junction
+
+ RDD.DEVICES.JUNCTION.PCELLS = Junction_PCELL_Database()
+
+A Josephson junction device is added to the LVS database by importing an already defined
+PCell class and can be constucted using the dot operator:
+
+.. code-block:: python
+
+ # Create a JTL instance from the definition in the RDD LVS database.
+ JtlPCell = RDD.DEVICES.JUNCTION.PCELLS.DEFAULT()
+
+ # View the created instance.
+ JtlPCell.gdsii_view()
+
+
+
+
+
+
diff --git a/docs/_2_basic.rst b/docs/_2_basic.rst
new file mode 100644
index 00000000..f6d61714
--- /dev/null
+++ b/docs/_2_basic.rst
@@ -0,0 +1,797 @@
+##############
+Basic Tutorial
+##############
+
+This tutorial consists of a set of examples that will guide you on how to create a basic PCell,
+manipulate layout elements, and connect process data to your design.
+
+******************
+Parameterized Cell
+******************
+
+First, we have to understand the basic PCell template structure innate to any SPiRA design environment.
+
+Demonstrates
+============
+
+* How to create a parameterized cell by inheriting form :py:class:`spira.PCell`.
+* How to add parameters to the cell.
+* How to validate received parameters.
+
+The first step in any SPiRA design environment is to import the framework:
+
+.. code-block:: python
+
+ import spira.all as spira
+
+The :py:mod:`spira` namespace contains all the important functions and classes provided by the framework.
+In order to create a layout cell all classes has to inherit from :py:class:`spira.PCell`:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+The :py:class:`spira.PCell` class connects the design to the **SPiRA core**. In the exampe above we created
+a parameterized cell of type :py:class:`Resistor` and a basic description given in qoutation marks.
+Now that a layout class has been constructed we need to define a set of *parameters* that will
+describe relations between layout elements.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+We defined two ``float`` restricted parameters, the :py:data:`width` and the :py:data:`length` of the resistor,
+along with documentation (using the :py:data:`doc` attribute) and a default value equal to :math:`0.3` and :math:`1.0`, respectively.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+By definition we want to make sure the length of of the resistor is larger than the width.
+To check the validity of the parameters in relation to eachother, we can use the :py:meth:`validate_parameters` method:
+This method consists of a series of *if-statements* that checks whether the defined parameters are valid or not after instantiation.
+
+.. code-block:: python
+
+ # 1. First create an instance of the resistor class.
+ >>> D = Resistor()
+
+ # 2. You van view the default values of the parameters.
+ >>> (D.width, D.length)
+ (0.3, 1.0)
+
+ # 3. The parameter is successfully updated if it is valid.
+ >>> D.width = 0.5
+ >>> (D.width, D.length)
+ (0.5, 1.0)
+
+ # 4. If an invalid value is received, an error is thrown.
+ >>> D.width = 1.1
+ ValueError: `Width` cannot be larger than `length`.
+
+
+***********************
+Connecting Process Data
+***********************
+
+Now that we have created a basic PCell and understand how to define parameters, we want to
+connect data from the fabrication process to these parameters.
+
+Demonstrates
+============
+
+* How to connect fabrication process data to a design.
+* How to change to a different fabrication process.
+
+The *Rule Deck Database* is a set of Python scripting files that contains all the required fabrication process data,
+and is accessed using the :py:mod:`RDD` module.
+SPiRA contains a default process that can be used directly from the :py:mod:`spira` namespace:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+We updated the parameter default values to equal that of the minimum design restrictions defined
+by the process for the resistor layer :py:data:`R1`.
+After having imported the :py:mod:`spira` namespace the default process database can be changed
+by importing the desired :py:mod:`RDD` object.
+
+.. code-block:: python
+
+ import spira.all as spira
+ from spira.technologies.mit.process.database import RDD
+
+ >>> RDD
+
+
+
+*****************
+Creating Elements
+*****************
+
+Next, we want to create geometric shapes based on the received instance parameters,
+before adding them to the cell instance as element objects.
+
+Demonstrates
+============
+
+* How to add elements to a cell instance.
+* How to create a shape geometry.
+* How to create a GDSII polygon from a shape.
+
+The :py:data:`create_elements` class method is a unique SPiRA method that automatically connects
+a list of elements to the class instance. Methods that starts with ``create_`` are special
+methods in SPiRA and are called *create methods*.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ w, l = self.width, self.length
+ shape = spira.Shape(points=[[0,0], [l,0], [l,w], [0,w]])
+ elems += spira.Polygon(shape=shape, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_3_layout.png
+ :align: center
+
+The defined parameters are used to create a geometeric shape inside the :py:data:`create_elements` method.
+Once the shape is defined it can be added to the layout as a polygon element. The purpose of a polygon
+is to add GDSII-related data to the defined shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+Instead of manually creating shapes SPiRA offers a set of predefined polygons that can be used.
+The code snippet above illustrates the use of the :py:meth:`spira.Box` polygon instead of creating
+a shape object and sending it the polygon container.
+
+
+**************
+Creating Ports
+**************
+
+Similar to the :py:data:`create_elements` method that connects element to your cell instance,
+the :py:data:`create_ports` method adds ports to your design. A port is defined as a vector object
+that is used to connect different layout elements.
+
+Demonstrates
+============
+
+* How to connect ports to your layout.
+* How to name and connect a process type to your port.
+* How to unlock edge specific ports.
+
+Ports are used to connect different layout elements, such as routing different device cells via a metal polygon.
+Therefore, defining the port position, its orientation, and to what process layer is connects are extremely important.
+These are some of the most commonly used port parameters:
+
+* :py:data:`name` The name of the port.
+* :py:data:`midpoint` The position of the port.
+* :py:data:`orientation` The direction of the port.
+* :py:data:`width` The width of the port.
+* :py:data:`process` The process to which the port object connects.
+
+In the example below we first define a box polygon and then add ports to the left and right edges of the shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ w, l = self.width, self.length
+ ports += spira.Port(name='P1_R1', midpoint=(-l/2,0), orientation=180, width=self.width)
+ ports += spira.Port(name='P2', midpoint=(l/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return ports
+
+.. image:: _figures/_4_ports_0_enabled.png
+ :align: center
+
+Port names has to contain one of the following formats:
+
+**Pname_Process**
+ The first letter is defines the **purpose** of the port followed by the port name, typically a number.
+ After the underscore character the **process** symbol is added (as defined in the RDD).
+ This port naming convention is used when no process parameter is added to the object, as shown in the
+ example above with port ``P1_R1``. This process symbol are compared to the defined processes in the
+ RDD and automatically updates the process parameter of the port instance.
+
+*Pname*
+ As shown with ``P2`` the port name does not have to contain the process symbol if a process parameter
+ is manually added to the creation of a port instance.
+
+The most important port purposes for PCell creation are:
+
+* **P** (PinPort): The default port used as a terminal to horizontally connect different elements.
+* **E** (EdgePort): Ports that are automatically generated from the edges of metal polygons.
+* **D** (DummyPort): Typically used to snap a one side of a route object to a specific position.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(alias='ply1', width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ # Process symbol will automatically be added to the port name.
+ ports += self.elements['ply1'].ports['E1_R1'].copy(name='P1')
+ ports += self.elements['ply1'].ports['E3_R1'].copy(name='P2')
+ return ports
+
+Defining the exact midpoint of a port required knowledge of the boundary of the shape we want to connect to.
+SPiRA automatically generates edge ports for metal polygons. The generated box element is given an alias
+that is used to access that specific element. These edges can be activated as ports by simply changing
+the port name. The example above illustrates changing edge port ``E1_R1`` to port ``P1``.
+
+.. image:: _figures/_4_ports_0.png
+ :align: center
+
+The image bove depicts the automatically generated edge ports that can be used for identifying which
+edges to convert to active port. In this example we are converting edges, ``E1_R1`` and ``E3_R1``,
+to ports ``P1_R1`` and ``P2_R1``, respectively. Note, that even though we only added ``P1`` as the port name,
+the process symbol to which the port belongs are automatically added by the SPiRA framework, since the process
+parameter is already set within the edge port. The end result is shown in the figure below:
+
+.. image:: _figures/_4_ports_1.png
+ :align: center
+
+
+***************
+Creating Routes
+***************
+
+Generally metal polygons are used to connect different circuit devices. In this example we first define
+two ports and then generate a metal polygon between them using the :py:class:`spira.Route` base class.
+SPiRA offers a variaty of different routing algorithm depending on the relative position between ports.
+
+Demonstrates
+============
+
+* How to create a route between two different ports.
+* How to externally cache parameters.
+
+First, we define the ports as two separate parameters, :py:data:`p1` and :py:data:`p2`. Second, we use create
+methods to generate port parameters. Doing so allows us to access the ports in both :py:data:`create_elements`
+and :py:data:`create_ports` without re-calculating the ports.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ # Create a straight route between ports p1 and p2.
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+.. image:: _figures/_5_routes_0.png
+ :align: center
+
+It is also possible to define all ports in a single method and externally cache the method using the ``spira.cache``
+decorator as shown in the following example.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ @spira.cache()
+ def get_ports(self):
+ p1 = spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+ p2 = spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return [p1, p2]
+
+ def create_elements(self, elems):
+ p1, p2 = self.get_ports()
+ elems += spira.RouteStraight(p1=p1, p2=p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_ports()
+ return ports
+
+
+**************
+Cell Hierarchy
+**************
+
+As layout designs becomes bigger and more complex with larger circuits, extending an maintaining PCells
+becomes a tedious task. Using basic object-oriented inheritance simplifies the overall structure of our designs.
+
+Demonstrates
+============
+
+* How to create a manhattan route between two ports.
+* How to use inheritance to mimic layout hierarchy.
+* How to extend a layout without changing the parent class.
+* How to pass cells as a parameter to another cell class.
+* How to connect different structures using their ports.
+
+If two ports are not aligned on the same axis, the :py:data:`spira.RouteManhattan` method can be used to
+generate a manhattan polygon between them. One prerequisite is that the absolute port orientation difference
+must equal :math:`180` degrees.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return port
+
+.. image:: _figures/_6_hierarchy_0.png
+ :align: center
+
+The created :py:class:`Resistor` cell can be extended by creating a new cell that inherits from this class.
+To extend the elements we have to add the parent class elements to the current instance. This is done
+using Python's :py:data:`super` method: ``elems = super().create_elements(elems)``. A second route can then
+be generated starting from :py:data:`p2` and ending at :py:data:`p3` with a rounded corner bend.
+
+.. code-block:: python
+
+ # ...
+
+ class ResistorExtended(Resistor):
+
+ p3 = spira.Parameter(fdef_name='create_p3')
+
+ def create_p3(self):
+ return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems = super().create_elements(elems)
+ elems += spira.RouteManhattan(ports=[self.p2, self.p3], corners='round', layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_6_hierarchy_1.png
+ :align: center
+
+Another method to mimic cell hierarchy is to pass a cell to another cell as a parameter:
+
+.. code-block:: python
+
+ class ResistorManhattan(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorStraight(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorConnect(spira.PCell):
+
+ res0 = spira.CellParameter(default=ResistorManhattan)
+ res1 = spira.CellParameter(default=ResistorStraight)
+
+ def create_elements(self, elems):
+ s1 = spira.SRef(reference=self.res0())
+ s2 = spira.SRef(reference=self.res1())
+ s2.connect(port=s2.ports['P1'], destination=s1.ports['P2'])
+ elems += [s1, s2]
+ return elem
+
+We start by creating two resistor classes, :py:class:`ResistorManhattan` and :py:class:`ResistorStraight`,
+then we add them to a single cell instance were we can snap the two structures into place
+by connecting their respective instance ports. An instance for each resistor cell is created
+using :py:class:`spira.SRef` and then :py:data:`P1` of instance :py:class:`ResistorStraight`
+is connect to :py:data:`P2` of instance :py:class:`ResistorManhattan` using the :py:meth:`connect` method.
+
+.. image:: _figures/RouteConnect.*
+ :align: center
+
+
+***************
+Transformations
+***************
+
+Transformations is SPiRA are not directly applied to layout elements. Instead, they are
+abstraction build as a layer on top of the SPiRA core, and are connected to Elements
+as parameters. Doing so enable us to transform elements without losing hierarchical
+data implicit in the layout structure.
+
+Demonstrates
+============
+
+* Understand why transformations are parameterized in SPiRA.
+* How to apply transformations to layout elements.
+* How to keep the hierarchical structure of a flatened layout.
+
+There are multiple different ways to apply a transformation to a layout element:
+
+* The first method creates a transform object and then applies it to an object.
+* The second directly uses a element method to apply the transform.
+
+.. code-block:: python
+
+ class TranslatePolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ """ Apply transformation by first creating a transform object. """
+ T = spira.Translation(Coord(-10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(T)
+ return ply
+
+ def create_t2(self):
+ """ Apply transformation by creating a generic transform.
+ Instead of using the `.ttransform` method, the transform
+ is directly added as a parameter."""
+ tf = spira.GenericTransform(translation=Coord(-22, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=tf)
+ return ply
+
+ def create_t3(self):
+ """ Directly transform the element using the corresponding transform method. """
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((-34, 0))
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+.. image:: _figures/_9_translate.png
+ :align: center
+
+The code snippet above illustrates the different ways to connect a transform to an element.
+The first method in :py:data:`create_t1` is typically used when we want to create a set of
+predefined transforms and later connect them to multiple elements.
+
+The second method in :py:data:`create_t2` is very similar to that of the first, but instead
+manually creates a generic transformation object and connect it to the element as a parameter.
+This method is just shown for illustration purposes and rarely used in practice, since a generic
+transform is automatically created by the framework when multiple transform objects are added.
+
+The thrid method in :py:data:`create_t3` uses the class method to automatically create the
+transform object and emidiately apply the transform to the subject element.
+
+.. code-block:: python
+
+ class TransformPolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ T = spira.Rotation(30) + spira.Translation(Coord(10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(transformation=T)
+ return ply
+
+ def create_t2(self):
+ T = spira.GenericTransform(translation=(20, 0), rotation=60)
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=T)
+ return ply
+
+ def create_t3(self):
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((30, 0))
+ ply.rotate(90)
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+Transformations can be compounded using the plus operator as shown in :py:data:`create_t1`.
+The result is a generic transformation that can be added to any element. A generic transform
+can also be explicitly defined as in :py:data:`create_t2`, or multiple transforms can be
+adding using the corresponding methods as shown in :py:data:`create_t3`.
+
+.. image:: _figures/_9_transform.png
+ :align: center
+
+
+**********
+Stretching
+**********
+
+This tutorial builds from the previous tutorial of transformations.
+Here, we will look at how to stretch a cell reference and specific polygons using ports.
+
+Demonstrates
+============
+
+* How to stretch layout elements.
+* How to use expanded transformations to view flattened ports.
+* How to stretch a specific polygon while maintaining the layout hierarchy.
+
+.. First, we will start by stretching basic flattened layout structures.
+
+In this example we are stretching an entire cell reference by some factor.
+We have created a basic Josephson Junction to demonstrate the stretching of different polygons
+inside the PCell, while maintaining the hierarchical structure.
+
+.. code-block:: python
+
+ class Jj(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Convex(radius=7.0, layer=RDD.PLAYER.C2.VIA)
+ return elems
+
+
+ class ResVia(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Rectangle(p1=(-7.5, -13.2), p2=(7.5, -8.2), layer=RDD.PLAYER.R1.METAL)
+ elems += spira.Rectangle(p1=(-4, -12), p2=(4.1, -10), layer=RDD.PLAYER.C1.VIA)
+ return elems
+
+
+ class Top(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -8))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sj1', reference=Jj(), transformation=t1)
+ elems += spira.SRef(alias='Sr1', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -23), p2=(10, 10), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Bot(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -30))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sr2', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -55), p2=(10, -35), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Junction(spira.Cell):
+ """ Josephson junction. """
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -5))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.Rectangle(p1=(-13, -60), p2=(13, 12), layer=RDD.PLAYER.M1.METAL)
+ elems += spira.SRef(alias='S1', reference=Top(), transformation=t1)
+ elems += spira.SRef(alias='S2', reference=Bot(), transformation=t2)
+ return elems
+
+An instance of the :py:class:`Junction` cell can be created and added as a reference, which
+can be stretched using the :py:meth:`stretch_by_factor` method:
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ C += S.stretch_by_factor(factor=(2,1))
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded flattened view of the junction cell is shown below.
+
+.. image:: _figures/_9_expanded.png
+ :align: center
+
+All polygon elements that coalesces this cell is stretched by a factor of two in the horizontal direction (x-axis).
+
+.. image:: _figures/_9_factor.png
+ :align: center
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ S.stretch_p2p(port_name='S1:Sr1:E3_R1', destination_name='S2:Sr2:E1_R1')
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded view is used to access flattened ports using their hierarchically derived names.
+The port names used in the code above are shown in the expanded view of the cell.
+In this example we want to stretch the two shunt resistor polygons so form a single resistor connection polygon.
+
+.. image:: _figures/_9_ports.png
+ :align: center
+
+
+
+
+
+
diff --git a/docs/_3_advanced.rst b/docs/_3_advanced.rst
new file mode 100644
index 00000000..7d33139c
--- /dev/null
+++ b/docs/_3_advanced.rst
@@ -0,0 +1,888 @@
+#################
+Advanced Tutorial
+#################
+
+This set of tutorials focuses on explaining more advanced features that the SPiRA framework
+has to offer. We go into more details on how to create **device** and **circuit** PCells,
+how to structure a design, and how to manipulate layout elements.
+
+In SPiRA PCells can be divided into two categorises, :py:class:`spira.Device` and :py:class:`spira.Circuit`.
+Each of these classes contains a set of different back-end algorithms that are automatically executed when
+the layout class is constructed. Typically, these algorithms consists of boolean operations and filtering algorithms.
+Also, inheriting from these classes defines the purpose of the layout, either a *device* or a *circuit*.
+
+**Devices:**
+
+Similar to creating a PCell, constructing a device cell required inheriting from :py:class:`spira.Device`
+instead of :py:class:`spira.PCell`. In superconducting circuits a device layout is usually a *Via* or a *Junction*.
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+ pass
+
+**Circuits:**
+
+A circuit PCell is designed similar to that of a device. By definition a circuit layout contains polygon
+routes that connects different device and ports instances. Therefore, a :py:class:`spira.Circuit` contains
+two extra, but optional, create methods to simplify the code structure:
+
+* :py:data:`create_structures`: Defines the device instances.
+* :py:data:`create_routes`: Defines the routing paths between different structures and ports.
+
+.. code-block:: python
+
+ class Jtl(spira.Circuit):
+
+ def create_structures(self, elems):
+ return elems
+
+ def create_routes(self, elems):
+ return elems
+
+Note, it is not required to use these methods, but designing large circuits can cause the
+:py:data:`create_elements` method to become cumbersome.
+
+
+*****************
+Library Structure
+*****************
+
+Every design environment connects to a specific fabrication process, also known as the PDK.
+In SPiPA, the PDK data is encapsulated in Python scripts and are collectively called the RDD.
+RDD script names start with ``db_`` as illustrated below.
+
+This section discusses how to organize your design project in SPiRA as a systematized library.
+Technically, your library can have any structure given that you compensates for the necessary
+importing changes. But it is highly adviced to use the proposed structure.
+
+.. code-block:: bash
+
+ technologies
+ |__ mitll
+ |__ devices
+ |__ junction.py
+ |__ vias.py
+ |__ circuits
+ |__ jtl.py
+ |__ dcsfq.py
+ |__ db_init.py
+ |__ db_process.py
+ |__ db_lvs.py
+
+The technology library is broken down into 3 parts:
+
+1. **Devices**: Contains defined device PCells for the specific technology.
+2. **Circuits**: Contains PCell circuits created using the specific technology.
+3. **Database**: Contains a set database files that make up the RDD.
+
+The :py:data:`technologies` folder is the base folder inside the SPiRA design environment that
+contains all the different technology processes and PCell designs in a single place. The library structure
+above contains the ``mitll`` library, which consists of defined junction and via devices, a long
+with a JTL and DCSFQ circuit.
+
+The ``db_init`` script is the first file to be executed when the RDD database is constructed.
+The ``db_process`` script contains most of the information required to design a PCell.
+This file contains the process layers, layer purposes, process parameters, etc.
+The ``db_lvs`` script defines the created device PCells to be used in the device detection
+algorithms when doing LVS extraction.
+
+
+*****
+YTron
+*****
+
+In this example we will start from the beginning. First, we will create a *yTron* shape
+and then using this shape we will create a device containing input/output ports.
+This device will then be used to create a full circuit layout.
+
+Demonstrates
+============
+
+* How to create your own shape class.
+* How to create a device and a circuit PCell.
+* How to restrict a design to only accept a specific shape or device.
+
+We create our own yTron shape by inheriting from :py:class:`spira.Shape`, which allows us
+to manipulate the shape once it has been instantiated.
+
+.. code-block:: python
+
+ class YtronShape(spira.Shape):
+ """ Class for generating a yTron shape. """
+
+ rho = NumberParameter(default=2, doc='Angle of concave bend between the arms.')
+ arm_lengths = CoordParameter(default=(5,3), doc='Length or the left and right arms, respectively.')
+ source_length = NumberParameter(default=5, doc='Length of the source arm.')
+ arm_widths = CoordParameter(default=(2,2), doc='Width of the left and right arms, respectively.')
+ theta = NumberParameter(default=10, doc='Angle of the left and right arms.')
+ theta_resolution = NumberParameter(default=10, doc='Smoothness of the concave bend.')
+
+ xc = Parameter(fdef_name='create_xc')
+ yc = Parameter(fdef_name='create_yc')
+ arm_x_left = Parameter(fdef_name='create_arm_x_left')
+ arm_y_left = Parameter(fdef_name='create_arm_y_left')
+ arm_x_right = Parameter(fdef_name='create_arm_x_right')
+ arm_y_right = Parameter(fdef_name='create_arm_y_right')
+ rad_theta = Parameter(fdef_name='create_rad_theta')
+ ml = Parameter(fdef_name='create_midpoint_left')
+ mr = Parameter(fdef_name='create_midpoint_right')
+ ms = Parameter(fdef_name='create_midpoint_source')
+
+ def create_rad_theta(self):
+ return self.theta * np.pi/180
+
+ def create_xc(self):
+ return self.rho * np.cos(self.rad_theta)
+
+ def create_yc(self):
+ return self.rho * np.sin(self.rad_theta)
+
+ def create_arm_x_left(self):
+ return self.arm_lengths[0] * np.sin(self.rad_theta)
+
+ def create_arm_y_left(self):
+ return self.arm_lengths[0] * np.cos(self.rad_theta)
+
+ def create_arm_x_right(self):
+ return self.arm_lengths[1] * np.sin(self.rad_theta)
+
+ def create_arm_y_right(self):
+ return self.arm_lengths[1] * np.cos(self.rad_theta)
+
+ def create_midpoint_left(self):
+ xc = -(self.xc + self.arm_x_left + self.arm_widths[0]/2)
+ yc = self.yc + self.arm_y_left
+ return [xc, yc]
+
+ def create_midpoint_right(self):
+ xc = self.xc + self.arm_x_right + self.arm_widths[1]/2
+ yc = self.yc + self.arm_y_right
+ return [xc, yc]
+
+ def create_midpoint_source(self):
+ xc = (self.arm_widths[1] - self.arm_widths[0])/2
+ yc = -self.source_length + self.yc
+ return [xc, yc]
+
+ def create_points(self, points):
+
+ theta = self.theta * np.pi/180
+ theta_resolution = self.theta_resolution * np.pi/180
+ theta_norm = int((np.pi-2*theta)/theta_resolution) + 2
+ thetalist = np.linspace(-(np.pi-theta), -theta, theta_norm)
+ semicircle_x = self.rho * np.cos(thetalist)
+ semicircle_y = self.rho * np.sin(thetalist)+self.rho
+
+ xpts = semicircle_x.tolist() + [
+ self.xc + self.arm_x_right,
+ self.xc + self.arm_x_right + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ 0, -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left)
+ ]
+
+ ypts = semicircle_y.tolist() + [
+ self.yc + self.arm_y_right,
+ self.yc + self.arm_y_right,
+ self.yc, self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc, self.yc + self.arm_y_left,
+ self.yc + self.arm_y_left
+ ]
+
+ points = np.array(list(zip(xpts, ypts)))
+
+ return points
+
+There is a few important aspects to note in the :py:class:`YtronShape` class:
+
+1. The :py:data:`create_points` create method is required by the :py:class:`spira.Shape` class and is similar
+ to the :py:class:`create_elements` method for creating a cell.
+2. In this example the importance of the :py:data:`doc` attribute when defining a parameter becomes apparent.
+3. Using create methods to dynamically define the shape parameters makes the shape instance easier to use.
+
+Once we have the desired shape we can use it to create a device cell, containing a GDSii layer and ports instances.
+
+.. code-block:: python
+
+ # ...
+
+ class YtronDevice(spira.Device):
+
+ shape = spira.ShapeParameter(restriction=spira.RestrictType([YtronShape]))
+
+ def create_elements(self, elems):
+ elems += spira.Polygon(shape=self.shape, layer=RDD.PLAYER.M1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+
+ left_arm_width = self.shape.arm_widths[0]
+ rigth_arm_width = self.shape.arm_widths[1]
+ src_arm_width = self.shape.arm_widths[0] + self.shape.arm_widths[1] + 2*self.shape.xc
+
+ ports += spira.Port(name='Pl_M1', midpoint=self.shape.ml, width=left_arm_width, orientation=90)
+ ports += spira.Port(name='Pr_M1', midpoint=self.shape.mr, width=rigth_arm_width, orientation=90)
+ ports += spira.Port(name='Psrc_M1', midpoint=self.shape.ms, width=src_arm_width, orientation=270)
+
+ return ports
+
+ >>> shape = YtronShape(theta_resolution=100)
+ >>> D = YtronDevice(shape=shape)
+ >>> D.gdsii_output()
+
+.. image:: _figures/_adv_0_ytron.png
+ :align: center
+
+The :py:data:`shape` parameter defined in the :py:class:`YtronDevice` class restricts the instance to only receive
+a shape of type :py:class:`YtronShape`. Using the shape parameters the port instances for each arms
+can be defined and added to the PCell instance. The created yTron device can now be used in a circuit:
+
+.. code-block:: python
+
+ class YtronCircuit(spira.Circuit):
+
+ ytron = spira.Parameter(fdef_name='create_ytron', doc='Places an instance of the ytron device.')
+
+ @spira.cache()
+ def get_io_ports(self):
+ p1 = spira.Port(name='P1_M1', midpoint=(-10,10), orientation=0)
+ p2 = spira.Port(name='P2_M1', midpoint=(5,10), width=0.5, orientation=270)
+ p3 = spira.Port(name='P3_M1', midpoint=(0,-10), width=1, orientation=90)
+ return [p1, p2, p3]
+
+ def create_ytron(self):
+ shape = YtronShape(rho=0.5, theta=5)
+ D = YtronDevice(shape=shape)
+ return spira.SRef(alias='ytron', reference=D)
+
+ def create_elements(self, elems):
+ p1, p2, p3 = self.get_io_ports()
+
+ elems += self.ytron
+
+ elems += spira.RouteManhattan(
+ ports=[self.ytron.ports['Pl_M1'], p1],
+ width=self.ytron.ref.shape.arm_widths[0],
+ layer=RDD.PLAYER.M1.METAL,
+ corners=self.corners)
+
+ elems += spira.RouteStraight(p1=p2,
+ p2=self.ytron.ports['Pr_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ elems += spira.RouteStraight(p1=p3,
+ p2=self.ytron.ports['Psrc_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_io_ports()
+ return ports
+
+The figure below shows the output of the yTron PCell if the class was constructed inheriting from
+:py:class:`spira.PCell`. The metal layers are separated and the connection ports are still visible.
+
+.. image:: _figures/_adv_0_ytron_pcell.png
+ :align: center
+
+The following figure is the final result when inheriting from :py:class:`spira.Circuit`
+rather than :py:class:`spira.PCell`. The contacting metal layers are merged and the redundant ports are filtered.
+
+.. image:: _figures/_adv_0_ytron_circuit.png
+ :align: center
+
+From the code above we can see that three routes are defined.
+The first, connects the left arm with the first port using a basic manhattan structure.
+The second and third, connects the right arm to the second port and the source arm to the third port,
+but uses a ``sine`` path type to generate the routing polygons.
+
+
+**********
+Via Device
+**********
+
+Via devices generally following the same design patterns, but still require explicit construction
+to describe how PDK data should be handled on instance creation. This example illustrated the
+creation of the *alternative resistor via contact* that is responsible to connecting resistive
+layer ``R5`` to inductive layer ``M6``.
+
+Demonstrates
+============
+
+* How to create a via device.
+* How to add range restrictions to parameters.
+* How to create a cell that validates design rules on instance creation.
+
+Recall, that by definition a PCell script is responsible for describing the interrelations between
+layout elements and defined parameters. These parameters can be design restrictions imposed by the
+specific fabrication technology.
+
+.. code-block:: python
+
+ class ViaC5RA(spira.Device):
+ """ Via component for the MiTLL process. """
+
+ width = spira.NumberParameter(default=RDD.R5.MIN_SIZE, restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE))
+
+ height = spira.Parameter(fdef_name='create_height')
+ via_width = spira.Parameter(fdef_name='create_via_width')
+ via_height = spira.Parameter(fdef_name='create_via_height')
+
+ m6_width = spira.Parameter(fdef_name='create_m6_width', doc='Width of the via layer polygon.')
+ m6_height = spira.Parameter(fdef_name='create_m6_height', doc='Width of the via layer polygon.')
+
+ def create_m6_width(self):
+ return (self.via_width + 2*RDD.C5R.M6_MIN_SURROUND)
+
+ def create_via_width(self):
+ return (self.width + 2*RDD.C5R.R5_MAX_SIDE_SURROUND)
+
+ def create_via_height(self):
+ return RDD.C5R.MIN_SIZE
+
+ def create_height(self):
+ return self.via_height + 2*RDD.R5.C5R_MIN_SURROUND
+
+ def create_elements(self, elems):
+ elems += spira.Box(layer=RDD.PLAYER.C5R.VIA, width=self.via_width, height=self.via_height, enable_edges=False)
+ elems += spira.Box(alias='M6', layer=RDD.PLAYER.M6.METAL, width=self.m6_width, height=self.height, enable_edges=False)
+ elems += spira.Box(alias='R5', layer=RDD.PLAYER.R5.METAL, width=self.width, height=self.height, enable_edges=False)
+ return elems
+
+ def create_ports(self, ports):
+ p0 = self.elements['M6'].ports.unlock
+ p1 = self.elements['R5'].ports.unlock
+ return ports
+
+Thus, the code for the via PCell defined above is responsible for describing how the top and bottom metal layers
+must be constructed in relation to the contact layer without violating any design rules. The PCell defines the specific
+design rules applicable to the creation of this via device.
+
+
+********
+Resistor
+********
+
+In Single Flux Quantum (SFQ) logic circuits, we typically use a shunt resistance for the biasing section
+of the circuit. Therefore, we would want to create a single resistor PCell that can be used as a template
+in more complex circuit PCells. Here, we design a resistor that parameterized its width, length, and
+type of via connection to other metal layers.
+
+Demonstrates
+============
+
+* How to design a circuit that can interchange different via devices.
+* How to restrict the circuit to only accept vias of a certain type.
+* How to activate specific port edges that can be used for external connetions.
+
+This PCell can iterate between two different vias connections that connect metal layer ``R5`` and ``M6``;
+the *alternative* version of the *standard* version.
+
+.. code-block:: python
+
+ class Resistor(spira.Circuit):
+ """ Resistor PCell of type Circuit between two vias connecting to layer M6. """
+
+ length = spira.NumberParameter(default=7)
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE),
+ doc='Width of the shunt resistance.')
+ via = spira.CellParameter(
+ default=dev.ViaC5RS,
+ restriction=spira.RestrictType([dev.ViaC5RA, dev.ViaC5RS]),
+ doc='Via component for connecting R5 to M6')
+ text_type = spira.NumberParameter(default=92)
+
+ via_left = spira.Parameter(fdef_name='create_via_left')
+ via_right = spira.Parameter(fdef_name='create_via_right')
+
+ def validate_parameters(self):
+ if self.length < self.width:
+ raise ValueError('Length cannot be less than width.')
+ return True
+
+ def create_via_left(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90)
+ S = spira.SRef(via, transformation=T)
+ return S
+
+ def create_via_right(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90, rotation_center=(self.length, 0))
+ S = spira.SRef(via, midpoint=(self.length, 0), transformation=T)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += [self.via_left, self.via_right]
+
+ elems += RouteStraight(
+ p1=self.via_left.ports['E0_R5'],
+ p2=self.via_right.ports['E2_R5'],
+ layer=RDD.PLAYER.R5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+
+ ports += self.via_left.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.via_left.ports['E2_M6'].copy(name='P2_M6')
+ ports += self.via_left.ports['E3_M6'].copy(name='P3_M6')
+
+ ports += self.via_right.ports['E0_M6'].copy(name='P4_M6')
+ ports += self.via_right.ports['E1_M6'].copy(name='P5_M6')
+ ports += self.via_right.ports['E3_M6'].copy(name='P6_M6')
+
+ return ports
+
+The :py:data:`length` parameter can be any value as long as it is larger than the width. Therefore, the
+length parameter has no restrictions, but are validated once all parameters have been defined using the
+:py:data:`validate_parameters` method. The :py:data:`width` parameter is restricted to a minimum size,
+which implicitly mean the length is also restricted to this size value. The :py:data:`via` parameter
+has to be a PCell class and has to be of type :py:class:`dev.ViaC5RA` or :py:class:`dev.ViaC5RS`.
+
+We only want to connect to the connection vias of the instance, and therefore we only activate the ports
+of the two via instance, instead of activating all possible edge ports, as shown in the :py:data:`create_ports` method.
+
+******************
+Josephson Junction
+******************
+
+The Josephson junction is the most important device in any SDE circuit. We want to create a junction PCell
+that parameterizes the following device attributes:
+
+* The shunt resistor width.
+* The shunt resistor length.
+* The junction layer radius.
+* Boolean parameters to include/exclude via connections to ground and skyplane.
+
+Demonstrates
+============
+
+* How to design a fully parameterized Josephson junction.
+* How to add a bounding box around a set of polygon objects.
+
+The design of the junction is broken down into three sections; a top section, a bottom section, and the shunt
+resistor that connects the top and bottom sections. The top and bottom section each are wrapped with a
+bounding box polygon of metal layer ``M6``.
+
+.. code-block:: python
+
+ class __Junction__(spira.Cell):
+ """ Base class for Junction PCell. """
+
+ radius = spira.NumberParameter()
+ width = spira.NumberParameter(doc='Shunt resistance width')
+ c5r = spira.Parameter(fdef_name='create_c5r')
+
+
+ class I5Contacts(__Junction__):
+ """ Cell that contains all the vias of the bottom halve of the Junction. """
+
+ i5 = spira.Parameter(fdef_name='create_i5')
+ i6 = spira.Parameter(fdef_name='create_i6')
+
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5(self):
+ via = dev.ViaI5()
+ V = spira.SRef(via, midpoint=(0,0))
+ return V
+
+ def create_i6(self):
+ c = self.i5.midpoint
+ w = (self.i5.ref.width + 4*RDD.I6.I5_MIN_SURROUND)
+ via = dev.ViaI6(width=w, height=w)
+ V = spira.SRef(via, midpoint=c)
+ return V
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ if self.sky_via is True:
+ V.connect(port=V.ports['E0_R5'], destination=self.i6.ports['E2_M6'], ignore_process=True)
+ else:
+ V.connect(port=V.ports['E0_R5'], destination=self.i5.ports['E2_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.i5, self.c5r]
+
+ # Add the skyplane via instance if required.
+ if self.sky_via is True:
+ elems += self.i6
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.i5.ports['E2_M5'].copy(name='P2_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+
+ class J5Contacts(__Junction__):
+ """ Cell that contains all the vias of the top halve of the Junction. """
+
+ j5 = spira.Parameter(fdef_name='create_j5')
+
+ def create_j5(self):
+ jj = dev.JJ(width=2*self.radius)
+ D = spira.SRef(jj, midpoint=(0,0))
+ return D
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ V.connect(port=V.ports['E0_R5'], destination=self.j5.ports['E0_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.j5, self.c5r]
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M5'].copy(name='P0_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+The :py:class:`J5Contacts` and :py:class:`I5Contacts` classes are the top and bottom sections, respectively.
+The :py:class:`__Junction__` class is a base class that contains parameters common to both of these classes.
+As shown in the :py:data:`create_elements` methods for both classes a metal bounding box is added around
+all defined elements.
+
+The results for :py:class:`J5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a junction via that contains the actually junction layer.
+
+.. image:: _figures/_adv_junction_top.png
+ :align: center
+
+The result for :py:class:`I5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a ``I5`` via that connects layer ``M5`` to layer ``M6``. The skyplane via that connects
+``M6`` to ``M7`` is optional depending on the boolean value of the :py:data:`sky_via` parameter.
+
+.. image:: _figures/_adv_junction_bot.png
+ :align: center
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+
+ text_type = spira.NumberParameter(default=91)
+
+ length = spira.NumberParameter(default=1.5, doc='Length of the shunt resistance.')
+
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE, upper=RDD.R5.MAX_WIDTH),
+ doc='Width of the shunt resistance.')
+
+ radius = spira.NumberParameter(
+ default=RDD.J5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.J5.MIN_SIZE, upper=RDD.J5.MAX_SIZE),
+ doc='Radius of the circular junction layer.')
+
+ i5 = spira.Parameter(fdef_name='create_i5_cell')
+ j5 = spira.Parameter(fdef_name='create_j5_cell')
+
+ gnd_via = spira.BoolParameter(default=False)
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5_cell(self):
+ D = I5Contacts(width=self.width, radius=self.radius, sky_via=self.sky_via)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0, self.length))
+ return S
+
+ def create_j5_cell(self):
+ D = J5Contacts(width=self.width, radius=self.radius)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0,0))
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.i5
+ elems += self.j5
+
+ elems += RouteStraight(
+ p1=self.i5.ports['P2_R5'].copy(width=self.width),
+ p2=self.j5.ports['P2_R5'].copy(width=self.width),
+ layer=RDD.PLAYER.R5.METAL)
+
+ if self.gnd_via is True:
+ i4 = dev.ViaI4()
+ elems += spira.SRef(i4, midpoint=m5_block.center)
+
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M6'].copy(name='P0_M6')
+ ports += self.j5.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.j5.ports['E3_M6'].copy(name='P3_M6')
+ ports += self.i5.ports['E1_M6'].copy(name='P4_M6')
+ ports += self.i5.ports['E2_M6'].copy(name='P5_M6')
+ ports += self.i5.ports['E3_M6'].copy(name='P6_M6')
+ return ports
+
+The :py:class:`Junction` class is created and instances of the :py:class:`J5Contacts` and :py:class:`I5Contacts`
+cells are added and moved relative to eachother with a separation distance equal to the length of the shunt resistor.
+The instances of of these two cells are then connection via a resistive route. For debugging purposes we can disable
+the operations preformed by the :py:class:`spira.Device` class by setting ``pcell=False``. The output is shown below
+displays the individual layers of each instance.
+
+.. image:: _figures/_adv_junction_false.png
+ :align: center
+
+By enabling PCell operations again we can see that the overlapping metal layers are merged by similar process
+polygon, as shown in the figure below.
+
+.. image:: _figures/_adv_junction_true.png
+ :align: center
+
+
+
+***************************
+Josephson Transmission Line
+***************************
+
+The Josephson Transmission Line (JTL) is the most basic SFQ circuit and consist of two junctions, an
+input and output port, and a biasing port.
+
+Demonstrates
+============
+
+* How to define routes between different ports and devices.
+* How to parameterize the route widths.
+* How to include a device PCell into higher hierarchical designs.
+
+We define three width parameters to control the polygon routing width between:
+
+1. The input port and first junction.
+2. The ouput port and second junction.
+3. The first junction and second junction.
+
+Next, we create a set of *create methods* to define device and port instances.
+
+.. code-block:: python
+
+ class Jtl(spira.PCell):
+
+ w1 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of left inductor.'
+ )
+ w2 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of middle inductor.'
+ )
+ w3 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of rigth inductor.'
+ )
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+ p3 = spira.Parameter(fdef_name='create_p3')
+ p4 = spira.Parameter(fdef_name='create_p4')
+
+ jj1 = spira.Parameter(fdef_name='create_jj_left')
+ jj2 = spira.Parameter(fdef_name='create_jj_right')
+
+ shunt = spira.Parameter(fdef_name='create_shunt')
+
+ bias_res = spira.Parameter(fdef_name='create_bias_res')
+ via1 = spira.Parameter(fdef_name='create_via1')
+
+ def create_p1(self):
+ p1 = spira.Port(name='P1_M6', width=self.w1)
+ return p1.distance_alignment(port=p1, destination=self.jj1.ports['P1_M6'], distance=-10)
+
+ def create_p2(self):
+ p2 = spira.Port(name='P2_M6', width=self.w1)
+ return p2.distance_alignment(port=p2, destination=self.jj2.ports['P3_M6'], distance=10)
+
+ def create_p3(self):
+ return spira.Port(name='P3_M6', midpoint=(0, 15), orientation=270, width=self.w1)
+
+ def create_p4(self):
+ return spira.Port(name='P4_M6', midpoint=(0, 1.5), orientation=90, width=self.w1)
+
+ def create_jj_left(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(-10,0))
+ S = spira.SRef(jj, midpoint=(-10,0), transformation=T)
+ return S
+
+ def create_jj_right(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(10,0))
+ S = spira.SRef(jj, midpoint=(10,0), transformation=T)
+ return S
+
+ def create_shunt(self):
+ D = Resistor(width=1, length=3.7)
+ S = spira.SRef(reference=D, midpoint=(0,0))
+ S.distance_alignment(port='P2_M6', destination=self.p3, distance=-2.5)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.jj1
+ elems += self.jj2
+ elems += self.shunt
+
+ elems += RouteStraight(p1=self.p1,
+ p2=self.jj1.ports['P1_M6'].copy(width=self.p1.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.p2,
+ p2=self.jj2.ports['P3_M6'].copy(width=self.p2.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(
+ p1=self.jj1.ports['P3_M6'].copy(width=self.w2),
+ p2=self.jj2.ports['P1_M6'].copy(width=self.w2),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.shunt.ports['P2_M6'], p2=self.p3, layer=RDD.PLAYER.M6.ROUTE)
+ elems += RouteStraight(p1=self.shunt.ports['P4_M6'], p2=self.p4, layer=RDD.PLAYER.M6.ROUTE)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.p1
+ ports += self.p2
+ ports += self.p3
+ ports += self.p4
+ return ports
+
+This examples place two junctions, :py:data:`jj_left` and :py:data:`jj_right`, at positions (-10,0) and
+(10,0). The input port is placed a ditance of -10 to the left of :py:data:`jj_left`, and the ouput port
+a distance of 10 to the right of :py:data:`jj_right`.
+
+The biasing port, :py:data:`p3` is place at position (0,15) and port ``P2_M6`` of the biasing resistor PCell
+is place a distance of 2.5 to the bottom of :py:data:`p3`.
+
+.. image:: _figures/_adv_jtl_false.png
+ :align: center
+
+
+************************
+Electrical Rule Checking
+************************
+
+The electrical rule checking algorithm is applied on an instance using a filtering method.
+Therefore, it is easily enabled/disabled for debugging purposes.
+
+Demonstrates
+============
+
+* How to toggle the ERC algorithm.
+* How to view the electrical rule checking results using **virtual modeling**.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ f = RDD.FILTERS.PCELL.MASK
+
+ D = f(D)
+
+ from spira.yevon.vmodel.virtual import virtual_connect
+ v_model = virtual_connect(device=D)
+
+ v_model.view_virtual_connect(show_layers=True)
+
+.. image:: _figures/_adv_jtl_erc.png
+ :align: center
+
+The resultant layout or view of a cicuit that contains *virtual elements* that will not be included in the final design, is called a **virtual model**.
+The above example illustrates how electrical rule checking can be debugged using virtually constructed polygons.
+
+
+******************
+Netlist Extraction
+******************
+
+Netlists for PCells can be extracted and viewed in a graph representation.
+
+Demonstrates
+============
+
+* How to extract the netlist graph of a PCell.
+* How to view the extracted graph.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ D = RDD.FILTERS.PCELL.MASK(D)
+
+ # Extract the physical netlist.
+ net = D.extract_netlist
+
+ # View the netlist.
+ D.netlist_view(net=net)
+
+Before running the netlist extraction algorithm it is important to first apply the required filters to the pcell instance.
+These filters includes running electrical rule checking algorithm and compressing terminal ports down onto their corresponding polygon instances.
+It is also possible to toggle certain filters for debugging purposes:
+
+.. code-block:: python
+
+ D = Jtl()
+
+ f = RDD.FILTERS.PCELL.MASK
+
+ f['pin_attach'] = False
+
+ D = f(D)
+
+ net = D.extract_netlist
+
+ D.netlist_view(net=net)
+
+The above example illustrates the extracted netlist if the **pin attach** algorithm is disabled.
+The added terminal ports are not detected by the netlist run, since they are not compressed down the layout hierarchy onto their corresponding polygons.
+The following image shows the different extracted netlists for a basic JTL layout using the code snippets previously discussed.
+
+.. image:: _figures/_adv_jtl_net.png
+ :align: center
+
+
diff --git a/docs/_4_reference.rst b/docs/_4_reference.rst
new file mode 100644
index 00000000..a47c1b39
--- /dev/null
+++ b/docs/_4_reference.rst
@@ -0,0 +1,5 @@
+#########
+Reference
+#########
+
+
diff --git a/docs/developers.rst b/docs/_5_developers.rst
similarity index 90%
rename from docs/developers.rst
rename to docs/_5_developers.rst
index 76837c85..1e3a224c 100644
--- a/docs/developers.rst
+++ b/docs/_5_developers.rst
@@ -1,8 +1,7 @@
Developers
==========
-Documentation for developers for maintaining and extending. Extra information is added
-to better understand specific code implementations.
+Documentation for developers for maintaining and extending.
Distribtuion
------------
@@ -65,8 +64,6 @@ The following are useful links to some of the mixin implementations used in the
* https://stackoverflow.com/questions/6966772/using-the-call-
* method-of-a-metaclass-instead-of-new
-Metaprogramming
----------------
diff --git a/docs/_build/doctrees/_0_methodology.doctree b/docs/_build/doctrees/_0_methodology.doctree
new file mode 100644
index 00000000..fc027674
Binary files /dev/null and b/docs/_build/doctrees/_0_methodology.doctree differ
diff --git a/docs/_build/doctrees/_1_overview.doctree b/docs/_build/doctrees/_1_overview.doctree
new file mode 100644
index 00000000..0141bb99
Binary files /dev/null and b/docs/_build/doctrees/_1_overview.doctree differ
diff --git a/docs/_build/doctrees/_2_basic.doctree b/docs/_build/doctrees/_2_basic.doctree
new file mode 100644
index 00000000..19d1ace5
Binary files /dev/null and b/docs/_build/doctrees/_2_basic.doctree differ
diff --git a/docs/_build/doctrees/_3_advanced.doctree b/docs/_build/doctrees/_3_advanced.doctree
new file mode 100644
index 00000000..32e2167b
Binary files /dev/null and b/docs/_build/doctrees/_3_advanced.doctree differ
diff --git a/docs/_build/doctrees/_4_reference.doctree b/docs/_build/doctrees/_4_reference.doctree
new file mode 100644
index 00000000..89b68bb8
Binary files /dev/null and b/docs/_build/doctrees/_4_reference.doctree differ
diff --git a/docs/_build/doctrees/_5_developers.doctree b/docs/_build/doctrees/_5_developers.doctree
new file mode 100644
index 00000000..71fe5285
Binary files /dev/null and b/docs/_build/doctrees/_5_developers.doctree differ
diff --git a/docs/_build/doctrees/developers.doctree b/docs/_build/doctrees/developers.doctree
index 14fcbb26..6c6e9ba4 100644
Binary files a/docs/_build/doctrees/developers.doctree and b/docs/_build/doctrees/developers.doctree differ
diff --git a/docs/_build/doctrees/gdsii.doctree b/docs/_build/doctrees/gdsii.doctree
index cdb1bb6e..746fe0ef 100644
Binary files a/docs/_build/doctrees/gdsii.doctree and b/docs/_build/doctrees/gdsii.doctree differ
diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree
index 408500ca..b2bcdea0 100644
Binary files a/docs/_build/doctrees/index.doctree and b/docs/_build/doctrees/index.doctree differ
diff --git a/docs/_build/doctrees/installation.doctree b/docs/_build/doctrees/installation.doctree
deleted file mode 100644
index 3fdc86e8..00000000
Binary files a/docs/_build/doctrees/installation.doctree and /dev/null differ
diff --git a/docs/_build/doctrees/overview.doctree b/docs/_build/doctrees/overview.doctree
index fab13a83..399a6759 100644
Binary files a/docs/_build/doctrees/overview.doctree and b/docs/_build/doctrees/overview.doctree differ
diff --git a/docs/_build/doctrees/overview_old.doctree b/docs/_build/doctrees/overview_old.doctree
new file mode 100644
index 00000000..96c9077e
Binary files /dev/null and b/docs/_build/doctrees/overview_old.doctree differ
diff --git a/docs/_build/doctrees/parameters.doctree b/docs/_build/doctrees/parameters.doctree
index a7f87bcd..3593c243 100644
Binary files a/docs/_build/doctrees/parameters.doctree and b/docs/_build/doctrees/parameters.doctree differ
diff --git a/docs/_build/doctrees/pcell_examples.doctree b/docs/_build/doctrees/pcell_examples.doctree
index e5400918..1ae1c8c3 100644
Binary files a/docs/_build/doctrees/pcell_examples.doctree and b/docs/_build/doctrees/pcell_examples.doctree differ
diff --git a/docs/_build/doctrees/pdk.doctree b/docs/_build/doctrees/pdk.doctree
new file mode 100644
index 00000000..dfbf0707
Binary files /dev/null and b/docs/_build/doctrees/pdk.doctree differ
diff --git a/docs/_build/doctrees/rdd_schema.doctree b/docs/_build/doctrees/rdd_schema.doctree
index c7c09079..dd775120 100644
Binary files a/docs/_build/doctrees/rdd_schema.doctree and b/docs/_build/doctrees/rdd_schema.doctree differ
diff --git a/docs/_build/doctrees/setup.doctree b/docs/_build/doctrees/setup.doctree
deleted file mode 100644
index 519cbad8..00000000
Binary files a/docs/_build/doctrees/setup.doctree and /dev/null differ
diff --git a/docs/_build/doctrees/tutorials.doctree b/docs/_build/doctrees/tutorials.doctree
index 3eac13f6..cc121311 100644
Binary files a/docs/_build/doctrees/tutorials.doctree and b/docs/_build/doctrees/tutorials.doctree differ
diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo
index 7fefaa4d..25f77cb4 100644
--- a/docs/_build/html/.buildinfo
+++ b/docs/_build/html/.buildinfo
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 35e62fe88854bb4ce94fe73921793229
+config: 7471fab6c1a18c1104d55b4919740668
tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/_build/html/.doctrees/_0_methodology.doctree b/docs/_build/html/.doctrees/_0_methodology.doctree
new file mode 100644
index 00000000..7ea56db7
Binary files /dev/null and b/docs/_build/html/.doctrees/_0_methodology.doctree differ
diff --git a/docs/_build/html/.doctrees/_1_overview.doctree b/docs/_build/html/.doctrees/_1_overview.doctree
new file mode 100644
index 00000000..eace7965
Binary files /dev/null and b/docs/_build/html/.doctrees/_1_overview.doctree differ
diff --git a/docs/_build/html/.doctrees/_2_basic.doctree b/docs/_build/html/.doctrees/_2_basic.doctree
new file mode 100644
index 00000000..4a734d3f
Binary files /dev/null and b/docs/_build/html/.doctrees/_2_basic.doctree differ
diff --git a/docs/_build/html/.doctrees/_2_tutorials.doctree b/docs/_build/html/.doctrees/_2_tutorials.doctree
new file mode 100644
index 00000000..c3869829
Binary files /dev/null and b/docs/_build/html/.doctrees/_2_tutorials.doctree differ
diff --git a/docs/_build/html/.doctrees/_3_advanced.doctree b/docs/_build/html/.doctrees/_3_advanced.doctree
new file mode 100644
index 00000000..e439e8e2
Binary files /dev/null and b/docs/_build/html/.doctrees/_3_advanced.doctree differ
diff --git a/docs/_build/html/.doctrees/_3_reference.doctree b/docs/_build/html/.doctrees/_3_reference.doctree
new file mode 100644
index 00000000..1ea18ae4
Binary files /dev/null and b/docs/_build/html/.doctrees/_3_reference.doctree differ
diff --git a/docs/_build/html/.doctrees/_4_reference.doctree b/docs/_build/html/.doctrees/_4_reference.doctree
new file mode 100644
index 00000000..9c37f92b
Binary files /dev/null and b/docs/_build/html/.doctrees/_4_reference.doctree differ
diff --git a/docs/_build/html/.doctrees/_5_developers.doctree b/docs/_build/html/.doctrees/_5_developers.doctree
new file mode 100644
index 00000000..c3593c6b
Binary files /dev/null and b/docs/_build/html/.doctrees/_5_developers.doctree differ
diff --git a/docs/_build/html/.doctrees/developers.doctree b/docs/_build/html/.doctrees/developers.doctree
new file mode 100644
index 00000000..6c6e9ba4
Binary files /dev/null and b/docs/_build/html/.doctrees/developers.doctree differ
diff --git a/docs/_build/html/.doctrees/framework.doctree b/docs/_build/html/.doctrees/framework.doctree
new file mode 100644
index 00000000..5b3965e5
Binary files /dev/null and b/docs/_build/html/.doctrees/framework.doctree differ
diff --git a/docs/_build/html/.doctrees/gdsii.doctree b/docs/_build/html/.doctrees/gdsii.doctree
new file mode 100644
index 00000000..746fe0ef
Binary files /dev/null and b/docs/_build/html/.doctrees/gdsii.doctree differ
diff --git a/docs/_build/html/.doctrees/gettingstarted.doctree b/docs/_build/html/.doctrees/gettingstarted.doctree
new file mode 100644
index 00000000..7df3120c
Binary files /dev/null and b/docs/_build/html/.doctrees/gettingstarted.doctree differ
diff --git a/docs/_build/html/.doctrees/index.doctree b/docs/_build/html/.doctrees/index.doctree
new file mode 100644
index 00000000..7f7eab73
Binary files /dev/null and b/docs/_build/html/.doctrees/index.doctree differ
diff --git a/docs/_build/html/.doctrees/overview.doctree b/docs/_build/html/.doctrees/overview.doctree
new file mode 100644
index 00000000..399a6759
Binary files /dev/null and b/docs/_build/html/.doctrees/overview.doctree differ
diff --git a/docs/_build/html/.doctrees/overview_old.doctree b/docs/_build/html/.doctrees/overview_old.doctree
new file mode 100644
index 00000000..a8eae9f3
Binary files /dev/null and b/docs/_build/html/.doctrees/overview_old.doctree differ
diff --git a/docs/_build/html/.doctrees/parameters.doctree b/docs/_build/html/.doctrees/parameters.doctree
new file mode 100644
index 00000000..3593c243
Binary files /dev/null and b/docs/_build/html/.doctrees/parameters.doctree differ
diff --git a/docs/_build/html/.doctrees/pcell_examples.doctree b/docs/_build/html/.doctrees/pcell_examples.doctree
new file mode 100644
index 00000000..1ae1c8c3
Binary files /dev/null and b/docs/_build/html/.doctrees/pcell_examples.doctree differ
diff --git a/docs/_build/html/.doctrees/pdk.doctree b/docs/_build/html/.doctrees/pdk.doctree
new file mode 100644
index 00000000..dfbf0707
Binary files /dev/null and b/docs/_build/html/.doctrees/pdk.doctree differ
diff --git a/docs/_build/html/.doctrees/rdd_schema.doctree b/docs/_build/html/.doctrees/rdd_schema.doctree
new file mode 100644
index 00000000..dd775120
Binary files /dev/null and b/docs/_build/html/.doctrees/rdd_schema.doctree differ
diff --git a/docs/_build/html/.doctrees/tutorials.doctree b/docs/_build/html/.doctrees/tutorials.doctree
new file mode 100644
index 00000000..cc121311
Binary files /dev/null and b/docs/_build/html/.doctrees/tutorials.doctree differ
diff --git a/docs/_build/html/_downloads/1d02506b92a2f8a3ba1d3b93325cc26f/jj_squid.py b/docs/_build/html/_downloads/1d02506b92a2f8a3ba1d3b93325cc26f/jj_squid.py
deleted file mode 100644
index 63094401..00000000
--- a/docs/_build/html/_downloads/1d02506b92a2f8a3ba1d3b93325cc26f/jj_squid.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import spira
-from spira import param
-from spira.rdd import get_rule_deck
-from examples.junction import Junction
-
-
-RDD = get_rule_deck()
-
-
-class JunctionSquid(spira.Cell):
-
- width = param.FloatField()
- height = param.FloatField()
- midpoint = param.FloatField()
- w = param.FloatField()
- h = param.FloatField()
-
- top_routing = param.DataField(fdef_name='create_top_routing')
- bot_routing = param.DataField(fdef_name='create_bot_routing')
-
- def create_top_routing(self):
- p1 = [self.midpoint, self.h/2]
- p2 = [self.midpoint, self.h/2+self.height]
- p3 = [self.width, self.h/2+self.height]
- p4 = [self.width, self.h/2]
-
- points = [p1, p2, p3, p4]
-
- return spira.Path(points, width=1, gdslayer=RDD.M5, distance=3)
-
- def create_bot_routing(self):
- p1 = [self.midpoint, -self.h/2]
- p2 = [self.midpoint, -self.height]
- p3 = [self.width, -self.height]
- p4 = [self.width, -self.h/2]
-
- points = [p1, p2, p3, p4]
-
- return spira.Path(points, width=1, gdslayer=RDD.M6, distance=3)
-
- def create_elementals(self, elems):
-
- jj = Junction()
-
- # FIXME: Automate this movement.
- jj.move(origin=jj.center, destination=(0,0))
-
- # FIXME: Rotation applies to parent cell.
- j1 = spira.SRef(jj, origin=(-1, 0), rotation=90)
- # j1.move(origin=j1.ref.center, destination=(0,0))
- j2 = spira.SRef(jj, origin=(10.5, 0), rotation=180)
-
- elems += j1
- elems += j2
-
- elems += self.top_routing
- elems += self.bot_routing
-
- return elems
-
-
-if __name__ == '__main__':
-
- # from spira import settings
- # from spira.templates.library import library
-
- # settings.set_library(library)
-
- name = 'jj_squid'
- doc = 'Squid PCell with Junctions included.'
-
- spira.LOG.header('Running example: {}'.format(name))
-
- jj = JunctionSquid(width=10, height=3, w=5, h=0.5)
- jj.output(name=name)
-
- spira.LOG.end_print('Junction example finished')
-
diff --git a/docs/_build/html/_downloads/4bae37d49ce471ba89e3805fa3f3ca4a/junction.py b/docs/_build/html/_downloads/4bae37d49ce471ba89e3805fa3f3ca4a/junction.py
deleted file mode 100644
index cdfa61c1..00000000
--- a/docs/_build/html/_downloads/4bae37d49ce471ba89e3805fa3f3ca4a/junction.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import spira
-from spira import param
-from spira import Rectangle
-from spira.rdd import get_rule_deck
-
-
-RDD = get_rule_deck()
-
-
-class PhysicalLayer(spira.Cell):
-
- points = param.ListField()
- layer = param.LayerField()
-
- def create_elementals(self, elems):
- for pp in self.points:
- elems += Rectangle(point1=pp[0],
- point2=pp[1],
- layer=self.layer)
- return elems
-
-
-class Junction(spira.Cell):
-
- def create_elementals(self, elems):
-
- p0 = [[[0.5, -1.4], [3.4, -0.3]]]
- elems += PhysicalLayer(points=p0, layer=RDD.M6)
-
- p1 = [[[0.3, 0.3], [3.6, 3]],
- [[1.45, 2.8], [2.45, 5]],
- [[1.25, 4.75], [2.65, 6]]]
- elems += PhysicalLayer(points=p1, layer=RDD.M5)
-
- p2 = [[[0, -2], [3.8, 3.2]],
- [[1, 4.6], [2.9, 7.3]]]
- elems += PhysicalLayer(points=p2, layer=RDD.I5)
-
- p3 = [[[0.3, -1.6], [3.6, 3]],
- [[1.3, 4.8], [2.6, 6]]]
- elems += PhysicalLayer(points=p3, layer=RDD.I4)
-
- p4 = [[[1, 1], [2.9, 2.3]]]
- elems += PhysicalLayer(points=p4, layer=RDD.J5)
-
- p5 = [[[1, 1], [2.9, 2.3]]]
- elems += PhysicalLayer(points=p5, layer=RDD.C5)
-
- p6 = [[[1.3, 6.3], [2.6, 7]]]
- elems += PhysicalLayer(points=p6, layer=RDD.R5)
-
- p7 = [[[1, 0.5], [2.9, 7.3]]]
- elems += PhysicalLayer(points=p7, layer=RDD.M7)
-
- # p8 = [[[1.3, 1.3], [2.6, 2]]]
- # elems += PhysicalLayer(points=p8, layer=10)
-
- return elems
-
-
-if __name__ == '__main__':
-
- from spira import settings
- from spira.templates.library import library
-
- settings.set_library(library)
-
- name = 'Junction_PCell'
-
- spira.LOG.header('Running example: {}'.format(name))
-
- jj = Junction()
- print(jj.center)
- jj.output(name=name)
-
- spira.LOG.end_print('Junction example finished')
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/_build/html/_downloads/b075975b765182e8dd05ecc785d45c5c/junction.py b/docs/_build/html/_downloads/b075975b765182e8dd05ecc785d45c5c/junction.py
deleted file mode 100644
index 5ffc87e2..00000000
--- a/docs/_build/html/_downloads/b075975b765182e8dd05ecc785d45c5c/junction.py
+++ /dev/null
@@ -1,87 +0,0 @@
-import spira
-from spira import param
-from spira import Rectangle
-from spira.rdd import get_rule_deck
-
-
-RDD = get_rule_deck()
-
-
-class PhysicalLayer(spira.Cell):
-
- points = param.ListField()
- layer = param.LayerField()
-
- def create_elementals(self, elems):
- for pp in self.points:
- elems += Rectangle(point1=pp[0],
- point2=pp[1],
- layer=self.layer)
- return elems
-
-
-class Junction(spira.Cell):
-
- def create_elementals(self, elems):
-
- p0 = [[[0.5, -1.4], [3.4, -0.3]]]
- elems += PhysicalLayer(points=p0, layer=RDD.M6)
-
- p1 = [[[0.3, 0.3], [3.6, 3]],
- [[1.45, 2.8], [2.45, 5]],
- [[1.25, 4.75], [2.65, 6]]]
- elems += PhysicalLayer(points=p1, layer=RDD.M5)
-
- p2 = [[[0, -2], [3.8, 3.2]],
- [[1, 4.6], [2.9, 7.3]]]
- elems += PhysicalLayer(points=p2, layer=RDD.I5)
-
- p3 = [[[0.3, -1.6], [3.6, 3]],
- [[1.3, 4.8], [2.6, 6]]]
- elems += PhysicalLayer(points=p3, layer=RDD.I4)
-
- p4 = [[[1, 1], [2.9, 2.3]]]
- elems += PhysicalLayer(points=p4, layer=RDD.J5)
-
- p5 = [[[1, 1], [2.9, 2.3]]]
- elems += PhysicalLayer(points=p5, layer=RDD.C5)
-
- p6 = [[[1.3, 6.3], [2.6, 7]]]
- elems += PhysicalLayer(points=p6, layer=RDD.R5)
-
- p7 = [[[1, 0.5], [2.9, 7.3]]]
- elems += PhysicalLayer(points=p7, layer=RDD.M7)
-
- # p8 = [[[1.3, 1.3], [2.6, 2]]]
- # elems += PhysicalLayer(points=p8, layer=10)
-
- return elems
-
-
-if __name__ == '__main__':
-
- from spira import settings
- from spira.templates.library import library
-
- settings.set_library(library)
-
- name = 'Junction_PCell'
-
- spira.LOG.header('Running example: {}'.format(name))
-
- jj = Junction()
- jj.output(name=name)
-
- spira.LOG.end_print('Junction example finished')
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/_build/html/_downloads/e01eb95222e41b891d63122bea92f786/jj_squid.py b/docs/_build/html/_downloads/e01eb95222e41b891d63122bea92f786/jj_squid.py
deleted file mode 100644
index 63094401..00000000
--- a/docs/_build/html/_downloads/e01eb95222e41b891d63122bea92f786/jj_squid.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import spira
-from spira import param
-from spira.rdd import get_rule_deck
-from examples.junction import Junction
-
-
-RDD = get_rule_deck()
-
-
-class JunctionSquid(spira.Cell):
-
- width = param.FloatField()
- height = param.FloatField()
- midpoint = param.FloatField()
- w = param.FloatField()
- h = param.FloatField()
-
- top_routing = param.DataField(fdef_name='create_top_routing')
- bot_routing = param.DataField(fdef_name='create_bot_routing')
-
- def create_top_routing(self):
- p1 = [self.midpoint, self.h/2]
- p2 = [self.midpoint, self.h/2+self.height]
- p3 = [self.width, self.h/2+self.height]
- p4 = [self.width, self.h/2]
-
- points = [p1, p2, p3, p4]
-
- return spira.Path(points, width=1, gdslayer=RDD.M5, distance=3)
-
- def create_bot_routing(self):
- p1 = [self.midpoint, -self.h/2]
- p2 = [self.midpoint, -self.height]
- p3 = [self.width, -self.height]
- p4 = [self.width, -self.h/2]
-
- points = [p1, p2, p3, p4]
-
- return spira.Path(points, width=1, gdslayer=RDD.M6, distance=3)
-
- def create_elementals(self, elems):
-
- jj = Junction()
-
- # FIXME: Automate this movement.
- jj.move(origin=jj.center, destination=(0,0))
-
- # FIXME: Rotation applies to parent cell.
- j1 = spira.SRef(jj, origin=(-1, 0), rotation=90)
- # j1.move(origin=j1.ref.center, destination=(0,0))
- j2 = spira.SRef(jj, origin=(10.5, 0), rotation=180)
-
- elems += j1
- elems += j2
-
- elems += self.top_routing
- elems += self.bot_routing
-
- return elems
-
-
-if __name__ == '__main__':
-
- # from spira import settings
- # from spira.templates.library import library
-
- # settings.set_library(library)
-
- name = 'jj_squid'
- doc = 'Squid PCell with Junctions included.'
-
- spira.LOG.header('Running example: {}'.format(name))
-
- jj = JunctionSquid(width=10, height=3, w=5, h=0.5)
- jj.output(name=name)
-
- spira.LOG.end_print('Junction example finished')
-
diff --git a/docs/_build/html/_images/RouteConnect.png b/docs/_build/html/_images/RouteConnect.png
new file mode 100644
index 00000000..202b7875
Binary files /dev/null and b/docs/_build/html/_images/RouteConnect.png differ
diff --git a/docs/_build/html/_images/_3_layout.png b/docs/_build/html/_images/_3_layout.png
new file mode 100644
index 00000000..66051e2b
Binary files /dev/null and b/docs/_build/html/_images/_3_layout.png differ
diff --git a/docs/_build/html/_images/_4_ports_0.png b/docs/_build/html/_images/_4_ports_0.png
new file mode 100644
index 00000000..67f52142
Binary files /dev/null and b/docs/_build/html/_images/_4_ports_0.png differ
diff --git a/docs/_build/html/_images/_4_ports_0_enabled.png b/docs/_build/html/_images/_4_ports_0_enabled.png
new file mode 100644
index 00000000..6f26290a
Binary files /dev/null and b/docs/_build/html/_images/_4_ports_0_enabled.png differ
diff --git a/docs/_build/html/_images/_4_ports_1.png b/docs/_build/html/_images/_4_ports_1.png
new file mode 100644
index 00000000..842a40b3
Binary files /dev/null and b/docs/_build/html/_images/_4_ports_1.png differ
diff --git a/docs/_build/html/_images/_5_routes_0.png b/docs/_build/html/_images/_5_routes_0.png
new file mode 100644
index 00000000..fa2baba4
Binary files /dev/null and b/docs/_build/html/_images/_5_routes_0.png differ
diff --git a/docs/_build/html/_images/_6_hierarchy_0.png b/docs/_build/html/_images/_6_hierarchy_0.png
new file mode 100644
index 00000000..cba03721
Binary files /dev/null and b/docs/_build/html/_images/_6_hierarchy_0.png differ
diff --git a/docs/_build/html/_images/_6_hierarchy_1.png b/docs/_build/html/_images/_6_hierarchy_1.png
new file mode 100644
index 00000000..23f4c9eb
Binary files /dev/null and b/docs/_build/html/_images/_6_hierarchy_1.png differ
diff --git a/docs/_build/html/_images/_9_expanded.png b/docs/_build/html/_images/_9_expanded.png
new file mode 100644
index 00000000..71510e79
Binary files /dev/null and b/docs/_build/html/_images/_9_expanded.png differ
diff --git a/docs/_build/html/_images/_9_factor.png b/docs/_build/html/_images/_9_factor.png
new file mode 100644
index 00000000..a60600dc
Binary files /dev/null and b/docs/_build/html/_images/_9_factor.png differ
diff --git a/docs/_build/html/_images/_9_ports.png b/docs/_build/html/_images/_9_ports.png
new file mode 100644
index 00000000..3557c8bd
Binary files /dev/null and b/docs/_build/html/_images/_9_ports.png differ
diff --git a/docs/_build/html/_images/_9_transform.png b/docs/_build/html/_images/_9_transform.png
new file mode 100644
index 00000000..892bedea
Binary files /dev/null and b/docs/_build/html/_images/_9_transform.png differ
diff --git a/docs/_build/html/_images/_9_translate.png b/docs/_build/html/_images/_9_translate.png
new file mode 100644
index 00000000..2ff7e1f8
Binary files /dev/null and b/docs/_build/html/_images/_9_translate.png differ
diff --git a/docs/_build/html/_images/_adv_0_ytron.png b/docs/_build/html/_images/_adv_0_ytron.png
new file mode 100644
index 00000000..ada91a91
Binary files /dev/null and b/docs/_build/html/_images/_adv_0_ytron.png differ
diff --git a/docs/_build/html/_images/_adv_0_ytron_circuit.png b/docs/_build/html/_images/_adv_0_ytron_circuit.png
new file mode 100644
index 00000000..69b2104d
Binary files /dev/null and b/docs/_build/html/_images/_adv_0_ytron_circuit.png differ
diff --git a/docs/_build/html/_images/_adv_0_ytron_pcell.png b/docs/_build/html/_images/_adv_0_ytron_pcell.png
new file mode 100644
index 00000000..6dde0f95
Binary files /dev/null and b/docs/_build/html/_images/_adv_0_ytron_pcell.png differ
diff --git a/docs/_build/html/_images/_adv_erc_jtl.png b/docs/_build/html/_images/_adv_erc_jtl.png
new file mode 100644
index 00000000..63cb81b4
Binary files /dev/null and b/docs/_build/html/_images/_adv_erc_jtl.png differ
diff --git a/docs/_build/html/_images/_adv_jtl_erc.png b/docs/_build/html/_images/_adv_jtl_erc.png
new file mode 100644
index 00000000..78717e2e
Binary files /dev/null and b/docs/_build/html/_images/_adv_jtl_erc.png differ
diff --git a/docs/_build/html/_images/_adv_jtl_false.png b/docs/_build/html/_images/_adv_jtl_false.png
new file mode 100644
index 00000000..e60a2bf5
Binary files /dev/null and b/docs/_build/html/_images/_adv_jtl_false.png differ
diff --git a/docs/_build/html/_images/_adv_jtl_net.png b/docs/_build/html/_images/_adv_jtl_net.png
new file mode 100644
index 00000000..644ee118
Binary files /dev/null and b/docs/_build/html/_images/_adv_jtl_net.png differ
diff --git a/docs/_build/html/_images/_adv_jtl_netlist.png b/docs/_build/html/_images/_adv_jtl_netlist.png
new file mode 100644
index 00000000..b71d6677
Binary files /dev/null and b/docs/_build/html/_images/_adv_jtl_netlist.png differ
diff --git a/docs/_build/html/_images/_adv_junction_bot.png b/docs/_build/html/_images/_adv_junction_bot.png
new file mode 100644
index 00000000..7f0852e2
Binary files /dev/null and b/docs/_build/html/_images/_adv_junction_bot.png differ
diff --git a/docs/_build/html/_images/_adv_junction_false.png b/docs/_build/html/_images/_adv_junction_false.png
new file mode 100644
index 00000000..8c828730
Binary files /dev/null and b/docs/_build/html/_images/_adv_junction_false.png differ
diff --git a/docs/_build/html/_images/_adv_junction_top.png b/docs/_build/html/_images/_adv_junction_top.png
new file mode 100644
index 00000000..7a711b61
Binary files /dev/null and b/docs/_build/html/_images/_adv_junction_top.png differ
diff --git a/docs/_build/html/_images/_adv_junction_true.png b/docs/_build/html/_images/_adv_junction_true.png
new file mode 100644
index 00000000..9e5053ff
Binary files /dev/null and b/docs/_build/html/_images/_adv_junction_true.png differ
diff --git a/docs/_build/html/_images/_elements.png b/docs/_build/html/_images/_elements.png
new file mode 100644
index 00000000..b724d5f0
Binary files /dev/null and b/docs/_build/html/_images/_elements.png differ
diff --git a/docs/_build/html/_images/_group.png b/docs/_build/html/_images/_group.png
new file mode 100644
index 00000000..df08934a
Binary files /dev/null and b/docs/_build/html/_images/_group.png differ
diff --git a/docs/_build/html/_images/_ports.png b/docs/_build/html/_images/_ports.png
new file mode 100644
index 00000000..7efaa364
Binary files /dev/null and b/docs/_build/html/_images/_ports.png differ
diff --git a/docs/_build/html/_images/_routes.png b/docs/_build/html/_images/_routes.png
new file mode 100644
index 00000000..a2b599c1
Binary files /dev/null and b/docs/_build/html/_images/_routes.png differ
diff --git a/docs/_build/html/_sources/_0_methodology.rst.txt b/docs/_build/html/_sources/_0_methodology.rst.txt
new file mode 100644
index 00000000..8ed97ad7
--- /dev/null
+++ b/docs/_build/html/_sources/_0_methodology.rst.txt
@@ -0,0 +1,92 @@
+###########
+Methodology
+###########
+
+Using general mathematics and science as an analogy, a basic understanding
+can be constructed of the importance of software in IC design: *Mathematics is
+the discipline of proving provable statements true and science is the discipline
+of proving provable statements false*.
+
+***************************************
+The Importance of Software in IC Design
+***************************************
+
+In software development, testing shows the presence of bugs and not the absence thereof. Software development is not
+a mathematical endeavour, even though it seems to manipulate mathematical
+constructs. Rather, software is more connected to science in the sense that it
+shows correctness by failing to show incorrectness. Therefore, IC design is to
+some extent only as good as the software systems that can prove the design
+incorrect. Circuit verification software only shows the engineer where
+mistakes are made, if any.
+
+Structured programming elicits a design architect that recursively decomposes
+a program into a set of small provable functions. Unit tests can be
+used to try and prove these small provable functions incorrect. If such tests
+fail to prove incorrectness, then the functions are deemed to be correct enough
+for all intents and purposes. Superconducting Electronic Design Automation
+(S-EDA) tools from a macro view can be thought of as a set of unit tests for
+a hardware design engineer to stress test their circuit layouts.
+
+***********************************
+The Development Psychology of SPiRA
+***********************************
+
+The development history of SPiRA can be broken down into four phases. First,
+a rudimentary version that consisted of a collection of scripts. Second, a
+small project that assimilated a minimum set of functions and class objects.
+Third, a large systemic project with multiple coherently connected modules.
+Finally, a meticulously designed framework that uses special coding techniques
+to create dynamic binding, software pattern implementation, data abstraction
+and custom classes.
+
+Before understanding the reasoning behind developing a parameterized framework
+for *physical design verification* it is imporant to first categorize the type
+of problem we are dealing with:
+
+Deductive Logic
+===============
+
+Deductive logic implies applying general rules which hold over the entirety
+of a closed domain of discourse: Software solutions that will most likely not
+change in the near future, tend to solve problems that are implicit in the technology.
+The reading and parsing of GDSII layouts, and geometry modeling,
+are examples implemented, through solutions that use deductive reasoning.
+
+Inductive Logic
+===============
+
+Inductive logic is inherently uncertain; the results concluded from inductive reasoning are more nuanced than simply stating; if this, then that.
+Consequently, heuristics can be derived using inductive reasoning to develop a sufficient SDE verification tool:
+Implementing fabrication design rules must be done following inductive logic, since future technology changes in the superconductor
+electronics field are still speculative. For instance, currently there is no specific PDK setup for superconductor electronics, and consequently, it
+can either be assumed that the future PDK versions will be similar to that of semiconducting, or that it will prevail and create a new set of standards.
+Also, the rapid changes being made in the semiconductor field add to the uncertainty of future metadata in the field of superconductivity.
+
+The symmetries between the superconductor and the semiconductor field are not necessarily indicative of the future evolution of superconductor electronics.
+Therefore, a paradigmatic software system (not just a solution) has to be developed, which can accommodate for dynamic "meta-changes", while still being extendible and maintainable.
+Physical design verification is highly dependent on the modelling of design rules. Layout generators allows us to effectively create our own programmable
+circuit models. Only minor differences exist between different fabrication processes, which enables us to develop a general software verification package
+by focusing on creating solution heuristics, through inductive models, rather than trying to develop concrete deductive solutions.
+
+Metaprogramming
+===============
+
+Technical sophistication can, at some level, cause degradation.
+Metaprogramming forms the foundation of the SPiRA framework and therefore it becomes
+apparent to start with a more general explanation of a metamodel.
+A model is an abstraction of a real-world phenomena. A metamodel is an
+even higher level of abstraction, which coalesces the properties of the original
+model. A model conforms to its metamodel like a human conforms its understanding to the sophistication of its internal dictionary (language)—or lack thereof.
+Metamodeling is the construction of a collection of concepts within a certain domain. Metamodeling involves defining the output and input relationships and
+then fitting the correct metamodels to represent the desired behaviour.
+Analogously, binding generic data to a layout has to be done by developing
+a metamodel of the system. The inherit purpose of the base metaclasses in
+the SPiRA framework is to bind data to a class object depending on the
+class composition. This has to be done after defining the class constituents
+(parameters), but before class creation. Hence, the use of metaclasses. In
+Python a class is an object that can be dynamically manipulated. Therefore,
+constraints have to be implemented on the class so as to overcome information
+overloading. In order to constrain the class, it has to be known which data to
+filter and which to process, which must then be added to the class as attributes.
+In doing this, the concept evolves that the accepted data itself can be restricted
+to a specific domain. This is the core principle behind the **validate-by-design** method
diff --git a/docs/_build/html/_sources/_1_overview.rst.txt b/docs/_build/html/_sources/_1_overview.rst.txt
new file mode 100644
index 00000000..3b52a40b
--- /dev/null
+++ b/docs/_build/html/_sources/_1_overview.rst.txt
@@ -0,0 +1,764 @@
+########
+Overview
+########
+
+This overview discusses the basic constituents of the **SPiRA** framework.
+This includes how data from the fabrication process is connected to the design environment,
+the basic design template for creating parameterized cells, and how different layout
+elements are defined.
+
+******************
+Process Design Kit
+******************
+
+The process design kit (PDK) is a set of technology files needed to implement
+the physical aspects of a layout design. Application-specific rules specified
+in the PDK controls how physical design applications work.
+
+A new PDK scheme is introduced. The Python programming language is used to
+bind PDK data to a set of classes, called data trees, that uniquely categorises
+PDK data. This new PDK scheme is called the Rule Deck Database (RDD), also
+refered to as the Rule Design Database. By having a native PDK in Python it
+becomes possible to use methods from the SPiRA framework to create a
+more descriptive PDK database. A design process typically contains the
+following aspects:
+
+* *GDSII Data*: Contains general settings required by the GDSII library, such as grid size.
+* *Process Data*: Contains the process layers, layer purposes, layer parameters, and layer mappings.
+* *Virtual Modelling*: Define derived layers that describes layer boolean operations.
+
+
+Initialization
+==============
+
+All caps are used to represent the *RDD* syntax. The reason being to make the
+script structure clearly distinguishable from the rest of the framework source
+code. First, the RDD object is initialized, followed by the process name and
+description, and then the GDSII related variables are defined.
+
+.. code-block:: python
+
+ RDD.GDSII = ParameterDatabase()
+ RDD.GDSII.UNIT = 1e-6
+ RDD.GDSII.GRID = 1e-12
+ RDD.GDSII.PRECISION = 1e-9
+
+
+Process Data
+============
+
+Process data relates to data provided by a specific fabrication technology.
+
+Process Layer
+-------------
+
+The first step in creating a layer is to define the process step that
+it represents in mask fabrication. The layer **process** defines a specific
+fabrciation function, for examples **metalization**. There can be multiple
+different drawing layers for a single process. A process database object
+is created that contains all the different process steps in a specific
+fabrication process:
+
+.. code-block:: python
+
+ RDD.PROCESS = ProcessLayerDatabase()
+
+ RDD.PROCESS.R1 = ProcessLayer(name='Resistor 1', symbol='R1')
+ RDD.PROCESS.M1 = ProcessLayer(name='Metal 1', symbol='M1')
+ RDD.PROCESS.C1 = ProcessLayer(name='Contact 1', symbol='C1')
+
+Each process has a name that describes the process function, and
+a *symbol* that is used to identify the process.
+
+Purpose Layer
+-------------
+
+The **purpose** indicates the use of the layer. Multiple layers with
+the same process but different purposes can be created.
+Similar to a process value each purpose contains a name and a unique symbol.
+Purposes are defined using a purpose database object:
+
+.. code-block:: python
+
+ RDD.PURPOSE = PurposeLayerDatabase()
+
+ RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', symbol='METAL')
+ RDD.PURPOSE.VIA = PurposeLayer(name='Contact', symbol='VIA')
+
+Process Parameters
+------------------
+
+Parameters are added to a process by creating a *parameter* database object
+that has a key value equal to the symbol of a pre-defined process:
+
+.. code-block:: python
+
+ RDD.M1 = ParameterDatabase()
+ RDD.M1.MIN_SIZE = 0.7
+ RDD.M1.MAX_WIDTH = 20.0
+ RDD.M1.J5_MIN_SURROUND = 0.5
+ RDD.M1.MIN_SURROUND_OF_I5 = 0.5
+
+Any number of variables can be added to the database using the dot operator.
+The code above defines a set of design parameters for the **M1 process**.
+
+Physical Layers
+---------------
+
+*Physical Layers* are unique to SPiRA and is defined as a layer that has a
+defined process and purpose. A physical layer (PLayer) defines the different
+purposes that a single process can be used for in a layout design.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1 = PhysicalLayerDatabase()
+ RDD.PLAYER.C1 = PhysicalLayerDatabase()
+
+ RDD.PLAYER.C1.VIA = PhysicalLayer(process=RDD.PROCESS.C1, purpose=RDD.PURPOSE.VIA)
+ RDD.PLAYER.M1.METAL = PhysicalLayer(process=RDD.PROCESS.M1, purpose=RDD.PURPOSE.METAL)
+
+The code above illustrates that the layer ``M1`` is a metal layer on process ``M1``,
+and layer ``C1`` is a contact via on process ``C1``.
+
+Virtual Modelling
+~~~~~~~~~~~~~~~~~
+
+*Derived Layers* are used to define different PLayer boolean operations.
+They are typically used for virtual modelling and polygon operations,
+such as merged polygons or polygon holes.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1.EDGE_CONNECTED = RDD.PLAYER.M1.METAL & RDD.PLAYER.M1.OUTSIDE_EDGE_DISABLED
+
+The code above defines a derived layer that is generated when a layer with process ``M1`` and
+purpose ``metal`` overlaps the outside edges of a ``M1`` layer.
+
+
+.. ---------------------------------------------------------------------------------------------------
+
+
+**********
+Parameters
+**********
+
+Designing a generated layout requires modeling its parameters. To create an effective design
+environment it becomes paramount to define parameter restrictions.
+SPiRA uses a meta-configuration to define object parameters, which enables the following features:
+
+* Default values can be set to each parameter.
+* Documentation for each parameter can be added.
+* Parameters can be cached to ensure they aren't calculated multiple times.
+
+Introduction
+============
+
+Parameters are derived from the :py:class:`spira.Parameter` class. The
+:py:class:`ParameterInitializer` is responsible for storing the parameters of an
+instance. To define parameters the class has to inherit from the :py:class:`ParameterInitializer`
+class. The following code creates a layer object with a number parameter.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter()
+
+ >>> layer = Layer(number=9)
+ >>> layer.number
+ 9
+
+At first glance this may not seem to add any value that Python by default does not already adds.
+The same example can be generated using native Python:
+
+.. code-block:: python
+
+ class Layer(object):
+ def __init__(self, number=0):
+ self.number = number
+
+The true value of the parameterized framework becomes clear when adding attributes to the parameter, such as the **default** value, **restrictions**, **preprocess** and **doc**.
+These attributes allow a parameter to be type-checked and documented.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.INTEGER,
+ preprocess=spira.ProcessorInt(),
+ doc='Advanced parameter.')
+
+The newly defined parameter has more advanced features that makes for
+a more powerful design framework:
+
+.. code-block:: python
+
+ # The default value of the parameter is 0.
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+
+ # The parameter can be updated with an integer.
+ >>> layer.number = 9
+ >>> layer.number
+ 9
+
+ # The string can be preprocessed to an interger.
+ >>> layer.number = '8'
+ >>> layer.number
+ 8
+
+ # The string cannot be preprocessed and throws an error.
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+
+Default
+=======
+
+When defining a parameter the default value can be explicitly set using the :py:data:`default` attribute.
+This is a simple method of declaring your parameter.
+For more complex functionality the default function attribute, :py:data:`fdef_name`, can be used.
+This attribute defines the name of a class method that will be used to derive the default value of the parameter.
+Advantages of this implementation is:
+
+* **Logic operations:** The default value can be derived from other defined parameters.
+* **Inheritance:** The default value can be overwritten using class inheritance.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0)
+ datatype = spira.Parameter(fdef_name='create_datatype')
+
+ def create_datatype(self):
+ return 2 + 3
+
+ >>> layer = Layer()
+ >>> (layer.number, layer.datatype)
+ (0, 5)
+
+
+Restrictions
+============
+
+The validity of a parameter value is calculated by the *restriction* attribute.
+In certain cases we want to restrict a parameter value to a certain type or range of values, for example:
+
+* Validate that the value has a specific type, such as a via PCell.
+* Validate that the value falls between a specified minimum and maximum.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, restrictions=spira.RestrictRange(2,5))
+
+The example above restricts the number parameter of the layer to be between 2 and 5:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number = 3
+ 3
+ >>> layer.number = 1
+ ValueError: Invalid parameter assignment 'number' of cell 'Layer' with value '1', which is not compatible with 'Range Restriction: [2, 5)'.
+
+Preprocessors
+=============
+
+The preprocess attribute converts a received value before assigning it to the parameter.
+Preprocessors are typically used to convert a value of invalid type to one of a valid type, such as converting a float to an integer.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, preprocess=spira.ProcessorInt())
+
+ >>> layer = Layer()
+ >>> layer.number = 1
+ 1
+ >>> layer.number = 2.1
+ 2
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+Documentation
+=============
+
+Documentation can be added to the parameter using the :py:data:`doc` attribute.
+The created class can also be documented using triple qoutation marks.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ """ This is a layer class. """
+ number = spira.Parameter(default=0, doc='Parameter documentation.')
+
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+ >>> layer.__doc__
+ This is a layer class.
+ >>> layer.number.__doc__
+ Parameter documentation.
+
+Cache
+=====
+
+SPiRA automatically caches parameters once they have been initialized.
+When using class methods to define default parameters using the :py:data:`fdef_name` attribute, the value is stored when called for the first time.
+Calling this value for the second time will not lead to a re-calculation, but rather the value will be retrieved from the cached dictionary.
+The cache is automatically cleared when **any** parameter in the instance is updated, since other parameters might be dependent on the changed parameters.
+
+.. ---------------------------------------------------------------
+
+*******************
+Parameterized Cells
+*******************
+
+GDSII layouts encapsulate element design in the visual domain.
+Parameterized cells encapsulates elements in the programming domain, and utilizes this domain to map external data to elements.
+This external data can be data from the PDK or values extracted from an already designed layout using simulation software, such as InductEx.
+The SPiRA framework uses a scripting framework approach to connect the visual domain with a programming domain.
+The implemented architecture of SPiRA mimics the physical layout patterns implicit in hand-designed layouts.
+This framework architecture evolved by developing code heuristics that emerged from the process of creating a PCell.
+
+Creating a PCell is done by defining the elements and parameters required to create the desired layout.
+The relationship between the elements and parameters are described in a template format.
+Template design is an innate feature of parameterizing cell layouts.
+This heuristic concludes to develop a framework to effectively describe the different constituents of a PCell, rather than developing an API.
+The SPiRA framework was built from the following concepts:
+
+1. **Defining Element Shapes** This step defines the geometrical shapes from which an element polygon is generated.
+The supported shapes are rectangles, triangles, circles, as well as regular and irregular polygons.
+Each of these shapes has a set of parameters that control the pattern dimensions, e.g. the parameterized rectangle has two parameters, ``width`` and ``length``, that defines its length and width, respectively.
+
+2. **Element Shape Transformations** This step describes the relation between the elements through a set of operations, that includes transformations of a shape in the x-y plane.
+Transforming an element involves: movement with a specific offset relative to its original location, rotation of a shape around its center with a specific angle,
+reflection of a shape around a idefined line, and aligning a shape to another shape with a specific offset and angle.
+
+3. **PDK Binding** The final step is binding data from the PDK to each created pattern. In SPiRA, process related data is defined in the RDD.
+From this database the required data can be linked to any specific pattern by defining parameters and their design restrictions.
+
+Shapes
+======
+
+A shape is a basic 2-dimentional geometric pattern that consists of a list of points.
+These points can be manipulated and transformed as required by the designer, before commiting it to a layout cell.
+
+.. code-block:: python
+
+ class ShapeExample(spira.Cell):
+
+ def create_points(self, points):
+ points = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ return points
+
+You can create your own shape by creating a class that inherits from :py:class:`spira.Shape`.
+The shape coordinates are calculated by the :py:data:`create_points` class method that is innate to any :py:class:`spira.Shape` derived instance.
+The :py:class:`spira.Shape` class offers a rich set of methods for basic and advanced shape manipulation:
+
+.. code-block:: python
+
+ >>> shape = ShapeExample()
+ >>> shape.points
+ [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ >>> shape.area
+ 88
+ >>> shape.move((10, 0))
+ [[10, 0], [12, 2], [12, 6], [4, 6], [4, -6], [6, -4], [6, 4], [10, 4]]
+ >>> shape.x_coords
+ [10 12 12 4 4 6 6 10]
+
+Elements
+========
+
+The purpose of elements are to wrap geometry data with GDSII layout data.
+In SPiRA the following elements are defined:
+
+* **Polygon**: Connects a shape object with layout data (layer number, datatype).
+* **Label**: Generates text data in a GDSII layout.
+* **SRef**: A structure references, or sometimes called a cell reference, refers to another cell object, but with difference transformations.
+
+There are other special objects, called *element groups* that can be used in the design environment.
+These objects are mainly a combination of polygons and relations between polygons.
+These special objects are referenced as if they represent a single shape, and its outline is determined by its bounding box dimensions.
+The following element groups are defined in the SPiRA framework:
+
+* **Cells**: Is the most generic group that binds different parameterized elements or clusters, while conserving the geometrical relations between these polygons or clusters.
+* **Group**: A set of elements can be grouped in a logical container.
+* **Ports**: A port is simply a polygon with a label on a dedicated process layer. Typically, port elements are placed on conducting metal layers.
+* **Routes**: A route is defined as a cell that consists of a polygon element and a set of edge ports, that resembles a path-like structure.
+
+The SPiRA design environment for creating a PCEll is broken down into the following basic templated steps:
+
+.. code-block:: python
+
+ class PCell(spira.Cell):
+ """ My first parameterized cell. """
+
+ # Define parameters here
+ number = spira.IntegerParameter(default=0, doc='Parameter example number.')
+
+ def create_elements(self, elems):
+ # Define elements here.
+ return elems
+
+ def create_ports(self, ports):
+ # Define ports here.
+ return ports
+
+The most basic SPiRA template to generate a PCell is shown above, and consists of three parts:
+
+1. Create a new cell by inheriting from :py:class:`spira.Cell`. This connects the class to the SPiRA framework when constructed.
+2. Define the PCell parameters as class attributes.
+3. Elements and ports are defined in the :py:data:`create_elements` and :py:data:`create_ports` class methods, which is automatically added to the cell instance.
+ The create methods are special SPiRA class methods that specify how the parameters are used to create the cell.
+
+.. code-block:: python
+
+ class PolygonExample(spira.Cell):
+
+ def create_elements(self, elems):
+ pts = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ shape = spira.Shape(points=pts)
+ elems += spira.Polygon(shape=shape, layer=spira.Layer(1))
+ return elems
+
+ >>> D = PolygonExample()
+ >>> D.gdsii_output()
+
+.. image:: _figures/_elements.png
+ :align: center
+
+The code above illustrates the creation of a polygon object, using the already defined shape.
+The polygon object connects the shape to a GDSII library with a GDSII layer number equal to :math:`1`.
+Once the polygon has been created it can be added to the cell instance using the ``+`` operator
+to increment the :py:data:`elems` list.
+
+Group
+=====
+
+Groups are used to apply an operation on a set of polygons, such a retrieving their combined bounding box.
+The following example illistrated the use of :py:class:`spira.Group` to generate a metal bounding box
+around a set of polygons:
+
+.. code-block:: python
+
+ class GroupExample(spira.Cell):
+
+ def create_elements(self, elems):
+
+ group = spira.Group()
+ group += spira.Rectangle(p1=(0,0), p2=(10,10), layer=spira.Layer(1))
+ group += spira.Rectangle(p1=(0,15), p2=(10,30), layer=spira.Layer(1))
+
+ elems += group
+
+ bbox_shape = group.bbox_info.bounding_box(margin=1)
+ elems += spira.Polygon(shape=bbox_shape, layer=spira.Layer(2))
+
+ return elems
+
+.. image:: _figures/_group.png
+ :align: center
+
+A group polygon is created around the two defined polygons with a marginal offset of 1 micrometer.
+
+Ports
+=====
+
+Port objects are unique to the SPiRA framework and are mainly used for connection purposes.
+
+.. code-block:: python
+
+ class Box(spira.Cell):
+
+ width = spira.NumberParameter(default=1)
+ height = spira.NumberParameter(default=1)
+ layer = spira.LayerParameter(default=spira.Layer(1))
+
+ def create_elements(self, elems):
+ shape = shapes.BoxShape(width=self.width, height=self.height)
+ elems += spira.Polygon(shape=shape, layer=self.layer)
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1_M1', midpoint=(-0.5,0), orientation=180, width=1)
+ ports += spira.Port(name='P2_M1', midpoint=(0.5,0), orientation=0, width=1)
+ return ports
+
+.. code-block:: python
+
+ >>> box = Box()
+ [SPiRA: Cell] (name ’Box ’, width 1, height 1, number 0, datatype 0)
+ >>> box.width
+ 1
+ >>> box. height
+ 1
+ >>> box. gds_layer
+ [SPiRA Layer] (name ’’, number 0, datatype 0)
+ >>> box.gdsii_output(name='Ports')
+
+.. image:: _figures/_ports.png
+ :align: center
+
+The above example illustrates constructing a parameterized box using the proposed framework:
+First, defining the parameters that the user would want to change when creating a box instance.
+Here, three parameter are given namely, the :py:data:`width`, the :py:data:`height` and the layer
+properties for GDSII construction. Second, a shape is generated from the defined parameters using the shape module.
+Third, this box shape is added as a polygon element to the cell instance. This polygon takes the shape and connects
+it to a set of methods responsible for converting it to a GDSII element. Fourth, two terminal ports are added to
+the left and right edges of the box, with their directions pointing away from the polygon interior.
+
+Routes
+======
+
+Most of the times in designing digital electronic circuit layouts it is required to define metal polygon connections between different *devices*.
+Defining the exact points connecting different devices can become a tedious task. **Routes** are polygon classes that automatically generates
+a polygon path between different devices. As previously explained, ports are used to define connection points to a cell instance.
+Therefore, routes can be defined as a **polygon** that connects to two **ports** through a path-dependent algorithm.
+SPiRA offers a variety of different route algorithms that can be generated depending on the relative port positions and the user requirements.
+
+.. code-block:: python
+
+ class RouteExample(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=self.ports, layer=spira.Layer(1))
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1', midpoint=(0,0), orientation=180)
+ ports += spira.Port(name='P2', midpoint=(20,10), orientation=0)
+ return ports
+
+.. image:: _figures/_routes.png
+ :align: center
+
+.. --------------------------------------------------------------------------------------
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Validate-by-Design
+.. ******************
+
+
+.. .. --------------------------------------------------------------------------------------
+
+*******
+Filters
+*******
+
+Filters are algorithms whos state can be toggled (enabled or disabled). These algorithms are
+typically used to add or remove extra information to an already working design, hence the name *filter*.
+
+Boolean
+=======
+
+Instead of individually looping through the entire tree hierarchy of a layout to apply
+boolean operations on all polygons, a *boolean filter* can be used to automate this process.
+
+
+Layer
+=====
+
+Sometimes we want to filter certain layers, since they only serve a temporary purpose, or
+because we only want to view layers in the design, for example a specific purpose type.
+In these cases we can use the *layer filter* to automatically filter certain layers in a cell.
+
+
+*******
+Netlist
+*******
+
+The netlist extraction algorithm consists of a chain of filtering methods.
+The basic algorithmic steps is divided into two categories:
+
+1. Extracting a netlist for each individual metal polygon.
+2. Chaining the metal netlists into a single mask netlist.
+
+For each of these steps there is a chain of filter algorithms applied to ensure the correct extraction:
+
+Polygon Netlist
+===============
+
+* Label all nodes in the netlist to the metal layer they represent.
+* Label the nodes that are represetative of detected devices.
+* Label the nodes that represents ERC connections between differenct metal polygons.
+* Calcaulte the cross-over nodes and determine the individual inductive branches.
+
+Mask Netlist
+============
+
+* Combine all metal netlists into a single netlist domain and connect shared nodes.
+* Calculate individual branches between device nodes.
+* Calculate cross-over nodes between different branches.
+* Recalcalate individual branches which includes the detected cross-over nodes.
+* Collapse all nodes belonging to the same branch into a single node representation.
+
+
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Virtual Modeelling
+.. ******************
+
+
+
+.. Derived Edges
+.. =============
+
+
+
+.. --------------------------------------------------------------------------------------
+
+************
+RDD Advanced
+************
+
+The goal of the advanced RDD tutorial is to discuss:
+
+* How to define filters.
+* How to define derived layers.
+* How to create a LVS database.
+
+Filters
+=======
+
+Filters leverages the *chain of responsiblity* design pattern to chain a number of
+algorithms that has to be executed in a sequential order on a specific layout object.
+
+.. code-block:: python
+
+ # First we create a filters database.
+ RDD.FILTERS = ParameterDatabase()
+
+ class PCellFilterDatabase(LazyDatabase):
+ """ Define the filters that will be used when creating a spira.PCell object. """
+
+ def initialize(self):
+ from spira.yevon import filters
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.DEVICE_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+ f += filters.ContactAttachFilter(name='contact_attach')
+
+ f['boolean'] = True
+ f['simplify'] = True
+ f['contact_attach'] = True
+
+ self.DEVICE = f
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.CIRCUIT_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+
+ f['boolean'] = True
+ f['simplify'] = True
+
+ self.CIRCUIT = f
+
+ f = filters.ToggledCompositeFilter(name='mask_filters', filters=[])
+ f += filters.ElectricalAttachFilter(name='erc')
+ f += filters.PinAttachFilter(name='pin_attach')
+ f += filters.DeviceMetalFilter(name='device_metal')
+
+ f['erc'] = True
+ f['pin_attach'] = True
+ f['device_metal'] = False
+
+ self.MASK = f
+
+ RDD.FILTERS.PCELL = PCellFilterDatabase()
+
+The code above shows the creation of three composite filter algorithms:
+
+* The **device filters** will only be applied on detected device cells.
+* The **circuit filters** will only be aplied on non-device cell.
+* The **mask filters** will be executed on the top-level layout cell.
+
+The PCell filter class inherits from the :py:data:`LazyDatabase` class to delay its construction.
+Therefore, the PCell filter database is only instantiated when a specific filter is called using
+the dot operator as shown below:
+
+.. code-block:: python
+
+ f = RDD.FILTERS.PCELL.DEVICE
+
+Derived Layers
+==============
+
+Defining **derived layers** forms the basis of creating the LVS database, since derived layers
+almost by definition defines via connections.
+
+.. code-block:: python
+
+ RDD.VIAS.C5R = ParameterDatabase()
+
+ RDD.VIAS.C5R.LAYER_STACK = {
+ 'BOT_LAYER' : RDD.PLAYER.R5.METAL,
+ 'TOP_LAYER' : RDD.PLAYER.M6.METAL,
+ 'VIA_LAYER' : RDD.PLAYER.C5R.VIA
+ }
+ RDD.PLAYER.C5R.CLAYER_CONTACT = RDD.PLAYER.R5.METAL & RDD.PLAYER.M6.METAL & RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M1 = RDD.PLAYER.R5.METAL ^ RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M2 = RDD.PLAYER.M6.METAL ^ RDD.PLAYER.C5R.VIA
+
+ class C5R_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.via import ViaC5RA, ViaC5RS
+ self.DEFAULT = ViaC5RA
+ self.STANDARD = ViaC5RS
+
+ RDD.VIAS.C5R.PCELLS = C5R_PCELL_Database()
+
+The example above defines a C5R via which connects layer M6 to R5 through a contact layer C5R.
+The logic steps for creating this coding snippet is as follow:
+
+1. A layer stack is created to defined the top, bottom, and via layers.
+2. The derived layers are create that specifies the boolean operations between different layers required in order to detect a via connection. Note, that the :py:data:`RDD.PLAYER.C5R.CLAYER_CONTACT` is the via derived layer that specifies the via connection, while the other two derived layers is used for debugging purposes.
+3. A set of different via PCell classes is added to the database. These classes will be constructed and used during the device detection run.
+
+LVS Database
+============
+
+Defining devices in the LVS database is done similarly to defining vias as already explained:
+
+.. code-block:: python
+
+ RDD.DEVICES = ParameterDatabase()
+
+ RDD.DEVICES.JUNCTION = ParameterDatabase()
+
+ class Junction_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.junction import Junction
+ self.DEFAULT = Junction
+
+ RDD.DEVICES.JUNCTION.PCELLS = Junction_PCELL_Database()
+
+A Josephson junction device is added to the LVS database by importing an already defined
+PCell class and can be constucted using the dot operator:
+
+.. code-block:: python
+
+ # Create a JTL instance from the definition in the RDD LVS database.
+ JtlPCell = RDD.DEVICES.JUNCTION.PCELLS.DEFAULT()
+
+ # View the created instance.
+ JtlPCell.gdsii_view()
+
+
+
+
+
+
diff --git a/docs/_build/html/_sources/_2_basic.rst.txt b/docs/_build/html/_sources/_2_basic.rst.txt
new file mode 100644
index 00000000..f6d61714
--- /dev/null
+++ b/docs/_build/html/_sources/_2_basic.rst.txt
@@ -0,0 +1,797 @@
+##############
+Basic Tutorial
+##############
+
+This tutorial consists of a set of examples that will guide you on how to create a basic PCell,
+manipulate layout elements, and connect process data to your design.
+
+******************
+Parameterized Cell
+******************
+
+First, we have to understand the basic PCell template structure innate to any SPiRA design environment.
+
+Demonstrates
+============
+
+* How to create a parameterized cell by inheriting form :py:class:`spira.PCell`.
+* How to add parameters to the cell.
+* How to validate received parameters.
+
+The first step in any SPiRA design environment is to import the framework:
+
+.. code-block:: python
+
+ import spira.all as spira
+
+The :py:mod:`spira` namespace contains all the important functions and classes provided by the framework.
+In order to create a layout cell all classes has to inherit from :py:class:`spira.PCell`:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+The :py:class:`spira.PCell` class connects the design to the **SPiRA core**. In the exampe above we created
+a parameterized cell of type :py:class:`Resistor` and a basic description given in qoutation marks.
+Now that a layout class has been constructed we need to define a set of *parameters* that will
+describe relations between layout elements.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+We defined two ``float`` restricted parameters, the :py:data:`width` and the :py:data:`length` of the resistor,
+along with documentation (using the :py:data:`doc` attribute) and a default value equal to :math:`0.3` and :math:`1.0`, respectively.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+By definition we want to make sure the length of of the resistor is larger than the width.
+To check the validity of the parameters in relation to eachother, we can use the :py:meth:`validate_parameters` method:
+This method consists of a series of *if-statements* that checks whether the defined parameters are valid or not after instantiation.
+
+.. code-block:: python
+
+ # 1. First create an instance of the resistor class.
+ >>> D = Resistor()
+
+ # 2. You van view the default values of the parameters.
+ >>> (D.width, D.length)
+ (0.3, 1.0)
+
+ # 3. The parameter is successfully updated if it is valid.
+ >>> D.width = 0.5
+ >>> (D.width, D.length)
+ (0.5, 1.0)
+
+ # 4. If an invalid value is received, an error is thrown.
+ >>> D.width = 1.1
+ ValueError: `Width` cannot be larger than `length`.
+
+
+***********************
+Connecting Process Data
+***********************
+
+Now that we have created a basic PCell and understand how to define parameters, we want to
+connect data from the fabrication process to these parameters.
+
+Demonstrates
+============
+
+* How to connect fabrication process data to a design.
+* How to change to a different fabrication process.
+
+The *Rule Deck Database* is a set of Python scripting files that contains all the required fabrication process data,
+and is accessed using the :py:mod:`RDD` module.
+SPiRA contains a default process that can be used directly from the :py:mod:`spira` namespace:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+We updated the parameter default values to equal that of the minimum design restrictions defined
+by the process for the resistor layer :py:data:`R1`.
+After having imported the :py:mod:`spira` namespace the default process database can be changed
+by importing the desired :py:mod:`RDD` object.
+
+.. code-block:: python
+
+ import spira.all as spira
+ from spira.technologies.mit.process.database import RDD
+
+ >>> RDD
+
+
+
+*****************
+Creating Elements
+*****************
+
+Next, we want to create geometric shapes based on the received instance parameters,
+before adding them to the cell instance as element objects.
+
+Demonstrates
+============
+
+* How to add elements to a cell instance.
+* How to create a shape geometry.
+* How to create a GDSII polygon from a shape.
+
+The :py:data:`create_elements` class method is a unique SPiRA method that automatically connects
+a list of elements to the class instance. Methods that starts with ``create_`` are special
+methods in SPiRA and are called *create methods*.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ w, l = self.width, self.length
+ shape = spira.Shape(points=[[0,0], [l,0], [l,w], [0,w]])
+ elems += spira.Polygon(shape=shape, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_3_layout.png
+ :align: center
+
+The defined parameters are used to create a geometeric shape inside the :py:data:`create_elements` method.
+Once the shape is defined it can be added to the layout as a polygon element. The purpose of a polygon
+is to add GDSII-related data to the defined shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+Instead of manually creating shapes SPiRA offers a set of predefined polygons that can be used.
+The code snippet above illustrates the use of the :py:meth:`spira.Box` polygon instead of creating
+a shape object and sending it the polygon container.
+
+
+**************
+Creating Ports
+**************
+
+Similar to the :py:data:`create_elements` method that connects element to your cell instance,
+the :py:data:`create_ports` method adds ports to your design. A port is defined as a vector object
+that is used to connect different layout elements.
+
+Demonstrates
+============
+
+* How to connect ports to your layout.
+* How to name and connect a process type to your port.
+* How to unlock edge specific ports.
+
+Ports are used to connect different layout elements, such as routing different device cells via a metal polygon.
+Therefore, defining the port position, its orientation, and to what process layer is connects are extremely important.
+These are some of the most commonly used port parameters:
+
+* :py:data:`name` The name of the port.
+* :py:data:`midpoint` The position of the port.
+* :py:data:`orientation` The direction of the port.
+* :py:data:`width` The width of the port.
+* :py:data:`process` The process to which the port object connects.
+
+In the example below we first define a box polygon and then add ports to the left and right edges of the shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ w, l = self.width, self.length
+ ports += spira.Port(name='P1_R1', midpoint=(-l/2,0), orientation=180, width=self.width)
+ ports += spira.Port(name='P2', midpoint=(l/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return ports
+
+.. image:: _figures/_4_ports_0_enabled.png
+ :align: center
+
+Port names has to contain one of the following formats:
+
+**Pname_Process**
+ The first letter is defines the **purpose** of the port followed by the port name, typically a number.
+ After the underscore character the **process** symbol is added (as defined in the RDD).
+ This port naming convention is used when no process parameter is added to the object, as shown in the
+ example above with port ``P1_R1``. This process symbol are compared to the defined processes in the
+ RDD and automatically updates the process parameter of the port instance.
+
+*Pname*
+ As shown with ``P2`` the port name does not have to contain the process symbol if a process parameter
+ is manually added to the creation of a port instance.
+
+The most important port purposes for PCell creation are:
+
+* **P** (PinPort): The default port used as a terminal to horizontally connect different elements.
+* **E** (EdgePort): Ports that are automatically generated from the edges of metal polygons.
+* **D** (DummyPort): Typically used to snap a one side of a route object to a specific position.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(alias='ply1', width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ # Process symbol will automatically be added to the port name.
+ ports += self.elements['ply1'].ports['E1_R1'].copy(name='P1')
+ ports += self.elements['ply1'].ports['E3_R1'].copy(name='P2')
+ return ports
+
+Defining the exact midpoint of a port required knowledge of the boundary of the shape we want to connect to.
+SPiRA automatically generates edge ports for metal polygons. The generated box element is given an alias
+that is used to access that specific element. These edges can be activated as ports by simply changing
+the port name. The example above illustrates changing edge port ``E1_R1`` to port ``P1``.
+
+.. image:: _figures/_4_ports_0.png
+ :align: center
+
+The image bove depicts the automatically generated edge ports that can be used for identifying which
+edges to convert to active port. In this example we are converting edges, ``E1_R1`` and ``E3_R1``,
+to ports ``P1_R1`` and ``P2_R1``, respectively. Note, that even though we only added ``P1`` as the port name,
+the process symbol to which the port belongs are automatically added by the SPiRA framework, since the process
+parameter is already set within the edge port. The end result is shown in the figure below:
+
+.. image:: _figures/_4_ports_1.png
+ :align: center
+
+
+***************
+Creating Routes
+***************
+
+Generally metal polygons are used to connect different circuit devices. In this example we first define
+two ports and then generate a metal polygon between them using the :py:class:`spira.Route` base class.
+SPiRA offers a variaty of different routing algorithm depending on the relative position between ports.
+
+Demonstrates
+============
+
+* How to create a route between two different ports.
+* How to externally cache parameters.
+
+First, we define the ports as two separate parameters, :py:data:`p1` and :py:data:`p2`. Second, we use create
+methods to generate port parameters. Doing so allows us to access the ports in both :py:data:`create_elements`
+and :py:data:`create_ports` without re-calculating the ports.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ # Create a straight route between ports p1 and p2.
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+.. image:: _figures/_5_routes_0.png
+ :align: center
+
+It is also possible to define all ports in a single method and externally cache the method using the ``spira.cache``
+decorator as shown in the following example.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ @spira.cache()
+ def get_ports(self):
+ p1 = spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+ p2 = spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return [p1, p2]
+
+ def create_elements(self, elems):
+ p1, p2 = self.get_ports()
+ elems += spira.RouteStraight(p1=p1, p2=p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_ports()
+ return ports
+
+
+**************
+Cell Hierarchy
+**************
+
+As layout designs becomes bigger and more complex with larger circuits, extending an maintaining PCells
+becomes a tedious task. Using basic object-oriented inheritance simplifies the overall structure of our designs.
+
+Demonstrates
+============
+
+* How to create a manhattan route between two ports.
+* How to use inheritance to mimic layout hierarchy.
+* How to extend a layout without changing the parent class.
+* How to pass cells as a parameter to another cell class.
+* How to connect different structures using their ports.
+
+If two ports are not aligned on the same axis, the :py:data:`spira.RouteManhattan` method can be used to
+generate a manhattan polygon between them. One prerequisite is that the absolute port orientation difference
+must equal :math:`180` degrees.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return port
+
+.. image:: _figures/_6_hierarchy_0.png
+ :align: center
+
+The created :py:class:`Resistor` cell can be extended by creating a new cell that inherits from this class.
+To extend the elements we have to add the parent class elements to the current instance. This is done
+using Python's :py:data:`super` method: ``elems = super().create_elements(elems)``. A second route can then
+be generated starting from :py:data:`p2` and ending at :py:data:`p3` with a rounded corner bend.
+
+.. code-block:: python
+
+ # ...
+
+ class ResistorExtended(Resistor):
+
+ p3 = spira.Parameter(fdef_name='create_p3')
+
+ def create_p3(self):
+ return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems = super().create_elements(elems)
+ elems += spira.RouteManhattan(ports=[self.p2, self.p3], corners='round', layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_6_hierarchy_1.png
+ :align: center
+
+Another method to mimic cell hierarchy is to pass a cell to another cell as a parameter:
+
+.. code-block:: python
+
+ class ResistorManhattan(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorStraight(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorConnect(spira.PCell):
+
+ res0 = spira.CellParameter(default=ResistorManhattan)
+ res1 = spira.CellParameter(default=ResistorStraight)
+
+ def create_elements(self, elems):
+ s1 = spira.SRef(reference=self.res0())
+ s2 = spira.SRef(reference=self.res1())
+ s2.connect(port=s2.ports['P1'], destination=s1.ports['P2'])
+ elems += [s1, s2]
+ return elem
+
+We start by creating two resistor classes, :py:class:`ResistorManhattan` and :py:class:`ResistorStraight`,
+then we add them to a single cell instance were we can snap the two structures into place
+by connecting their respective instance ports. An instance for each resistor cell is created
+using :py:class:`spira.SRef` and then :py:data:`P1` of instance :py:class:`ResistorStraight`
+is connect to :py:data:`P2` of instance :py:class:`ResistorManhattan` using the :py:meth:`connect` method.
+
+.. image:: _figures/RouteConnect.*
+ :align: center
+
+
+***************
+Transformations
+***************
+
+Transformations is SPiRA are not directly applied to layout elements. Instead, they are
+abstraction build as a layer on top of the SPiRA core, and are connected to Elements
+as parameters. Doing so enable us to transform elements without losing hierarchical
+data implicit in the layout structure.
+
+Demonstrates
+============
+
+* Understand why transformations are parameterized in SPiRA.
+* How to apply transformations to layout elements.
+* How to keep the hierarchical structure of a flatened layout.
+
+There are multiple different ways to apply a transformation to a layout element:
+
+* The first method creates a transform object and then applies it to an object.
+* The second directly uses a element method to apply the transform.
+
+.. code-block:: python
+
+ class TranslatePolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ """ Apply transformation by first creating a transform object. """
+ T = spira.Translation(Coord(-10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(T)
+ return ply
+
+ def create_t2(self):
+ """ Apply transformation by creating a generic transform.
+ Instead of using the `.ttransform` method, the transform
+ is directly added as a parameter."""
+ tf = spira.GenericTransform(translation=Coord(-22, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=tf)
+ return ply
+
+ def create_t3(self):
+ """ Directly transform the element using the corresponding transform method. """
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((-34, 0))
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+.. image:: _figures/_9_translate.png
+ :align: center
+
+The code snippet above illustrates the different ways to connect a transform to an element.
+The first method in :py:data:`create_t1` is typically used when we want to create a set of
+predefined transforms and later connect them to multiple elements.
+
+The second method in :py:data:`create_t2` is very similar to that of the first, but instead
+manually creates a generic transformation object and connect it to the element as a parameter.
+This method is just shown for illustration purposes and rarely used in practice, since a generic
+transform is automatically created by the framework when multiple transform objects are added.
+
+The thrid method in :py:data:`create_t3` uses the class method to automatically create the
+transform object and emidiately apply the transform to the subject element.
+
+.. code-block:: python
+
+ class TransformPolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ T = spira.Rotation(30) + spira.Translation(Coord(10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(transformation=T)
+ return ply
+
+ def create_t2(self):
+ T = spira.GenericTransform(translation=(20, 0), rotation=60)
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=T)
+ return ply
+
+ def create_t3(self):
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((30, 0))
+ ply.rotate(90)
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+Transformations can be compounded using the plus operator as shown in :py:data:`create_t1`.
+The result is a generic transformation that can be added to any element. A generic transform
+can also be explicitly defined as in :py:data:`create_t2`, or multiple transforms can be
+adding using the corresponding methods as shown in :py:data:`create_t3`.
+
+.. image:: _figures/_9_transform.png
+ :align: center
+
+
+**********
+Stretching
+**********
+
+This tutorial builds from the previous tutorial of transformations.
+Here, we will look at how to stretch a cell reference and specific polygons using ports.
+
+Demonstrates
+============
+
+* How to stretch layout elements.
+* How to use expanded transformations to view flattened ports.
+* How to stretch a specific polygon while maintaining the layout hierarchy.
+
+.. First, we will start by stretching basic flattened layout structures.
+
+In this example we are stretching an entire cell reference by some factor.
+We have created a basic Josephson Junction to demonstrate the stretching of different polygons
+inside the PCell, while maintaining the hierarchical structure.
+
+.. code-block:: python
+
+ class Jj(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Convex(radius=7.0, layer=RDD.PLAYER.C2.VIA)
+ return elems
+
+
+ class ResVia(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Rectangle(p1=(-7.5, -13.2), p2=(7.5, -8.2), layer=RDD.PLAYER.R1.METAL)
+ elems += spira.Rectangle(p1=(-4, -12), p2=(4.1, -10), layer=RDD.PLAYER.C1.VIA)
+ return elems
+
+
+ class Top(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -8))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sj1', reference=Jj(), transformation=t1)
+ elems += spira.SRef(alias='Sr1', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -23), p2=(10, 10), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Bot(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -30))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sr2', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -55), p2=(10, -35), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Junction(spira.Cell):
+ """ Josephson junction. """
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -5))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.Rectangle(p1=(-13, -60), p2=(13, 12), layer=RDD.PLAYER.M1.METAL)
+ elems += spira.SRef(alias='S1', reference=Top(), transformation=t1)
+ elems += spira.SRef(alias='S2', reference=Bot(), transformation=t2)
+ return elems
+
+An instance of the :py:class:`Junction` cell can be created and added as a reference, which
+can be stretched using the :py:meth:`stretch_by_factor` method:
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ C += S.stretch_by_factor(factor=(2,1))
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded flattened view of the junction cell is shown below.
+
+.. image:: _figures/_9_expanded.png
+ :align: center
+
+All polygon elements that coalesces this cell is stretched by a factor of two in the horizontal direction (x-axis).
+
+.. image:: _figures/_9_factor.png
+ :align: center
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ S.stretch_p2p(port_name='S1:Sr1:E3_R1', destination_name='S2:Sr2:E1_R1')
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded view is used to access flattened ports using their hierarchically derived names.
+The port names used in the code above are shown in the expanded view of the cell.
+In this example we want to stretch the two shunt resistor polygons so form a single resistor connection polygon.
+
+.. image:: _figures/_9_ports.png
+ :align: center
+
+
+
+
+
+
diff --git a/docs/_build/html/_sources/_2_tutorials.rst.txt b/docs/_build/html/_sources/_2_tutorials.rst.txt
new file mode 100644
index 00000000..26f5ceac
--- /dev/null
+++ b/docs/_build/html/_sources/_2_tutorials.rst.txt
@@ -0,0 +1,488 @@
+#########
+Tutorials
+#########
+
+
+******************
+Parameterized Cell
+******************
+
+Demonstrates
+============
+
+* How to create a parameterized cell by inheriting form ``spira.PCell``.
+* How to add parameters to the cell.
+* How to validate received parameters.
+
+The first step in any SPiRA design environment is to import the framework:
+
+.. code-block:: python
+
+ import spira.all as spira
+
+The ``spira`` namespace contains all the important functions and classes provided by the framework.
+In order to create a layout cell all classes has to inherit from ``spira.PCell``:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+The ``spira.PCell`` class connects the design to the **SPiRA core**. In the exampe above we created
+a parameterized cell of type ``Resistor`` and a basic description given in qoutation marks.
+Now that a layout class has been constructed we need to define a set of *parameters* that will
+describe how relations between layout elements in this class.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+We defined two parameters the ``width`` and the ``length`` of the resistor, along with a default
+value equal to 0.3 and 1.0, respectively. Each parameter is also documented using the ``doc`` attribute.
+As illistrated in this example the parameters are restricted to the ``float`` type. To check the validity
+of the parameters is relation to eachother, we can use the ``validate_parameters`` method:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+The ``validate_parameters`` consists of a series of *if-statements* that check whether the defined
+parameters are valid or not. Here, by definition we want to make sure the length of of the resistor
+is larger than the width.
+
+.. code-block:: python
+
+ # 1. First create an instance of the resistor class.
+ >>> D = Resistor()
+
+ # 2. You van view the default values of the parameters.
+ >>> (D.width, D.length)
+ (0.3, 1.0)
+
+ # 3. The parameter value is changed if it is valid.
+ >>> D.width = 0.5
+ >>> (D.width, D.length)
+ (0.5, 1.0)
+
+ # 4. Is an invalid value is received, an error is thrown.
+ >>> D.width = 1.1
+ ValueError: `Width` cannot be larger than `length`.
+
+
+***********************
+Connecting Process Data
+***********************
+
+Demonstrates
+============
+
+* How to connect fabrication process data to a design.
+* How to change to a different fabrication process.
+
+The ``RDD`` database is a SPiRA object that contains all the required data of a fabrication process.
+SPiRA contains a default process that can be used directly from the ``spira`` namespace:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+We updated the parameter default values to equal that of the minimum design restrictions defined
+by the process for the resistor layer, ``R1``.
+
+After having imported the ``spira`` namespace the default process database can be changed
+by importing the desired ``RDD`` object.
+
+.. code-block:: python
+
+ import spira.all as spira
+ from spira.technologies.mit.process.database import RDD
+
+ >>> RDD
+
+
+
+*****************
+Creating Elements
+*****************
+
+Demonstrates
+============
+
+* How to add elements to a cell instance.
+* How to create a shape geometry.
+* How to create a GDSII polygon from a shape.
+
+The ``create_elements`` class method is a unique SPiRA method that automatically connects
+a list of elements to the class instance. Methods that starts with ``create_`` are special
+methods in SPiRA and are called *create methods*.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ w, l = self.width, self.length
+ shape = spira.Shape(points=[[0,0], [l,0], [l,w], [0,w]])
+ elems += spira.Polygon(shape=shape, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+The defined parameters are used to create a geometeric shape inside the ``create_elements`` method.
+Once the shape is created it can be added to the layout as a polygon. The purpose of the ``Polygon``
+class is to add GDSII-related data to an abstract geometry.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+Instead of manually creating shapes SPiRA offers a set of predefined polygons that can be used.
+The code snippet above illustrates the use of the ``spira.Box()`` polygon instead of creating
+a shape object and sending it the polygon container.
+
+
+**************
+Creating Ports
+**************
+
+Demonstrates
+============
+
+* How to connect ports to you layout.
+* How to name and connect a process type to your port.
+* How to unlock edge specific ports.
+
+Similar to the ``create_elements`` method that connects element to your cell instance,
+the ``create_ports`` method adds ports to your design. A port is defined as a vector object
+that is used to connect different layout elements.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ w, l = self.width, self.length
+ ports += spira.Port(name='P1_R1', midpoint=(-l/2,0), orientation=180, width=self.width)
+ ports += spira.Port(name='P2', midpoint=(l/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return ports
+
+Port names has to be of the form *PortName_ProcessSymbol* is no process is added to the created object, as shown in
+the example above with port ``P1_R1``. The process symbol set in the name are compared to the defined processes
+in the RDD and automatically adds the process to the port object.
+
+As shown with the ``P2`` the port name does not have to contain the process symbol is a process parameter
+is added. The first letter of the port name defines its type. The 2 most important port types for PCell creation is:
+
+* **P** (PinPort): The default port used as a terminal to horizontally connect different elements.
+* **E** (EdgePort): Ports that are automatically generated from the edges of metal purpose layer polygons.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(alias='ply1', width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ # Process symbol will automatically be added to the port name.
+ ports += self.elements['ply1'].ports['E1_R1'].copy(name='P1')
+ ports += self.elements['ply1'].ports['E3_R1'].copy(name='P2')
+ return ports
+
+Defining the exact midpoint of a port required knowledge of the boundary of the shape we want to connect to.
+SPiRA automatically generates edge ports for metal polygons. The generated box element is given an alias
+that is used to access that specific element. These edges can be activated as ports by simply changing
+the port name. The example above illustrates changing edge port ``E1_R1`` to port ``P1``.
+
+
+******
+Routes
+******
+
+Demonstrates
+============
+
+* How to create a routes between two different ports.
+* How to externally cache parameters.
+
+Generally metal polygons are used to connect different circuit devices. In this example we first define
+two ports and then generate a metal polygon between them using the ``spira.Route`` base class.
+SPiRA offers a variaty of different routing algorithm depending on the relative position between
+the ports. In this example we are generating a simple straight route, since the ports are already
+horizontally aligned.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+First, we define the ports as two separate parameters, ``p1`` and ``p2``. We use create methods to generate to ports
+before adding them to the instance. Doing so allows us to access the port objects from both the ``create_elements``
+method and the ``create_ports`` method.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ @spira.cache()
+ def get_ports(self):
+ p1 = spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+ p2 = spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return [p1, p2]
+
+ def create_elements(self, elems):
+ p1, p2 = self.get_ports()
+ elems += spira.RouteStraight(p1=p1, p2=p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_ports()
+ return ports
+
+It is also possible to define all ports in a single method and externally cache the method using the ``spira.cache``
+decorator as shown in the code snippet above.
+
+
+**************
+Cell Hierarchy
+**************
+
+Demonstrates
+============
+
+* How to create a manhattan route between two ports.
+* How to use inheritance to mimic layout hierarchy.
+* How to extend a layout without changing the parent class.
+* How to pass cells as a parameter to another cell class.
+* How to connect different structures using their ports.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return port
+
+If two ports are not align on a single axis, the ``spira.RouteManhattan`` method can be used to
+generate a manhattan polygon between them. One prerequisite is that the port orientations difference must
+equal 180 degrees.
+
+The created ``Resistor`` cell can be extende by creating a new cell that inherits from this class:
+
+.. code-block:: python
+
+ class ResistorExtended(Resistor):
+
+ p3 = spira.Parameter(fdef_name='create_p3')
+
+ def create_p3(self):
+ return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems = super().create_elements(elems)
+ elems += spira.RouteManhattan(ports=[self.p2, self.p3], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+To extend the elements we have to add the parent class elements to the current instance. This is done
+using Python's ``super`` method: ``elems = super().create_elements(elems)``. A second route can then
+be generated starting from ``p2`` and ending at ``p3``.
+
+Another method to mimic cell hierarchy is to pass a cell to another cell as a parameter:
+
+
+.. code-block:: python
+
+ class ResistorManhattan(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorStraight(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorConnect(spira.PCell):
+
+ res0 = spira.CellParameter(default=ResistorManhattan)
+ res1 = spira.CellParameter(default=ResistorStraight)
+
+ def create_elements(self, elems):
+ s1 = spira.SRef(reference=self.res0())
+ s2 = spira.SRef(reference=self.res1())
+ s2.connect(port=s2.ports['P1'], destination=s1.ports['P2'])
+ elems += [s1, s2]
+ return elem
+
+We start by creating two resistor classes, ``ResistorManhattan`` and ``ResistorStraight``.
+Then, we add them to a single cell instance were we can snap the two structures into place
+by connecting their respective instance ports. A instance for each resistor cell is created
+using ``spira.SRef`` and then ``P1`` of instance ``ResistorStraight`` is connect to ``P2``
+of instance ``ResistorManhattan`` using the ``connect`` method.
+
+
+
+
+
+
+
diff --git a/docs/_build/html/_sources/_3_advanced.rst.txt b/docs/_build/html/_sources/_3_advanced.rst.txt
new file mode 100644
index 00000000..7d33139c
--- /dev/null
+++ b/docs/_build/html/_sources/_3_advanced.rst.txt
@@ -0,0 +1,888 @@
+#################
+Advanced Tutorial
+#################
+
+This set of tutorials focuses on explaining more advanced features that the SPiRA framework
+has to offer. We go into more details on how to create **device** and **circuit** PCells,
+how to structure a design, and how to manipulate layout elements.
+
+In SPiRA PCells can be divided into two categorises, :py:class:`spira.Device` and :py:class:`spira.Circuit`.
+Each of these classes contains a set of different back-end algorithms that are automatically executed when
+the layout class is constructed. Typically, these algorithms consists of boolean operations and filtering algorithms.
+Also, inheriting from these classes defines the purpose of the layout, either a *device* or a *circuit*.
+
+**Devices:**
+
+Similar to creating a PCell, constructing a device cell required inheriting from :py:class:`spira.Device`
+instead of :py:class:`spira.PCell`. In superconducting circuits a device layout is usually a *Via* or a *Junction*.
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+ pass
+
+**Circuits:**
+
+A circuit PCell is designed similar to that of a device. By definition a circuit layout contains polygon
+routes that connects different device and ports instances. Therefore, a :py:class:`spira.Circuit` contains
+two extra, but optional, create methods to simplify the code structure:
+
+* :py:data:`create_structures`: Defines the device instances.
+* :py:data:`create_routes`: Defines the routing paths between different structures and ports.
+
+.. code-block:: python
+
+ class Jtl(spira.Circuit):
+
+ def create_structures(self, elems):
+ return elems
+
+ def create_routes(self, elems):
+ return elems
+
+Note, it is not required to use these methods, but designing large circuits can cause the
+:py:data:`create_elements` method to become cumbersome.
+
+
+*****************
+Library Structure
+*****************
+
+Every design environment connects to a specific fabrication process, also known as the PDK.
+In SPiPA, the PDK data is encapsulated in Python scripts and are collectively called the RDD.
+RDD script names start with ``db_`` as illustrated below.
+
+This section discusses how to organize your design project in SPiRA as a systematized library.
+Technically, your library can have any structure given that you compensates for the necessary
+importing changes. But it is highly adviced to use the proposed structure.
+
+.. code-block:: bash
+
+ technologies
+ |__ mitll
+ |__ devices
+ |__ junction.py
+ |__ vias.py
+ |__ circuits
+ |__ jtl.py
+ |__ dcsfq.py
+ |__ db_init.py
+ |__ db_process.py
+ |__ db_lvs.py
+
+The technology library is broken down into 3 parts:
+
+1. **Devices**: Contains defined device PCells for the specific technology.
+2. **Circuits**: Contains PCell circuits created using the specific technology.
+3. **Database**: Contains a set database files that make up the RDD.
+
+The :py:data:`technologies` folder is the base folder inside the SPiRA design environment that
+contains all the different technology processes and PCell designs in a single place. The library structure
+above contains the ``mitll`` library, which consists of defined junction and via devices, a long
+with a JTL and DCSFQ circuit.
+
+The ``db_init`` script is the first file to be executed when the RDD database is constructed.
+The ``db_process`` script contains most of the information required to design a PCell.
+This file contains the process layers, layer purposes, process parameters, etc.
+The ``db_lvs`` script defines the created device PCells to be used in the device detection
+algorithms when doing LVS extraction.
+
+
+*****
+YTron
+*****
+
+In this example we will start from the beginning. First, we will create a *yTron* shape
+and then using this shape we will create a device containing input/output ports.
+This device will then be used to create a full circuit layout.
+
+Demonstrates
+============
+
+* How to create your own shape class.
+* How to create a device and a circuit PCell.
+* How to restrict a design to only accept a specific shape or device.
+
+We create our own yTron shape by inheriting from :py:class:`spira.Shape`, which allows us
+to manipulate the shape once it has been instantiated.
+
+.. code-block:: python
+
+ class YtronShape(spira.Shape):
+ """ Class for generating a yTron shape. """
+
+ rho = NumberParameter(default=2, doc='Angle of concave bend between the arms.')
+ arm_lengths = CoordParameter(default=(5,3), doc='Length or the left and right arms, respectively.')
+ source_length = NumberParameter(default=5, doc='Length of the source arm.')
+ arm_widths = CoordParameter(default=(2,2), doc='Width of the left and right arms, respectively.')
+ theta = NumberParameter(default=10, doc='Angle of the left and right arms.')
+ theta_resolution = NumberParameter(default=10, doc='Smoothness of the concave bend.')
+
+ xc = Parameter(fdef_name='create_xc')
+ yc = Parameter(fdef_name='create_yc')
+ arm_x_left = Parameter(fdef_name='create_arm_x_left')
+ arm_y_left = Parameter(fdef_name='create_arm_y_left')
+ arm_x_right = Parameter(fdef_name='create_arm_x_right')
+ arm_y_right = Parameter(fdef_name='create_arm_y_right')
+ rad_theta = Parameter(fdef_name='create_rad_theta')
+ ml = Parameter(fdef_name='create_midpoint_left')
+ mr = Parameter(fdef_name='create_midpoint_right')
+ ms = Parameter(fdef_name='create_midpoint_source')
+
+ def create_rad_theta(self):
+ return self.theta * np.pi/180
+
+ def create_xc(self):
+ return self.rho * np.cos(self.rad_theta)
+
+ def create_yc(self):
+ return self.rho * np.sin(self.rad_theta)
+
+ def create_arm_x_left(self):
+ return self.arm_lengths[0] * np.sin(self.rad_theta)
+
+ def create_arm_y_left(self):
+ return self.arm_lengths[0] * np.cos(self.rad_theta)
+
+ def create_arm_x_right(self):
+ return self.arm_lengths[1] * np.sin(self.rad_theta)
+
+ def create_arm_y_right(self):
+ return self.arm_lengths[1] * np.cos(self.rad_theta)
+
+ def create_midpoint_left(self):
+ xc = -(self.xc + self.arm_x_left + self.arm_widths[0]/2)
+ yc = self.yc + self.arm_y_left
+ return [xc, yc]
+
+ def create_midpoint_right(self):
+ xc = self.xc + self.arm_x_right + self.arm_widths[1]/2
+ yc = self.yc + self.arm_y_right
+ return [xc, yc]
+
+ def create_midpoint_source(self):
+ xc = (self.arm_widths[1] - self.arm_widths[0])/2
+ yc = -self.source_length + self.yc
+ return [xc, yc]
+
+ def create_points(self, points):
+
+ theta = self.theta * np.pi/180
+ theta_resolution = self.theta_resolution * np.pi/180
+ theta_norm = int((np.pi-2*theta)/theta_resolution) + 2
+ thetalist = np.linspace(-(np.pi-theta), -theta, theta_norm)
+ semicircle_x = self.rho * np.cos(thetalist)
+ semicircle_y = self.rho * np.sin(thetalist)+self.rho
+
+ xpts = semicircle_x.tolist() + [
+ self.xc + self.arm_x_right,
+ self.xc + self.arm_x_right + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ 0, -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left)
+ ]
+
+ ypts = semicircle_y.tolist() + [
+ self.yc + self.arm_y_right,
+ self.yc + self.arm_y_right,
+ self.yc, self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc, self.yc + self.arm_y_left,
+ self.yc + self.arm_y_left
+ ]
+
+ points = np.array(list(zip(xpts, ypts)))
+
+ return points
+
+There is a few important aspects to note in the :py:class:`YtronShape` class:
+
+1. The :py:data:`create_points` create method is required by the :py:class:`spira.Shape` class and is similar
+ to the :py:class:`create_elements` method for creating a cell.
+2. In this example the importance of the :py:data:`doc` attribute when defining a parameter becomes apparent.
+3. Using create methods to dynamically define the shape parameters makes the shape instance easier to use.
+
+Once we have the desired shape we can use it to create a device cell, containing a GDSii layer and ports instances.
+
+.. code-block:: python
+
+ # ...
+
+ class YtronDevice(spira.Device):
+
+ shape = spira.ShapeParameter(restriction=spira.RestrictType([YtronShape]))
+
+ def create_elements(self, elems):
+ elems += spira.Polygon(shape=self.shape, layer=RDD.PLAYER.M1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+
+ left_arm_width = self.shape.arm_widths[0]
+ rigth_arm_width = self.shape.arm_widths[1]
+ src_arm_width = self.shape.arm_widths[0] + self.shape.arm_widths[1] + 2*self.shape.xc
+
+ ports += spira.Port(name='Pl_M1', midpoint=self.shape.ml, width=left_arm_width, orientation=90)
+ ports += spira.Port(name='Pr_M1', midpoint=self.shape.mr, width=rigth_arm_width, orientation=90)
+ ports += spira.Port(name='Psrc_M1', midpoint=self.shape.ms, width=src_arm_width, orientation=270)
+
+ return ports
+
+ >>> shape = YtronShape(theta_resolution=100)
+ >>> D = YtronDevice(shape=shape)
+ >>> D.gdsii_output()
+
+.. image:: _figures/_adv_0_ytron.png
+ :align: center
+
+The :py:data:`shape` parameter defined in the :py:class:`YtronDevice` class restricts the instance to only receive
+a shape of type :py:class:`YtronShape`. Using the shape parameters the port instances for each arms
+can be defined and added to the PCell instance. The created yTron device can now be used in a circuit:
+
+.. code-block:: python
+
+ class YtronCircuit(spira.Circuit):
+
+ ytron = spira.Parameter(fdef_name='create_ytron', doc='Places an instance of the ytron device.')
+
+ @spira.cache()
+ def get_io_ports(self):
+ p1 = spira.Port(name='P1_M1', midpoint=(-10,10), orientation=0)
+ p2 = spira.Port(name='P2_M1', midpoint=(5,10), width=0.5, orientation=270)
+ p3 = spira.Port(name='P3_M1', midpoint=(0,-10), width=1, orientation=90)
+ return [p1, p2, p3]
+
+ def create_ytron(self):
+ shape = YtronShape(rho=0.5, theta=5)
+ D = YtronDevice(shape=shape)
+ return spira.SRef(alias='ytron', reference=D)
+
+ def create_elements(self, elems):
+ p1, p2, p3 = self.get_io_ports()
+
+ elems += self.ytron
+
+ elems += spira.RouteManhattan(
+ ports=[self.ytron.ports['Pl_M1'], p1],
+ width=self.ytron.ref.shape.arm_widths[0],
+ layer=RDD.PLAYER.M1.METAL,
+ corners=self.corners)
+
+ elems += spira.RouteStraight(p1=p2,
+ p2=self.ytron.ports['Pr_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ elems += spira.RouteStraight(p1=p3,
+ p2=self.ytron.ports['Psrc_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_io_ports()
+ return ports
+
+The figure below shows the output of the yTron PCell if the class was constructed inheriting from
+:py:class:`spira.PCell`. The metal layers are separated and the connection ports are still visible.
+
+.. image:: _figures/_adv_0_ytron_pcell.png
+ :align: center
+
+The following figure is the final result when inheriting from :py:class:`spira.Circuit`
+rather than :py:class:`spira.PCell`. The contacting metal layers are merged and the redundant ports are filtered.
+
+.. image:: _figures/_adv_0_ytron_circuit.png
+ :align: center
+
+From the code above we can see that three routes are defined.
+The first, connects the left arm with the first port using a basic manhattan structure.
+The second and third, connects the right arm to the second port and the source arm to the third port,
+but uses a ``sine`` path type to generate the routing polygons.
+
+
+**********
+Via Device
+**********
+
+Via devices generally following the same design patterns, but still require explicit construction
+to describe how PDK data should be handled on instance creation. This example illustrated the
+creation of the *alternative resistor via contact* that is responsible to connecting resistive
+layer ``R5`` to inductive layer ``M6``.
+
+Demonstrates
+============
+
+* How to create a via device.
+* How to add range restrictions to parameters.
+* How to create a cell that validates design rules on instance creation.
+
+Recall, that by definition a PCell script is responsible for describing the interrelations between
+layout elements and defined parameters. These parameters can be design restrictions imposed by the
+specific fabrication technology.
+
+.. code-block:: python
+
+ class ViaC5RA(spira.Device):
+ """ Via component for the MiTLL process. """
+
+ width = spira.NumberParameter(default=RDD.R5.MIN_SIZE, restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE))
+
+ height = spira.Parameter(fdef_name='create_height')
+ via_width = spira.Parameter(fdef_name='create_via_width')
+ via_height = spira.Parameter(fdef_name='create_via_height')
+
+ m6_width = spira.Parameter(fdef_name='create_m6_width', doc='Width of the via layer polygon.')
+ m6_height = spira.Parameter(fdef_name='create_m6_height', doc='Width of the via layer polygon.')
+
+ def create_m6_width(self):
+ return (self.via_width + 2*RDD.C5R.M6_MIN_SURROUND)
+
+ def create_via_width(self):
+ return (self.width + 2*RDD.C5R.R5_MAX_SIDE_SURROUND)
+
+ def create_via_height(self):
+ return RDD.C5R.MIN_SIZE
+
+ def create_height(self):
+ return self.via_height + 2*RDD.R5.C5R_MIN_SURROUND
+
+ def create_elements(self, elems):
+ elems += spira.Box(layer=RDD.PLAYER.C5R.VIA, width=self.via_width, height=self.via_height, enable_edges=False)
+ elems += spira.Box(alias='M6', layer=RDD.PLAYER.M6.METAL, width=self.m6_width, height=self.height, enable_edges=False)
+ elems += spira.Box(alias='R5', layer=RDD.PLAYER.R5.METAL, width=self.width, height=self.height, enable_edges=False)
+ return elems
+
+ def create_ports(self, ports):
+ p0 = self.elements['M6'].ports.unlock
+ p1 = self.elements['R5'].ports.unlock
+ return ports
+
+Thus, the code for the via PCell defined above is responsible for describing how the top and bottom metal layers
+must be constructed in relation to the contact layer without violating any design rules. The PCell defines the specific
+design rules applicable to the creation of this via device.
+
+
+********
+Resistor
+********
+
+In Single Flux Quantum (SFQ) logic circuits, we typically use a shunt resistance for the biasing section
+of the circuit. Therefore, we would want to create a single resistor PCell that can be used as a template
+in more complex circuit PCells. Here, we design a resistor that parameterized its width, length, and
+type of via connection to other metal layers.
+
+Demonstrates
+============
+
+* How to design a circuit that can interchange different via devices.
+* How to restrict the circuit to only accept vias of a certain type.
+* How to activate specific port edges that can be used for external connetions.
+
+This PCell can iterate between two different vias connections that connect metal layer ``R5`` and ``M6``;
+the *alternative* version of the *standard* version.
+
+.. code-block:: python
+
+ class Resistor(spira.Circuit):
+ """ Resistor PCell of type Circuit between two vias connecting to layer M6. """
+
+ length = spira.NumberParameter(default=7)
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE),
+ doc='Width of the shunt resistance.')
+ via = spira.CellParameter(
+ default=dev.ViaC5RS,
+ restriction=spira.RestrictType([dev.ViaC5RA, dev.ViaC5RS]),
+ doc='Via component for connecting R5 to M6')
+ text_type = spira.NumberParameter(default=92)
+
+ via_left = spira.Parameter(fdef_name='create_via_left')
+ via_right = spira.Parameter(fdef_name='create_via_right')
+
+ def validate_parameters(self):
+ if self.length < self.width:
+ raise ValueError('Length cannot be less than width.')
+ return True
+
+ def create_via_left(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90)
+ S = spira.SRef(via, transformation=T)
+ return S
+
+ def create_via_right(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90, rotation_center=(self.length, 0))
+ S = spira.SRef(via, midpoint=(self.length, 0), transformation=T)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += [self.via_left, self.via_right]
+
+ elems += RouteStraight(
+ p1=self.via_left.ports['E0_R5'],
+ p2=self.via_right.ports['E2_R5'],
+ layer=RDD.PLAYER.R5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+
+ ports += self.via_left.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.via_left.ports['E2_M6'].copy(name='P2_M6')
+ ports += self.via_left.ports['E3_M6'].copy(name='P3_M6')
+
+ ports += self.via_right.ports['E0_M6'].copy(name='P4_M6')
+ ports += self.via_right.ports['E1_M6'].copy(name='P5_M6')
+ ports += self.via_right.ports['E3_M6'].copy(name='P6_M6')
+
+ return ports
+
+The :py:data:`length` parameter can be any value as long as it is larger than the width. Therefore, the
+length parameter has no restrictions, but are validated once all parameters have been defined using the
+:py:data:`validate_parameters` method. The :py:data:`width` parameter is restricted to a minimum size,
+which implicitly mean the length is also restricted to this size value. The :py:data:`via` parameter
+has to be a PCell class and has to be of type :py:class:`dev.ViaC5RA` or :py:class:`dev.ViaC5RS`.
+
+We only want to connect to the connection vias of the instance, and therefore we only activate the ports
+of the two via instance, instead of activating all possible edge ports, as shown in the :py:data:`create_ports` method.
+
+******************
+Josephson Junction
+******************
+
+The Josephson junction is the most important device in any SDE circuit. We want to create a junction PCell
+that parameterizes the following device attributes:
+
+* The shunt resistor width.
+* The shunt resistor length.
+* The junction layer radius.
+* Boolean parameters to include/exclude via connections to ground and skyplane.
+
+Demonstrates
+============
+
+* How to design a fully parameterized Josephson junction.
+* How to add a bounding box around a set of polygon objects.
+
+The design of the junction is broken down into three sections; a top section, a bottom section, and the shunt
+resistor that connects the top and bottom sections. The top and bottom section each are wrapped with a
+bounding box polygon of metal layer ``M6``.
+
+.. code-block:: python
+
+ class __Junction__(spira.Cell):
+ """ Base class for Junction PCell. """
+
+ radius = spira.NumberParameter()
+ width = spira.NumberParameter(doc='Shunt resistance width')
+ c5r = spira.Parameter(fdef_name='create_c5r')
+
+
+ class I5Contacts(__Junction__):
+ """ Cell that contains all the vias of the bottom halve of the Junction. """
+
+ i5 = spira.Parameter(fdef_name='create_i5')
+ i6 = spira.Parameter(fdef_name='create_i6')
+
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5(self):
+ via = dev.ViaI5()
+ V = spira.SRef(via, midpoint=(0,0))
+ return V
+
+ def create_i6(self):
+ c = self.i5.midpoint
+ w = (self.i5.ref.width + 4*RDD.I6.I5_MIN_SURROUND)
+ via = dev.ViaI6(width=w, height=w)
+ V = spira.SRef(via, midpoint=c)
+ return V
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ if self.sky_via is True:
+ V.connect(port=V.ports['E0_R5'], destination=self.i6.ports['E2_M6'], ignore_process=True)
+ else:
+ V.connect(port=V.ports['E0_R5'], destination=self.i5.ports['E2_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.i5, self.c5r]
+
+ # Add the skyplane via instance if required.
+ if self.sky_via is True:
+ elems += self.i6
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.i5.ports['E2_M5'].copy(name='P2_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+
+ class J5Contacts(__Junction__):
+ """ Cell that contains all the vias of the top halve of the Junction. """
+
+ j5 = spira.Parameter(fdef_name='create_j5')
+
+ def create_j5(self):
+ jj = dev.JJ(width=2*self.radius)
+ D = spira.SRef(jj, midpoint=(0,0))
+ return D
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ V.connect(port=V.ports['E0_R5'], destination=self.j5.ports['E0_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.j5, self.c5r]
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M5'].copy(name='P0_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+The :py:class:`J5Contacts` and :py:class:`I5Contacts` classes are the top and bottom sections, respectively.
+The :py:class:`__Junction__` class is a base class that contains parameters common to both of these classes.
+As shown in the :py:data:`create_elements` methods for both classes a metal bounding box is added around
+all defined elements.
+
+The results for :py:class:`J5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a junction via that contains the actually junction layer.
+
+.. image:: _figures/_adv_junction_top.png
+ :align: center
+
+The result for :py:class:`I5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a ``I5`` via that connects layer ``M5`` to layer ``M6``. The skyplane via that connects
+``M6`` to ``M7`` is optional depending on the boolean value of the :py:data:`sky_via` parameter.
+
+.. image:: _figures/_adv_junction_bot.png
+ :align: center
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+
+ text_type = spira.NumberParameter(default=91)
+
+ length = spira.NumberParameter(default=1.5, doc='Length of the shunt resistance.')
+
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE, upper=RDD.R5.MAX_WIDTH),
+ doc='Width of the shunt resistance.')
+
+ radius = spira.NumberParameter(
+ default=RDD.J5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.J5.MIN_SIZE, upper=RDD.J5.MAX_SIZE),
+ doc='Radius of the circular junction layer.')
+
+ i5 = spira.Parameter(fdef_name='create_i5_cell')
+ j5 = spira.Parameter(fdef_name='create_j5_cell')
+
+ gnd_via = spira.BoolParameter(default=False)
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5_cell(self):
+ D = I5Contacts(width=self.width, radius=self.radius, sky_via=self.sky_via)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0, self.length))
+ return S
+
+ def create_j5_cell(self):
+ D = J5Contacts(width=self.width, radius=self.radius)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0,0))
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.i5
+ elems += self.j5
+
+ elems += RouteStraight(
+ p1=self.i5.ports['P2_R5'].copy(width=self.width),
+ p2=self.j5.ports['P2_R5'].copy(width=self.width),
+ layer=RDD.PLAYER.R5.METAL)
+
+ if self.gnd_via is True:
+ i4 = dev.ViaI4()
+ elems += spira.SRef(i4, midpoint=m5_block.center)
+
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M6'].copy(name='P0_M6')
+ ports += self.j5.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.j5.ports['E3_M6'].copy(name='P3_M6')
+ ports += self.i5.ports['E1_M6'].copy(name='P4_M6')
+ ports += self.i5.ports['E2_M6'].copy(name='P5_M6')
+ ports += self.i5.ports['E3_M6'].copy(name='P6_M6')
+ return ports
+
+The :py:class:`Junction` class is created and instances of the :py:class:`J5Contacts` and :py:class:`I5Contacts`
+cells are added and moved relative to eachother with a separation distance equal to the length of the shunt resistor.
+The instances of of these two cells are then connection via a resistive route. For debugging purposes we can disable
+the operations preformed by the :py:class:`spira.Device` class by setting ``pcell=False``. The output is shown below
+displays the individual layers of each instance.
+
+.. image:: _figures/_adv_junction_false.png
+ :align: center
+
+By enabling PCell operations again we can see that the overlapping metal layers are merged by similar process
+polygon, as shown in the figure below.
+
+.. image:: _figures/_adv_junction_true.png
+ :align: center
+
+
+
+***************************
+Josephson Transmission Line
+***************************
+
+The Josephson Transmission Line (JTL) is the most basic SFQ circuit and consist of two junctions, an
+input and output port, and a biasing port.
+
+Demonstrates
+============
+
+* How to define routes between different ports and devices.
+* How to parameterize the route widths.
+* How to include a device PCell into higher hierarchical designs.
+
+We define three width parameters to control the polygon routing width between:
+
+1. The input port and first junction.
+2. The ouput port and second junction.
+3. The first junction and second junction.
+
+Next, we create a set of *create methods* to define device and port instances.
+
+.. code-block:: python
+
+ class Jtl(spira.PCell):
+
+ w1 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of left inductor.'
+ )
+ w2 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of middle inductor.'
+ )
+ w3 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of rigth inductor.'
+ )
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+ p3 = spira.Parameter(fdef_name='create_p3')
+ p4 = spira.Parameter(fdef_name='create_p4')
+
+ jj1 = spira.Parameter(fdef_name='create_jj_left')
+ jj2 = spira.Parameter(fdef_name='create_jj_right')
+
+ shunt = spira.Parameter(fdef_name='create_shunt')
+
+ bias_res = spira.Parameter(fdef_name='create_bias_res')
+ via1 = spira.Parameter(fdef_name='create_via1')
+
+ def create_p1(self):
+ p1 = spira.Port(name='P1_M6', width=self.w1)
+ return p1.distance_alignment(port=p1, destination=self.jj1.ports['P1_M6'], distance=-10)
+
+ def create_p2(self):
+ p2 = spira.Port(name='P2_M6', width=self.w1)
+ return p2.distance_alignment(port=p2, destination=self.jj2.ports['P3_M6'], distance=10)
+
+ def create_p3(self):
+ return spira.Port(name='P3_M6', midpoint=(0, 15), orientation=270, width=self.w1)
+
+ def create_p4(self):
+ return spira.Port(name='P4_M6', midpoint=(0, 1.5), orientation=90, width=self.w1)
+
+ def create_jj_left(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(-10,0))
+ S = spira.SRef(jj, midpoint=(-10,0), transformation=T)
+ return S
+
+ def create_jj_right(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(10,0))
+ S = spira.SRef(jj, midpoint=(10,0), transformation=T)
+ return S
+
+ def create_shunt(self):
+ D = Resistor(width=1, length=3.7)
+ S = spira.SRef(reference=D, midpoint=(0,0))
+ S.distance_alignment(port='P2_M6', destination=self.p3, distance=-2.5)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.jj1
+ elems += self.jj2
+ elems += self.shunt
+
+ elems += RouteStraight(p1=self.p1,
+ p2=self.jj1.ports['P1_M6'].copy(width=self.p1.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.p2,
+ p2=self.jj2.ports['P3_M6'].copy(width=self.p2.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(
+ p1=self.jj1.ports['P3_M6'].copy(width=self.w2),
+ p2=self.jj2.ports['P1_M6'].copy(width=self.w2),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.shunt.ports['P2_M6'], p2=self.p3, layer=RDD.PLAYER.M6.ROUTE)
+ elems += RouteStraight(p1=self.shunt.ports['P4_M6'], p2=self.p4, layer=RDD.PLAYER.M6.ROUTE)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.p1
+ ports += self.p2
+ ports += self.p3
+ ports += self.p4
+ return ports
+
+This examples place two junctions, :py:data:`jj_left` and :py:data:`jj_right`, at positions (-10,0) and
+(10,0). The input port is placed a ditance of -10 to the left of :py:data:`jj_left`, and the ouput port
+a distance of 10 to the right of :py:data:`jj_right`.
+
+The biasing port, :py:data:`p3` is place at position (0,15) and port ``P2_M6`` of the biasing resistor PCell
+is place a distance of 2.5 to the bottom of :py:data:`p3`.
+
+.. image:: _figures/_adv_jtl_false.png
+ :align: center
+
+
+************************
+Electrical Rule Checking
+************************
+
+The electrical rule checking algorithm is applied on an instance using a filtering method.
+Therefore, it is easily enabled/disabled for debugging purposes.
+
+Demonstrates
+============
+
+* How to toggle the ERC algorithm.
+* How to view the electrical rule checking results using **virtual modeling**.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ f = RDD.FILTERS.PCELL.MASK
+
+ D = f(D)
+
+ from spira.yevon.vmodel.virtual import virtual_connect
+ v_model = virtual_connect(device=D)
+
+ v_model.view_virtual_connect(show_layers=True)
+
+.. image:: _figures/_adv_jtl_erc.png
+ :align: center
+
+The resultant layout or view of a cicuit that contains *virtual elements* that will not be included in the final design, is called a **virtual model**.
+The above example illustrates how electrical rule checking can be debugged using virtually constructed polygons.
+
+
+******************
+Netlist Extraction
+******************
+
+Netlists for PCells can be extracted and viewed in a graph representation.
+
+Demonstrates
+============
+
+* How to extract the netlist graph of a PCell.
+* How to view the extracted graph.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ D = RDD.FILTERS.PCELL.MASK(D)
+
+ # Extract the physical netlist.
+ net = D.extract_netlist
+
+ # View the netlist.
+ D.netlist_view(net=net)
+
+Before running the netlist extraction algorithm it is important to first apply the required filters to the pcell instance.
+These filters includes running electrical rule checking algorithm and compressing terminal ports down onto their corresponding polygon instances.
+It is also possible to toggle certain filters for debugging purposes:
+
+.. code-block:: python
+
+ D = Jtl()
+
+ f = RDD.FILTERS.PCELL.MASK
+
+ f['pin_attach'] = False
+
+ D = f(D)
+
+ net = D.extract_netlist
+
+ D.netlist_view(net=net)
+
+The above example illustrates the extracted netlist if the **pin attach** algorithm is disabled.
+The added terminal ports are not detected by the netlist run, since they are not compressed down the layout hierarchy onto their corresponding polygons.
+The following image shows the different extracted netlists for a basic JTL layout using the code snippets previously discussed.
+
+.. image:: _figures/_adv_jtl_net.png
+ :align: center
+
+
diff --git a/docs/_build/html/_sources/_3_reference.rst.txt b/docs/_build/html/_sources/_3_reference.rst.txt
new file mode 100644
index 00000000..a47c1b39
--- /dev/null
+++ b/docs/_build/html/_sources/_3_reference.rst.txt
@@ -0,0 +1,5 @@
+#########
+Reference
+#########
+
+
diff --git a/docs/_build/html/_sources/_4_reference.rst.txt b/docs/_build/html/_sources/_4_reference.rst.txt
new file mode 100644
index 00000000..a47c1b39
--- /dev/null
+++ b/docs/_build/html/_sources/_4_reference.rst.txt
@@ -0,0 +1,5 @@
+#########
+Reference
+#########
+
+
diff --git a/docs/_build/html/_sources/_5_developers.rst.txt b/docs/_build/html/_sources/_5_developers.rst.txt
new file mode 100644
index 00000000..1e3a224c
--- /dev/null
+++ b/docs/_build/html/_sources/_5_developers.rst.txt
@@ -0,0 +1,69 @@
+Developers
+==========
+
+Documentation for developers for maintaining and extending.
+
+Distribtuion
+------------
+
+Uploading package to PyPi using *twine*.
+Remember to remove all Eggs before doing a push to PyPi.
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 setup.py bdist_wheel
+ twine upload dist/*
+
+To install package systemwide set the prefix value when running setuptools:
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 setup.py install --prefix=/usr
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 -m pip install --upgrade .
+
+* https://docs.python.org/3.3/install/index.html
+
+Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
+
+Documentation
+-------------
+
+If you want to generate the docs make sure the Napoleon package is installed:
+
+.. code-block:: bash
+ :linenos:
+
+ pip install sphinxcontrib-napoleon
+
+Coding standards for parsing the correct docs is given in:
+
+* https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
+
+* https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+Introduction to Python Virtual Enviroments:
+
+* https://realpython.com/python-virtual-environments-a-primer/
+* https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
+
+.. ---------------------------------------------------------------------------------------------
+
+Mixins
+------
+
+The following are useful links to some of the mixin implementations used in the SPiRA framework,
+
+* http://tobyho.com/2009/01/18/auto-mixin-in-python/
+* http://code.activestate.com/recipes/577730-mixin-and-overlay/
+* https://stackoverflow.com/questions/6966772/using-the-call-
+* method-of-a-metaclass-instead-of-new
+
+
+
+
diff --git a/docs/_build/html/_sources/developers.rst.txt b/docs/_build/html/_sources/developers.rst.txt
index 76837c85..6ee0e8a8 100644
--- a/docs/_build/html/_sources/developers.rst.txt
+++ b/docs/_build/html/_sources/developers.rst.txt
@@ -4,69 +4,69 @@ Developers
Documentation for developers for maintaining and extending. Extra information is added
to better understand specific code implementations.
-Distribtuion
-------------
+.. Distribtuion
+.. ------------
-Uploading package to PyPi using *twine*.
-Remember to remove all Eggs before doing a push to PyPi.
+.. Uploading package to PyPi using *twine*.
+.. Remember to remove all Eggs before doing a push to PyPi.
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 setup.py bdist_wheel
- twine upload dist/*
+.. sudo python3 setup.py bdist_wheel
+.. twine upload dist/*
-To install package systemwide set the prefix value when running setuptools:
+.. To install package systemwide set the prefix value when running setuptools:
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 setup.py install --prefix=/usr
+.. sudo python3 setup.py install --prefix=/usr
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 -m pip install --upgrade .
+.. sudo python3 -m pip install --upgrade .
-* https://docs.python.org/3.3/install/index.html
+.. * https://docs.python.org/3.3/install/index.html
-Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
+.. Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
-Documentation
--------------
+.. Documentation
+.. -------------
-If you want to generate the docs make sure the Napoleon package is installed:
+.. If you want to generate the docs make sure the Napoleon package is installed:
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- pip install sphinxcontrib-napoleon
+.. pip install sphinxcontrib-napoleon
-Coding standards for parsing the correct docs is given in:
+.. Coding standards for parsing the correct docs is given in:
-* https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
+.. * https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
-* https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+.. * https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
-Introduction to Python Virtual Enviroments:
+.. Introduction to Python Virtual Enviroments:
-* https://realpython.com/python-virtual-environments-a-primer/
-* https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
+.. * https://realpython.com/python-virtual-environments-a-primer/
+.. * https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
-.. ---------------------------------------------------------------------------------------------
+.. .. ---------------------------------------------------------------------------------------------
-Mixins
-------
+.. Mixins
+.. ------
-The following are useful links to some of the mixin implementations used in the SPiRA framework,
+.. The following are useful links to some of the mixin implementations used in the SPiRA framework,
-* http://tobyho.com/2009/01/18/auto-mixin-in-python/
-* http://code.activestate.com/recipes/577730-mixin-and-overlay/
-* https://stackoverflow.com/questions/6966772/using-the-call-
-* method-of-a-metaclass-instead-of-new
+.. * http://tobyho.com/2009/01/18/auto-mixin-in-python/
+.. * http://code.activestate.com/recipes/577730-mixin-and-overlay/
+.. * https://stackoverflow.com/questions/6966772/using-the-call-
+.. * method-of-a-metaclass-instead-of-new
-Metaprogramming
----------------
+.. Metaprogramming
+.. ---------------
diff --git a/docs/_build/html/_sources/framework.rst.txt b/docs/_build/html/_sources/framework.rst.txt
new file mode 100644
index 00000000..5219fea2
--- /dev/null
+++ b/docs/_build/html/_sources/framework.rst.txt
@@ -0,0 +1,491 @@
+#########
+Framework
+#########
+
+
+
+******************
+Process Design Kit
+******************
+
+The process design kit (PDK) is a set of technology files needed to implement
+the physical aspects of a layout design. Application-specific rules specified
+in the PDK controls how physical design applications work.
+
+A new PDK scheme is introduced. The Python programming language is used to
+bind PDK data to a set of classes, called data trees, that uniquely categorises
+PDK data. This new PDK scheme is called the Rule Deck Database (RDD), also
+refered to as the Rule Design Database. By having a native PDK in Python it
+becomes possible to use methods from the SPiRA framework to create a
+more descriptive PDK database. A design process typically contains the
+following aspects:
+
+* *GDSII Data*: Contains general settings required by the GDSII library, such as grid size.
+* *Process Data*: Contains the process layers, layer purposes, layer parameters, and layer mappings.
+* *Virtual Modelling*: Define derived layers that describes layer boolean operations.
+
+
+Initialization
+==============
+
+All caps are used to represent the *RDD* syntax. The reason being to make the
+script structure clearly distinguishable from the rest of the framework source
+code. First, the RDD object is initialized, followed by the process name and
+description. Second, the GDSII related variables are defined.
+
+.. code-block:: python
+
+ RDD.GDSII = ParameterDatabase()
+ RDD.GDSII.UNIT = 1e-6
+ RDD.GDSII.GRID = 1e-12
+ RDD.GDSII.PRECISION = 1e-9
+
+
+Process Data
+============
+
+.. ---------- Define Processes ----------
+
+Define Processes
+----------------
+
+The first step in creating a layer is to define the process step that
+it represents in mask fabrication. The layer process defines a specific
+fabrciation function, for examples **metalization**. There can be multiple
+different drawing layers for a single process. A *Process* database object
+is created that contains all the different process steps in a specific
+fabrication process:
+
+.. code-block:: python
+
+ RDD.PROCESS = ProcessLayerDatabase()
+
+ RDD.PROCESS.GND = ProcessLayer(name='Ground Plane', symbol='GND')
+ RDD.PROCESS.SKY = ProcessLayer(name='Sky Plane', symbol='SKY')
+ RDD.PROCESS.R5 = ProcessLayer(name='Resistor 1', symbol='R5')
+ RDD.PROCESS.M1 = ProcessLayer(name='Metal 1', symbol='M1')
+
+Each process has a name that describes the process function, and
+a *symbol* that is used to identify the process.
+
+.. ---------- Define Purposes ----------
+
+The purpose indicates the use of the layer. Multiple layers with
+the same process but different purposes can be created. Purposes are defined
+using a *Purpose* database object:
+
+.. code-block:: python
+
+ RDD.PURPOSE = PurposeLayerDatabase()
+
+ RDD.PURPOSE.GROUND = PurposeLayer(name='Ground plane polygons', symbol='GND')
+ RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', symbol='METAL')
+ RDD.PURPOSE.ROUTE = PurposeLayer(name='Metal routes', symbol='ROUTE')
+ RDD.PURPOSE.RESISTOR = PurposeLayer(name='Polygon resistor', symbol='RES')
+
+Similar to a **process** value each purpose contains a name and a unique symbol.
+
+.. ---------- Process Parameters ----------
+
+Parameters are added to a process by creating a *parameter* database object
+that has a key value equal to the symbol of a pre-defined process:
+
+.. code-block:: python
+
+ RDD.M5 = ParameterDatabase()
+ RDD.M5.MIN_SIZE = 0.7
+ RDD.M5.MAX_WIDTH = 20.0
+ RDD.M5.J5_MIN_SURROUND = 0.5
+ RDD.M5.MIN_SURROUND_OF_I5 = 0.5
+
+Any number of variables can be added to the tree using the dot operator.
+The code above defines a set of design parameters for the *M5* process.
+
+.. ---------- Physical Layers ----------
+
+*Physical Layers* are unique to SPiRA and is defined as a layer that has a
+defined process and purpose. A physical layer (PLayer) defines the different
+purposes that a single process can be used for in a layout design.
+
+.. code-block:: python
+
+ RDD.PLAYER.M6 = PhysicalLayerDatabase()
+
+ RDD.PLAYER.I5.VIA = PhysicalLayer(process=RDD.PROCESS.I5, purpose=RDD.PURPOSE.VIA)
+
+ RDD.PLAYER.M6.METAL = PhysicalLayer(process=RDD.PROCESS.M6, purpose=RDD.PURPOSE.METAL)
+ RDD.PLAYER.M6.HOLE = PhysicalLayer(process=RDD.PROCESS.M6, purpose=RDD.PURPOSE.HOLE)
+
+The code above illustrated the different purposes that process layer
+**M6** can have in a layout design.
+
+Virtual Modelling
+~~~~~~~~~~~~~~~~~
+
+*Derived Layers* are used to define different PLayer boolean operations.
+They are typically used for virtual modelling and polygon operations,
+such as merged polygons or polygon holes.
+
+.. code-block:: python
+
+ RDD.PLAYER.M5.EDGE_CONNECTED = RDD.PLAYER.M5.METAL & RDD.PLAYER.M5.OUTSIDE_EDGE_DISABLED
+ RDD.PLAYER.M6.EDGE_CONNECTED = RDD.PLAYER.M6.METAL & RDD.PLAYER.M6.OUTSIDE_EDGE_DISABLED
+
+The code above defines a derived layer that is generated when a layer with
+process **M5** and purpose metal overlaps the outside edges of a all
+process **M5** layers.
+
+
+.. ---------------------------------------------------------------
+
+
+Parameters
+----------
+
+When we’re designing PCells we need to model its parameters. An important characteristic
+of a parameter is that it often only accepts a select range of values. When the parameter
+corresponds to something physical the value often makes no sense when it’s zero or negative.
+To avoid that users create designs which have no meaning, we want to inhibit that the user
+assigns an invalid value to the parameter. This is exactly what we use properties for:
+restricting the range and type of values you can assign to a parameter
+
+In addition IPKISS’ properties help you as well with the following tasks:
+
+* providing defaults for your parameters
+* adding documentation for your parameters
+* implement caching to ensure that calculations don’t need to be run twice ( when not required )
+
+Define Parameters
+~~~~~~~~~~~~~~~~~
+
+Parameters are derived from the ``Parameter`` class. The
+``ParameterInitializer`` is responsible for storing the parameters of an
+instance. To define parameters the class has to inherit from the ``ParameterInitializer``
+class. The following code creates a layer object with a number as a parameter.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter()
+
+ >>> layer = Layer(number=9)
+ >>> layer.number
+ 9
+
+At first glance this may not seem to add any value that default Python already adds.
+The same example can be generated using native Python:
+
+.. code-block:: python
+
+ class Layer(object):
+ def __init__(self, number=0):
+ self.number = number
+
+The true value of the parameterized framework comes into play when adding
+parameter attributes, such as the **default** value, **restrictions**,
+**preprocess** and **doc**. With these attributes parameters can be
+type-checked and documented using customized values.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.INTEGER,
+ preprocess=spira.ProcessorInt(),
+ doc='Advanced parameter.')
+
+The newly defined parameter has more advanced features that makes for
+a more powerful design framework:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+ >>> layer.number = 9
+ >>> layer.number
+ 9
+ >>> layer.number = '8'
+ >>> layer.number
+ 8
+ >>> layer.number = 'Hi'
+ ValueError:
+
+
+Default
+~~~~~~~
+
+When defining a parameter the default value can be explicitly set using
+the ``default`` attribute. This is a simple method of declaring your parameter.
+For more complex functionality the default function attribute, ``fdef_name``,
+can be used. This attribute defines the name of a class method that is used To
+derive the default value of the parameter. Advantages of this technique is:
+
+* **Logic operations:** The default value can be derived from other defined parameters.
+* **Inheritance:** The default value can be overwritten using class inheritance.
+
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0)
+ datatype = spira.Parameter(fdef_name='create_datatype')
+
+ def create_datatype(self):
+ return 1
+
+ >>> layer = Layer()
+ >>> (layer.number, layer.datatype)
+ (0, 1)
+
+
+Restrictions
+~~~~~~~~~~~~
+
+**Restrictions** are Python objects that validates the received value of a parameter.
+In certain cases we want to restrict a parameter value to a certain type or range
+of values, for example:
+
+* Validate that the value is of specific object.
+* Validate that the value falls between then minimum and maximum.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.RestrictRange(2,5))
+
+The example above restricts the number parameter of the layer to be between 2 and 5:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number = 3
+ 3
+ >>> layer.number = 1
+ ValueError:
+
+Preprocessors
+~~~~~~~~~~~~~
+
+**Preprocessors** converts a received value before assigning it to the parameter.
+Preprocessors are typically used to convert a value of invalid type to one of
+a valid type, such as converting a float to an integer.
+
+Cache
+~~~~~
+
+SPiRA automatically caches parameters once they have been initialized.
+When using class methods to define default parameters using the ``fdef_name``
+attribute, the value is stored when called for the first time. Calling this
+value for the second time will not lead to a re-calculation, but rather the
+value will be retrieved from the cached dictionary.
+
+The cache is automatically cleared when **any** parameter in the class is
+updated, since other parameters might be dependent on the changed parameters.
+
+.. ---------------------------------------------------------------
+
+Parameterized Cells
+-------------------
+
+The SPiRA definition of a Parameterized Cell (PCell) in general terms:
+
+ A PCell is a cell that defines how layout elementals must be generated.
+ When instantiated it constructs itself according to the defined parameters.
+
+GDSII layouts encapsulate elemental design in the visual domain. Parameterized cells encapsulates elementals in the programming domain, and utilizes this domain to map external data to elementals.
+This external data can be data from the PDK or values extracted from an already designed layout using simulation software, such as InductEx.
+The SPiRA framework uses a scripting framework approach to connect the visual domain with a programming domain.
+The implemented architecture of SPiRA mimics the physical layout patterns implicit in hand-designed layouts.
+This framework architecture evolved by developing code heuristics that emerged from the process of creating a PCell.
+
+Creating a PCell is done by defining the elements and parameters required to create the desired layout.
+The relationship between the elements and parameters are described in a template format.
+Template design is an innate feature of parameterizing cell layouts.
+This heuristic concludes to develop a framework to effectively describe the different constituents of a PCell, rather than developing an API.
+The SPiRA framework was built from the following concepts:
+
+1. **Defining Element Shapes** This step defines the geometrical shapes from which an element polygon is generated.
+The supported shapes are rectangles, triangles, circles, as well as regular and irregular polygons.
+Each of these shapes has a set of parameters that control the pattern dimensions, e.g. the parameterized rectangle has two parameters, width and length , that defines its length and width, respectively.
+
+2. **Element Shape Transformations** This step describes the relation between the elements through a set of operations, that includes transformations of a shape in the x-y plane.
+Transforming an element involves: movement with a specific offset relative to its original location, rotation of a shape around its center with a specific angle,
+reflection of a shape around a idefined line, and aligning a shape to another shape with a specific offset and angle.
+
+3. **PDK Binding** The final step is binding data from the PDK to each created pattern. In SPiRA data from the PDK is parsed into the RDD.
+From this database the required process data can be linked to any specific pattern, such as the layer type of the defined rectangle, by defining
+parameters and placing design restrictions on them.
+
+Shapes
+~~~~~~
+
+
+.. code-block:: python
+
+ class ShapeExample(spira.Cell):
+
+ def create_elementals(self, elems):
+ pts = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ shape = spira.Shape(points=pts)
+ elems += spira.Polygon(shape=shape, layer=spira.Layer(1))
+ return elems
+
+
+Elements
+~~~~~~~~
+
+In the aboth example the ``spira.Polygon`` class was used to connect the shape with GDSII-related data, such as a layer number.
+This is the purpose of elementals; to wrap geometry data with GDSII layout data.
+In SPiRA the following elementals are defined:
+
+* **Polygon**: Connects a shape object with layout data (layer number, datatype).
+* **Label**: Generates text data in a GDSII layout.
+* **SRef**: A structure references, or sometimes called a cell reference, refers to another cell object, but with difference transformations.
+
+There are other special shapes that can be used in the pattern creation.
+These shapes are mainly a combination polygons and relations between polygons.
+These special shapes are referenced as if they represent a single shape and its outline is determined by its bounding box dimensions.
+The following elemental groups are defined in the SPiRA framework:
+
+* **Cells**: Is the most generic group that binds different parameterized elementals or clusters, while conserving the geometrical relations between these polygons or clusters.
+* **Group**: A set of elementals can be grouped in a logical container, called ``Group``.
+* **Ports**: A port is simply a polygon with a label on a dedicated process layer. Typically, port elementals are placed on conducting metal layers.
+* **Routes**: A route is defined as a cell that consists of a polygon elemental and a set of edge ports, that resembles a path-like structure.
+
+Group
+~~~~~
+
+Groups are used to apply an operation on a set of polygons, such a retrieving their combined bounding box.
+The following example illistrated the use of ``Group`` to generate a metal bounding box around a set of polygons:
+
+.. code-block:: python
+
+ class GroupExample(spira.Cell):
+
+ def create_elementals(self, elems):
+
+ group = spira.Group()
+ group += spira.Rectangle(p1=(0,0), p2=(10,10), layer=spira.Layer(1))
+ group += spira.Rectangle(p1=(0,15), p2=(10,30), layer=spira.Layer(1))
+
+ group.transform(spira.Rotation(45))
+
+ elems += group
+
+ bbox_shape = group.bbox_info.bounding_box(margin=1)
+ elems += spira.Polygon(shape=bbox_shape, layer=spira.Layer(2))
+
+ return elems
+
+Ports
+~~~~~
+
+Port objects are unique to the SPiRA framework and are mainly used for connection purposes.
+
+.. code-block:: python
+
+ class PortExample(spira.Cell):
+
+ def create_elementals(self, elems):
+ elems += spira.Rectangle(p1=(0,0), p2=(20,5), layer=spira.Layer(1))
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1', midpoint=(0,2.5), orientation=180)
+ ports += spira.Port(name='P2', midpoint=(20,2.5), orientation=0)
+ return ports
+
+Routes
+~~~~~~
+
+
+
+PCell creation is broken down into the following basic steps:
+
+.. code-block:: python
+
+ class PCell(spira.Cell):
+ """ My first parameterized cell. """
+
+ # Define parameters here.
+ number = spira.IntegerParameter(default=0, doc=’Parameter example number.’)
+
+ def create_elementals(self, elems):
+ # Define elementals here.
+ return elems
+
+ def create_ports(self, ports):
+ # Define ports here.
+ return ports
+
+.. code-block:: python
+
+ >>> pcell = PCell()
+ [SPiRA: Cell] (name ’PCell’, elementals 0, ports 0)
+ >>> pcell.number
+ 0
+ >>> pcell.__doc__
+ My first parameterized cell.
+ >>> pcell.number.__doc__
+ Parameter example number.
+
+The most basic SPiRA template to generate a PCell is shown above, and consists of three parts:
+
+1. Create a new cell by inheriting from ``spira.Cell``. This connects the class to the SPiRA framework when constructed.
+
+2. Define the PCell parameters as class attributes.
+
+3. Elementals and ports are defined in the ``create_elementals`` and ``create_ports`` class methods, which is automatically added to the cell instance.
+ The create methods are special SPiRA class methods that specify how the parameters are used to create the cell.
+
+
+.. code-block:: python
+
+ class Box(spira.Cell):
+
+ width = param. NumberField(default=1)
+ height = param. NumberField(default=1)
+ gds_layer = param. LayerField(number=0, datatype=0)
+
+ def create_elementals(self, elems):
+ shape = shapes.BoxShape(width=self.width, height=self.height)
+ elems += spira.Polygon(shape=shape, gds_layer=self.gds_layer)
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='Input', midpoint=(-0.5,0), orientation=90)
+ ports += spira.Port(name='Output', midpoint=(0.5,0), orientation=270)
+ return ports
+
+.. code-block:: python
+
+ >>> box = Box()
+ [SPiRA: Cell] (name ’Box ’, width 1, height 1, number 0, datatype 0)
+ >>> box.width
+ 1
+ >>> box. height
+ 1
+ >>> box. gds_layer
+ [SPiRA Layer] (name ’’, number 0, datatype 0)
+
+
+The above example illustrates constructing a parameterized box using the proposed framework:
+First, defining the parameters that the user would want to change when creating a box instance.
+Here, three parameter are given namely, the width, the height and the layer properties for GDSII construction.
+Second, a shape is generated from the defined parameters using the shape module.
+Third, this box shape is added as a polygon elemental to the cell instance.
+This polygon takes the shape and connects it to a set of methods responsible for converting it to a GDSII elemental.
+Fourth, two terminal ports are added to the left and right edges of the box, with their directions pointing away from the polygon interior.
+
+
+Validate-by-Design
+------------------
+
+
+
diff --git a/docs/_build/html/_sources/gdsii.rst.txt b/docs/_build/html/_sources/gdsii.rst.txt
index 52d2ef6c..f90782d0 100644
--- a/docs/_build/html/_sources/gdsii.rst.txt
+++ b/docs/_build/html/_sources/gdsii.rst.txt
@@ -2,28 +2,28 @@ GDSII Elementals
################
-Classes
-*******
+.. Classes
+.. *******
-.. .. py:function:: create_elements
-.. Creates an elemental.
+.. .. .. py:function:: create_elements
+.. .. Creates an elemental.
-.. .. function:: format_exception(etype, value, tb[, limit=None])
+.. .. .. function:: format_exception(etype, value, tb[, limit=None])
-.. Format the exception with a traceback.
+.. .. Format the exception with a traceback.
-.. :param etype: exception type
-.. :param value: exception value
-.. :param tb: traceback object
-.. :param limit: maximum number of stack frames to show
-.. :type limit: integer or None
-.. :rtype: list of strings
+.. .. :param etype: exception type
+.. .. :param value: exception value
+.. .. :param tb: traceback object
+.. .. :param limit: maximum number of stack frames to show
+.. .. :type limit: integer or None
+.. .. :rtype: list of strings
-.. autoclass:: spira.Cell
- :members:
- :undoc-members:
-.. :inherited-members:
-.. :show-inheritance:
+.. .. autoclass:: spira.Cell
+.. :members:
+.. :undoc-members:
+.. .. :inherited-members:
+.. .. :show-inheritance:
diff --git a/docs/_build/html/_sources/gettingstarted.rst.txt b/docs/_build/html/_sources/gettingstarted.rst.txt
new file mode 100644
index 00000000..6528e547
--- /dev/null
+++ b/docs/_build/html/_sources/gettingstarted.rst.txt
@@ -0,0 +1,46 @@
+Getting Started
+===============
+
+GDSII files contain a hierarchical representation of any polygonal geometry.
+They are mainly used in the microelectronics industry for the design of mask layouts, but are also employed in other areas.
+
+Because it is a hierarchical format, repeated structures, such as identical transistors, can be defined once and referenced multiple times in the layout, reducing the file size.
+
+There is one important limitation in the GDSII format: it only supports `weakly simple polygons `_, that is, polygons whose segments are allowed to intersect, but not cross.
+
+In particular, curves and shapes with holes are *not* directly supported.
+Holes can be defined, nonetheless, by connecting their boundary to the boundary of the enclosing shape.
+In the case of curves, they must be approximated by a polygon.
+The number of points in the polygonal approximation can be increased to better approximate the original curve up to some acceptable error.
+
+The original GDSII format limits the number of vertices in a polygon to 199.
+Most modern software disregards this limit and allows an arbitrary number of points per polygon.
+Gdspy follows the modern version of GDSII, but this is an important issue to keep in mind if the generated file is to be used in older systems.
+
+The units used to represent shapes in the GDSII format are defined by the user.
+The default unit in gdspy is 1 µm (10⁻⁶ m), but that can be easily changed by the user.
+
+
+First GDSII
+-----------
+
+Let's create our first GDSII file:
+
+.. code-block:: python
+
+ import gdspy
+
+ # Create the geometry: a single rectangle.
+ rect = gdspy.Rectangle((0, 0), (2, 1))
+ cell = gdspy.Cell('FIRST')
+ cell.add(rect)
+
+ # Save all created cells in file 'first.gds'.
+ gdspy.write_gds('first.gds')
+
+ # Optionally, display all cells using the internal viewer.
+ gdspy.LayoutViewer()
+
+
+
+
diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt
index 8d9b21bb..3bb1e328 100644
--- a/docs/_build/html/_sources/index.rst.txt
+++ b/docs/_build/html/_sources/index.rst.txt
@@ -1,26 +1,57 @@
-Welcome to the SPiRA documentation!
-===================================
+Welcome to the SPiRA Framework!
+===============================
+
+Parameterized Cells (PCells) are key components used to increase flexibility and productivity during layout design.
+Creating a parameterized cell integrates all design information into one place.
+The development and maintenance of PCell libraries typically requires device knowledge and advanced programming skills.
+
+Integrated circuit design requires many different levels of analysis. A lot of component design is done using a manual
+design flow, from SPICE simulations, to parameter extraction. While at the same time, circuit design requires abstraction
+at a much higher level.
+
+**SPiRA** is a parametric design framework for Superconductor and Quantum Integrated Circuit (SQIC) design.
+It revolves around the sound engineering concept that creating circuit layouts are prone to unexpected design errors.
+The design process is highly dependent on data provided by the fabrication process.
+In SPiRA, parameterized cells can be generated that interactively binds data from any fabrication process.
+A novel design method is introduced, called *validate-by-design*, that integrates parameter restrictions
+into the design flow, which limits a designer from breaking process design rules.
+
+SPiRA integrates different aspects into a single framework, where a parameterized cell can be defined once
+and then used throughout the design process, performing automatic device detection, netlist extraction, and
+design rule checking. Consequently, errors are significantly reduced by using the same component definition throughout the entire design flow.
+
+Lore
+----
+
+*Spira* is the fictional world of the Square role-playing video game Final Fantasy X.
+The name Spira refers to the word "spiral", alluding to one of the main themes of Final Fantasy X: *continuity*.
+The word "spiral" has multiple meanings depending on context. In geometry, it is a curve acting as the focus
+of a point rotating around a fixed point that continuously extends from that point.
+The inspiration behind the fictional Spira world, according to the producer Yoshinori Kitase,
+is the heuristic that players prefer a "*simple fantasy world*" over a more science fiction world.
+
+**The reason for naming this framework SPiRA:**
+
+The aim is to develop a *continuous design environment* for IC engineers to design circuit layouts,
+with focus falling on a *simple script-based methodology*. The **SPiRA core** is the *focus point*
+that revolves around the single idea of parameterizing layout geometries.
+
+**Basic termnology before getting started:**
+
+1. **PCell** (Parameterized Cell): Also refered to as a *layout generator* is a cell that defines how layout elements must be generated based on a given set of parameters.
+2. **RDD** (Rule Deck Database): A novel script-based approach to develop a Process Design Kit (PDK).
.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
- installation
- overview
- rdd_schema
- parameters
- tutorials
- pcell_examples
- developers
-
-.. installation
-.. overview
-.. rdd_schema
-.. gdsii
-.. parameters
-.. tutorials
-.. pcell_examples
-.. developers
+ :maxdepth: 2
+ :caption: Contents:
+
+ _0_methodology
+ _1_overview
+ _2_basic
+ _3_advanced
+ _4_reference
+ _5_developers
+
Indices and tables
==================
diff --git a/docs/_build/html/_sources/installation.rst.txt b/docs/_build/html/_sources/installation.rst.txt
deleted file mode 100644
index dedee205..00000000
--- a/docs/_build/html/_sources/installation.rst.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-Installation
-============
-
-This page gives more information about installing and setting up the SPiRA framework.
-
-Environment Setup
------------------
-
-SPiRA package descriptions:
-
-* `gdspy `_ Library for GDS file manipulations.
-* `pyclipper `_ Python wrapper for Angusj Clipper library.
-* `pygmsh `_ The goal of pygmsh is to combine the power of Gmsh with the versatility of Python and to provide useful abstractions from the Gmsh scripting language so you can create complex geometries more easily.
-* `meshio `_ A package to read and write different mesh formats.
-* `NetworkX `_ A Python package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks.
-
-Ubuntu
-------
-
-The following packages has to be installed for Ubuntu systems.
-
-.. code-block:: bash
- :linenos:
-
- sudo apt-get install python-dev
- sudo apt-get install python3-dev
- sudo apt-get install --reinstall build-essential
- sudo apt-get install python-tk # Ubuntu
- sudo apt-get update
-
-ArchLinux
----------
-
-On ArchLinux install the following:
-
-.. code-block:: bash
- :linenos:
-
- sudo pacman -S tk
-
-FreeBSD
--------
-
-Support to be added in Q1 2019.
-
-
diff --git a/docs/_build/html/_sources/overview.rst.txt b/docs/_build/html/_sources/overview.rst.txt
index 8fc61573..a2496c09 100644
--- a/docs/_build/html/_sources/overview.rst.txt
+++ b/docs/_build/html/_sources/overview.rst.txt
@@ -13,7 +13,7 @@ parts, each of which is implemented as a segregated module:
* **Layout Generator Kernel** (LGK): Layout generator framework that can bind to a PDK. This involves operations on the GDSII file format elements, such as polygons, label, cell references, etc.
-* **Layout Geometry Modular** (LGM): Algorithms for layout polygon operations and physical geometry construction for 2D and 3D (experimental) modeling.
+* **Layout Geometry Modular** (geometry): Algorithms for layout polygon operations and physical geometry construction for 2D and 3D (experimental) modeling.
* **Layout Primitive Extractor** (LPE): Detecting layout primitives, such as vias, ports, ntrons and junctions.
@@ -31,7 +31,7 @@ coherent fashion. The `demo` folder is an example workspace. A workspace consist
parts:
* PDKs: Folder containing all the fabrication specific data.
-* Projects: Folder containing the Python source file createed using SPiRA.
+* Projects: Folder containing the Python source file createed using spira.
**PDKs**
diff --git a/docs/overview.rst b/docs/_build/html/_sources/overview_old.rst.txt
similarity index 91%
rename from docs/overview.rst
rename to docs/_build/html/_sources/overview_old.rst.txt
index 8fc61573..d20889a9 100644
--- a/docs/overview.rst
+++ b/docs/_build/html/_sources/overview_old.rst.txt
@@ -13,7 +13,7 @@ parts, each of which is implemented as a segregated module:
* **Layout Generator Kernel** (LGK): Layout generator framework that can bind to a PDK. This involves operations on the GDSII file format elements, such as polygons, label, cell references, etc.
-* **Layout Geometry Modular** (LGM): Algorithms for layout polygon operations and physical geometry construction for 2D and 3D (experimental) modeling.
+* **Layout Geometry Modular** (geometry): Algorithms for layout polygon operations and physical geometry construction for 2D and 3D (experimental) modeling.
* **Layout Primitive Extractor** (LPE): Detecting layout primitives, such as vias, ports, ntrons and junctions.
@@ -31,7 +31,7 @@ coherent fashion. The `demo` folder is an example workspace. A workspace consist
parts:
* PDKs: Folder containing all the fabrication specific data.
-* Projects: Folder containing the Python source file createed using SPiRA.
+* Projects: Folder containing the Python source file createed using spira.
**PDKs**
@@ -70,8 +70,8 @@ The *scripts* folder largly encapsulates layout generators, while the *tutorials
contains extra data.
Each workspace is linked to a single fabrication process, but using mutliple
-fabs is also possible due to the simplicity of the workspace tree. In essence,
-the workspace can have any structure given that the user compensates for
+fabs is also possible due to the simplicity of the workspace tree.
+Technically, the workspace can have any structure given that the user compensates for
the necessary import changes. But it is highly adviced to use this structure.
diff --git a/docs/_build/html/_sources/parameters.rst.txt b/docs/_build/html/_sources/parameters.rst.txt
index cd045566..69b4720b 100644
--- a/docs/_build/html/_sources/parameters.rst.txt
+++ b/docs/_build/html/_sources/parameters.rst.txt
@@ -3,39 +3,39 @@ Layout Parameters
-Constraints
------------
+.. Constraints
+.. -----------
-Variables
----------
+.. Variables
+.. ---------
-Variables are primitive parameters such as intergers and strings.
-The following variables are supported and initialized as shown.
+.. Variables are primitive parameters such as intergers and strings.
+.. The following variables are supported and initialized as shown.
-* Integer
-* Float
-* String
-* Dictionary
-* List
+.. * Integer
+.. * Float
+.. * String
+.. * Dictionary
+.. * List
-Structured
-----------
+.. Structured
+.. ----------
-Structured parameters are newly defined custom parameters introduced
-in the SPiRA framework. The purpose of this parameters is to structure
-data that can be manipulated using extended futures.
+.. Structured parameters are newly defined custom parameters introduced
+.. in the SPiRA framework. The purpose of this parameters is to structure
+.. data that can be manipulated using extended futures.
-ElementalList
-~~~~~~~~~~~~~
+.. ElementalList
+.. ~~~~~~~~~~~~~
-List that contains all the layout elementals.
+.. List that contains all the layout elementals.
-PortList
-~~~~~~~~
+.. PortList
+.. ~~~~~~~~
-List that contains all the port elementals of a layout.
+.. List that contains all the port elementals of a layout.
diff --git a/docs/_build/html/_sources/pcell_examples.rst.txt b/docs/_build/html/_sources/pcell_examples.rst.txt
index 117ebcbc..33bce975 100644
--- a/docs/_build/html/_sources/pcell_examples.rst.txt
+++ b/docs/_build/html/_sources/pcell_examples.rst.txt
@@ -1,25 +1,25 @@
PCell Examples
==============
-Junction PCell
---------------
+.. Junction PCell
+.. --------------
-A basic Junction PCell that creates physical layers instead of using native polygon structures.
+.. A basic Junction PCell that creates physical layers instead of using native polygon structures.
-:download:`Download sample file <../demo/pdks/components/junction.py>`
+.. :download:`Download sample file <../demo/pdks/components/junction.py>`
-.. literalinclude:: ../demo/pdks/components/junction.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/pdks/components/junction.py
+.. :language: python
+.. :linenos:
-SQUID PCell
------------
+.. SQUID PCell
+.. -----------
-The following code shows a basic SQUID that uses the already defined Junction PCell to create a composite PCell.
+.. The following code shows a basic SQUID that uses the already defined Junction PCell to create a composite PCell.
-:download:`Download sample file <../demo/pdks/components/jj_squid.py>`
+.. :download:`Download sample file <../demo/pdks/components/jj_squid.py>`
-.. literalinclude:: ../demo/pdks/components/jj_squid.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/pdks/components/jj_squid.py
+.. :language: python
+.. :linenos:
diff --git a/docs/_build/html/_sources/pdk.rst.txt b/docs/_build/html/_sources/pdk.rst.txt
new file mode 100644
index 00000000..7388f9f5
--- /dev/null
+++ b/docs/_build/html/_sources/pdk.rst.txt
@@ -0,0 +1,115 @@
+Rule Deck Database
+==================
+
+.. The Rule Deck Database (RDD) is the proposed database schema for describing
+.. a fabrication process and general settings. The process data defined in the
+.. RDD can be used as parameters when creating PCells. The general settings
+.. can include any extra or necessary data that you might want to connect to the
+.. framework. For example, the data in the .ldf file compatible with InductEx
+.. can easily be translated to the RDD schema.
+.. The RDD is divided into the following different categories. These categories
+.. can easily be expanded by the development team due to the simplicity of
+.. hooking Python classes to the RDD script:
+
+.. * **GDSII related data**: Unique data that can be parsed by the GDSII file format. Dumpy layers, terminals and text layers settings.
+
+.. * **Process data**: Layer definitions, purpose layer and pattern layers can be described.
+
+.. * **Design Rules**: Design rules variables can be defined and hooked to Rule Classes.
+
+.. * **Primitive description**: Template Cells can be hooked to primitive cells, such as vias, which defines the boolean operations for detection.
+
+.. * **Material stacking**: List vertical configuration of specific material stacks. Boolean operations are used before 3D model extrusion (still very experimental).
+
+.. The following examples will illustrate each of the mentioned categories. First the database have to initialized and given a name and then process layers can be added.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. from spira.yevon.rdd import get_rule_deck
+.. from spira.yevon.rdd.technology import ProcessTree
+
+.. print('Initializing Rule Deck Library...')
+
+.. RDD = get_rule_deck()
+
+.. RDD.name = 'MiTLL'
+
+.. # Define new process tree.
+.. RDD.METALS = ProcessTree()
+
+.. # Define new process layer.
+.. RDD.METALS.M5 = ProcessTree()
+.. RDD.METALS.M5.LAYER = 50
+.. RDD.METALS.M5.THICKNESS = 0.5
+.. RDD.METALS.M5.LAMBDA = 0.5
+
+.. GDSII related data can be added by simple creating a data tree.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.GDSII = DataTree ()
+.. RDD.GDSII.TERM = 63
+.. RDD.GDSII.TEXT = 64
+
+.. Design Rules can be categorized using the rule tree class provided by the
+.. framework.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.RULES = DataTree ()
+.. RDD.RULES.ENCLOSURE = RuleTree ()
+
+.. # Define enclosure rule for layers J5 and M6.
+.. RDD.RULES.ENCLOSURE += Enclosure (
+.. layer1 = RDD.VIAS.J5.LAYER,
+.. layer2 = RDD.METALS.M6.LAYER,
+.. minimum = 0.3
+.. )
+
+.. # Define enclosure rule for layers C5 and M6.
+.. RDD.RULES.ENCLOSURE += Enclosure (
+.. layer1 = RDD.VIAS.C5.LAYER,
+.. layer2 = RDD.METALS.M6.LAYER,
+.. minimum = 0.35
+.. )
+
+.. Primitives are detected from the hand-designed layout using Template Cells
+.. that describes the pattern recognition algorithm.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.VIAS.J5.PCELL = ViaTemplate (
+.. name = 'J5',
+.. via_layer = RDD.VIAS.J5,
+.. layer1 = RDD.METALS.M5,
+.. layer2 = RDD.METALS.M6
+.. )
+
+.. Switching between databases based on different process technologies are done
+.. by simply importing the specific process RDD file.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. >>> import spira.all as spira
+.. >>> from spira.yevon.rdd.settings import get_rule_deck
+.. >>> RDD = get_rule_deck()
+.. >>> RDD.name
+.. 'MiTLL'
+.. >>> from pdks import aist
+.. >>> RDD.name
+.. 'AiST'
+
+.. It is possible to analyze the data contained in the tree objects.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. >>> RDD.METALS.keys
+.. ['GP', 'RES', 'BAS', 'COU', 'CTL']
+
+
diff --git a/docs/_build/html/_sources/rdd_schema.rst.txt b/docs/_build/html/_sources/rdd_schema.rst.txt
index 91c90d34..7388f9f5 100644
--- a/docs/_build/html/_sources/rdd_schema.rst.txt
+++ b/docs/_build/html/_sources/rdd_schema.rst.txt
@@ -1,115 +1,115 @@
Rule Deck Database
==================
-The Rule Deck Database (RDD) is the proposed database schema for describing
-a fabrication process and general settings. The process data defined in the
-RDD can be used as parameters when creating PCells. The general settings
-can include any extra or necessary data that you might want to connect to the
-framework. For example, the data in the .ldf file compatible with InductEx
-can easily be translated to the RDD schema.
-The RDD is divided into the following different categories. These categories
-can easily be expanded by the development team due to the simplicity of
-hooking Python classes to the RDD script:
+.. The Rule Deck Database (RDD) is the proposed database schema for describing
+.. a fabrication process and general settings. The process data defined in the
+.. RDD can be used as parameters when creating PCells. The general settings
+.. can include any extra or necessary data that you might want to connect to the
+.. framework. For example, the data in the .ldf file compatible with InductEx
+.. can easily be translated to the RDD schema.
+.. The RDD is divided into the following different categories. These categories
+.. can easily be expanded by the development team due to the simplicity of
+.. hooking Python classes to the RDD script:
-* **GDSII related data**: Unique data that can be parsed by the GDSII file format. Dumpy layers, terminals and text layers settings.
+.. * **GDSII related data**: Unique data that can be parsed by the GDSII file format. Dumpy layers, terminals and text layers settings.
-* **Process data**: Layer definitions, purpose layer and pattern layers can be described.
+.. * **Process data**: Layer definitions, purpose layer and pattern layers can be described.
-* **Design Rules**: Design rules variables can be defined and hooked to Rule Classes.
+.. * **Design Rules**: Design rules variables can be defined and hooked to Rule Classes.
-* **Primitive description**: Template Cells can be hooked to primitive cells, such as vias, which defines the boolean operations for detection.
+.. * **Primitive description**: Template Cells can be hooked to primitive cells, such as vias, which defines the boolean operations for detection.
-* **Material stacking**: List vertical configuration of specific material stacks. Boolean operations are used before 3D model extrusion (still very experimental).
+.. * **Material stacking**: List vertical configuration of specific material stacks. Boolean operations are used before 3D model extrusion (still very experimental).
-The following examples will illustrate each of the mentioned categories. First the database have to initialized and given a name and then process layers can be added.
+.. The following examples will illustrate each of the mentioned categories. First the database have to initialized and given a name and then process layers can be added.
-.. code-block:: python
- :linenos:
+.. .. code-block:: python
+.. :linenos:
- from spira.rdd import get_rule_deck
- from spira.rdd.technology import ProcessTree
+.. from spira.yevon.rdd import get_rule_deck
+.. from spira.yevon.rdd.technology import ProcessTree
- print('Initializing Rule Deck Library...')
+.. print('Initializing Rule Deck Library...')
- RDD = get_rule_deck()
+.. RDD = get_rule_deck()
- RDD.name = 'MiTLL'
+.. RDD.name = 'MiTLL'
- # Define new process tree.
- RDD.METALS = ProcessTree()
+.. # Define new process tree.
+.. RDD.METALS = ProcessTree()
- # Define new process layer.
- RDD.METALS.M5 = ProcessTree()
- RDD.METALS.M5.LAYER = 50
- RDD.METALS.M5.THICKNESS = 0.5
- RDD.METALS.M5.LAMBDA = 0.5
+.. # Define new process layer.
+.. RDD.METALS.M5 = ProcessTree()
+.. RDD.METALS.M5.LAYER = 50
+.. RDD.METALS.M5.THICKNESS = 0.5
+.. RDD.METALS.M5.LAMBDA = 0.5
-GDSII related data can be added by simple creating a data tree.
+.. GDSII related data can be added by simple creating a data tree.
-.. code-block:: python
- :linenos:
-
- RDD.GDSII = DataTree ()
- RDD.GDSII.TERM = 63
- RDD.GDSII.TEXT = 64
-
-Design Rules can be categorized using the rule tree class provided by the
-framework.
-
-.. code-block:: python
- :linenos:
-
- RDD.RULES = DataTree ()
- RDD.RULES.ENCLOSURE = RuleTree ()
-
- # Define enclosure rule for layers J5 and M6.
- RDD.RULES.ENCLOSURE += Enclosure (
- layer1 = RDD.VIAS.J5.LAYER,
- layer2 = RDD.METALS.M6.LAYER,
- minimum = 0.3
- )
-
- # Define enclosure rule for layers C5 and M6.
- RDD.RULES.ENCLOSURE += Enclosure (
- layer1 = RDD.VIAS.C5.LAYER,
- layer2 = RDD.METALS.M6.LAYER,
- minimum = 0.35
- )
-
-Primitives are detected from the hand-designed layout using Template Cells
-that describes the pattern recognition algorithm.
-
-.. code-block:: python
- :linenos:
-
- RDD.VIAS.J5.PCELL = ViaTemplate (
- name = 'J5',
- via_layer = RDD.VIAS.J5,
- layer1 = RDD.METALS.M5,
- layer2 = RDD.METALS.M6
- )
-
-Switching between databases based on different process technologies are done
-by simply importing the specific process RDD file.
-
-.. code-block:: python
- :linenos:
-
- >>> import spira
- >>> from spira.rdd.settings import get_rule_deck
- >>> RDD = get_rule_deck()
- >>> RDD.name
- 'MiTLL'
- >>> from pdks import aist
- >>> RDD.name
- 'AiST'
-
-It is possible to analyze the data contained in the tree objects.
-
-.. code-block:: python
- :linenos:
-
- >>> RDD.METALS.keys
- ['GP', 'RES', 'BAS', 'COU', 'CTL']
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.GDSII = DataTree ()
+.. RDD.GDSII.TERM = 63
+.. RDD.GDSII.TEXT = 64
+
+.. Design Rules can be categorized using the rule tree class provided by the
+.. framework.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.RULES = DataTree ()
+.. RDD.RULES.ENCLOSURE = RuleTree ()
+
+.. # Define enclosure rule for layers J5 and M6.
+.. RDD.RULES.ENCLOSURE += Enclosure (
+.. layer1 = RDD.VIAS.J5.LAYER,
+.. layer2 = RDD.METALS.M6.LAYER,
+.. minimum = 0.3
+.. )
+
+.. # Define enclosure rule for layers C5 and M6.
+.. RDD.RULES.ENCLOSURE += Enclosure (
+.. layer1 = RDD.VIAS.C5.LAYER,
+.. layer2 = RDD.METALS.M6.LAYER,
+.. minimum = 0.35
+.. )
+
+.. Primitives are detected from the hand-designed layout using Template Cells
+.. that describes the pattern recognition algorithm.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. RDD.VIAS.J5.PCELL = ViaTemplate (
+.. name = 'J5',
+.. via_layer = RDD.VIAS.J5,
+.. layer1 = RDD.METALS.M5,
+.. layer2 = RDD.METALS.M6
+.. )
+
+.. Switching between databases based on different process technologies are done
+.. by simply importing the specific process RDD file.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. >>> import spira.all as spira
+.. >>> from spira.yevon.rdd.settings import get_rule_deck
+.. >>> RDD = get_rule_deck()
+.. >>> RDD.name
+.. 'MiTLL'
+.. >>> from pdks import aist
+.. >>> RDD.name
+.. 'AiST'
+
+.. It is possible to analyze the data contained in the tree objects.
+
+.. .. code-block:: python
+.. :linenos:
+
+.. >>> RDD.METALS.keys
+.. ['GP', 'RES', 'BAS', 'COU', 'CTL']
diff --git a/docs/_build/html/_sources/setup.rst.txt b/docs/_build/html/_sources/setup.rst.txt
deleted file mode 100644
index 31789b12..00000000
--- a/docs/_build/html/_sources/setup.rst.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-setup module
-============
-
-.. automodule:: setup
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/_build/html/_sources/tutorials.rst.txt b/docs/_build/html/_sources/tutorials.rst.txt
index 223ebb89..24893edb 100644
--- a/docs/_build/html/_sources/tutorials.rst.txt
+++ b/docs/_build/html/_sources/tutorials.rst.txt
@@ -5,63 +5,74 @@ The following tutorials will help you understand the basic methodology behind th
SPiRA framework. This will show you how to use the framework to connect metadata
to generated layout instances.
-Parameterized Cells
--------------------
+.. Parameterized Cells
+.. -------------------
-.. include:: ../demo/projects/tutorials/0-vanilla/readme.rst
+.. .. include:: ../demo/projects/tutorials/0-vanilla/readme.rst
-.. literalinclude:: ../demo/projects/tutorials/0-vanilla/run_vanilla.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/projects/tutorials/0-vanilla/run_vanilla.py
+.. :language: python
+.. :linenos:
-.. -----------------------------------------------------------------------------------
+.. .. -----------------------------------------------------------------------------------
-Database
---------
+.. Database
+.. --------
-.. include:: ../demo/projects/tutorials/2-database/readme.rst
+.. .. include:: ../demo/projects/tutorials/2-database/readme.rst
-.. literalinclude:: ../demo/projects/tutorials/2-database/run_database.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/projects/tutorials/2-database/run_database.py
+.. :language: python
+.. :linenos:
-.. -----------------------------------------------------------------------------------
+.. .. -----------------------------------------------------------------------------------
-Elementals
-----------
+.. Shapes
+.. ------
-.. include:: ../demo/projects/tutorials/3-elementals/readme.rst
+.. .. include:: ../demo/projects/tutorials/3-shapes/readme.rst
-.. literalinclude:: ../demo/projects/tutorials/3-elementals/run_elementals.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/projects/tutorials/3-shapes/run_shapes.py
+.. :language: python
+.. :linenos:
-.. -----------------------------------------------------------------------------------
+.. .. -----------------------------------------------------------------------------------
-Subcells
---------
+.. Elementals
+.. ----------
-.. include:: ../demo/projects/tutorials/4-subcells/readme.rst
+.. .. include:: ../demo/projects/tutorials/4-elementals/readme.rst
-.. literalinclude:: ../demo/projects/tutorials/4-subcells/run_subcells.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/projects/tutorials/4-elementals/run_elementals.py
+.. :language: python
+.. :linenos:
-.. -----------------------------------------------------------------------------------
+.. .. -----------------------------------------------------------------------------------
-Ports
------
+.. Subcells
+.. --------
-.. include:: ../demo/projects/tutorials/5-ports/readme.rst
+.. .. include:: ../demo/projects/tutorials/5-subcells/readme.rst
-.. literalinclude:: ../demo/projects/tutorials/5-ports/run_ports.py
- :language: python
- :linenos:
+.. .. literalinclude:: ../demo/projects/tutorials/5-subcells/run_subcells.py
+.. :language: python
+.. :linenos:
-.. literalinclude:: ../demo/projects/tutorials/5-ports/run_ports_1.py
- :language: python
- :linenos:
+.. .. -----------------------------------------------------------------------------------
-.. -----------------------------------------------------------------------------------
+.. Ports
+.. -----
+
+.. .. include:: ../demo/projects/tutorials/6-ports/readme.rst
+
+.. .. literalinclude:: ../demo/projects/tutorials/6-ports/run_ports.py
+.. :language: python
+.. :linenos:
+
+.. .. literalinclude:: ../demo/projects/tutorials/6-ports/run_ports_1.py
+.. :language: python
+.. :linenos:
+
+.. .. -----------------------------------------------------------------------------------
diff --git a/docs/_build/html/_static/_0_methodology.rst b/docs/_build/html/_static/_0_methodology.rst
new file mode 100644
index 00000000..8ed97ad7
--- /dev/null
+++ b/docs/_build/html/_static/_0_methodology.rst
@@ -0,0 +1,92 @@
+###########
+Methodology
+###########
+
+Using general mathematics and science as an analogy, a basic understanding
+can be constructed of the importance of software in IC design: *Mathematics is
+the discipline of proving provable statements true and science is the discipline
+of proving provable statements false*.
+
+***************************************
+The Importance of Software in IC Design
+***************************************
+
+In software development, testing shows the presence of bugs and not the absence thereof. Software development is not
+a mathematical endeavour, even though it seems to manipulate mathematical
+constructs. Rather, software is more connected to science in the sense that it
+shows correctness by failing to show incorrectness. Therefore, IC design is to
+some extent only as good as the software systems that can prove the design
+incorrect. Circuit verification software only shows the engineer where
+mistakes are made, if any.
+
+Structured programming elicits a design architect that recursively decomposes
+a program into a set of small provable functions. Unit tests can be
+used to try and prove these small provable functions incorrect. If such tests
+fail to prove incorrectness, then the functions are deemed to be correct enough
+for all intents and purposes. Superconducting Electronic Design Automation
+(S-EDA) tools from a macro view can be thought of as a set of unit tests for
+a hardware design engineer to stress test their circuit layouts.
+
+***********************************
+The Development Psychology of SPiRA
+***********************************
+
+The development history of SPiRA can be broken down into four phases. First,
+a rudimentary version that consisted of a collection of scripts. Second, a
+small project that assimilated a minimum set of functions and class objects.
+Third, a large systemic project with multiple coherently connected modules.
+Finally, a meticulously designed framework that uses special coding techniques
+to create dynamic binding, software pattern implementation, data abstraction
+and custom classes.
+
+Before understanding the reasoning behind developing a parameterized framework
+for *physical design verification* it is imporant to first categorize the type
+of problem we are dealing with:
+
+Deductive Logic
+===============
+
+Deductive logic implies applying general rules which hold over the entirety
+of a closed domain of discourse: Software solutions that will most likely not
+change in the near future, tend to solve problems that are implicit in the technology.
+The reading and parsing of GDSII layouts, and geometry modeling,
+are examples implemented, through solutions that use deductive reasoning.
+
+Inductive Logic
+===============
+
+Inductive logic is inherently uncertain; the results concluded from inductive reasoning are more nuanced than simply stating; if this, then that.
+Consequently, heuristics can be derived using inductive reasoning to develop a sufficient SDE verification tool:
+Implementing fabrication design rules must be done following inductive logic, since future technology changes in the superconductor
+electronics field are still speculative. For instance, currently there is no specific PDK setup for superconductor electronics, and consequently, it
+can either be assumed that the future PDK versions will be similar to that of semiconducting, or that it will prevail and create a new set of standards.
+Also, the rapid changes being made in the semiconductor field add to the uncertainty of future metadata in the field of superconductivity.
+
+The symmetries between the superconductor and the semiconductor field are not necessarily indicative of the future evolution of superconductor electronics.
+Therefore, a paradigmatic software system (not just a solution) has to be developed, which can accommodate for dynamic "meta-changes", while still being extendible and maintainable.
+Physical design verification is highly dependent on the modelling of design rules. Layout generators allows us to effectively create our own programmable
+circuit models. Only minor differences exist between different fabrication processes, which enables us to develop a general software verification package
+by focusing on creating solution heuristics, through inductive models, rather than trying to develop concrete deductive solutions.
+
+Metaprogramming
+===============
+
+Technical sophistication can, at some level, cause degradation.
+Metaprogramming forms the foundation of the SPiRA framework and therefore it becomes
+apparent to start with a more general explanation of a metamodel.
+A model is an abstraction of a real-world phenomena. A metamodel is an
+even higher level of abstraction, which coalesces the properties of the original
+model. A model conforms to its metamodel like a human conforms its understanding to the sophistication of its internal dictionary (language)—or lack thereof.
+Metamodeling is the construction of a collection of concepts within a certain domain. Metamodeling involves defining the output and input relationships and
+then fitting the correct metamodels to represent the desired behaviour.
+Analogously, binding generic data to a layout has to be done by developing
+a metamodel of the system. The inherit purpose of the base metaclasses in
+the SPiRA framework is to bind data to a class object depending on the
+class composition. This has to be done after defining the class constituents
+(parameters), but before class creation. Hence, the use of metaclasses. In
+Python a class is an object that can be dynamically manipulated. Therefore,
+constraints have to be implemented on the class so as to overcome information
+overloading. In order to constrain the class, it has to be known which data to
+filter and which to process, which must then be added to the class as attributes.
+In doing this, the concept evolves that the accepted data itself can be restricted
+to a specific domain. This is the core principle behind the **validate-by-design** method
diff --git a/docs/_build/html/_static/_1_overview.rst b/docs/_build/html/_static/_1_overview.rst
new file mode 100644
index 00000000..3b52a40b
--- /dev/null
+++ b/docs/_build/html/_static/_1_overview.rst
@@ -0,0 +1,764 @@
+########
+Overview
+########
+
+This overview discusses the basic constituents of the **SPiRA** framework.
+This includes how data from the fabrication process is connected to the design environment,
+the basic design template for creating parameterized cells, and how different layout
+elements are defined.
+
+******************
+Process Design Kit
+******************
+
+The process design kit (PDK) is a set of technology files needed to implement
+the physical aspects of a layout design. Application-specific rules specified
+in the PDK controls how physical design applications work.
+
+A new PDK scheme is introduced. The Python programming language is used to
+bind PDK data to a set of classes, called data trees, that uniquely categorises
+PDK data. This new PDK scheme is called the Rule Deck Database (RDD), also
+refered to as the Rule Design Database. By having a native PDK in Python it
+becomes possible to use methods from the SPiRA framework to create a
+more descriptive PDK database. A design process typically contains the
+following aspects:
+
+* *GDSII Data*: Contains general settings required by the GDSII library, such as grid size.
+* *Process Data*: Contains the process layers, layer purposes, layer parameters, and layer mappings.
+* *Virtual Modelling*: Define derived layers that describes layer boolean operations.
+
+
+Initialization
+==============
+
+All caps are used to represent the *RDD* syntax. The reason being to make the
+script structure clearly distinguishable from the rest of the framework source
+code. First, the RDD object is initialized, followed by the process name and
+description, and then the GDSII related variables are defined.
+
+.. code-block:: python
+
+ RDD.GDSII = ParameterDatabase()
+ RDD.GDSII.UNIT = 1e-6
+ RDD.GDSII.GRID = 1e-12
+ RDD.GDSII.PRECISION = 1e-9
+
+
+Process Data
+============
+
+Process data relates to data provided by a specific fabrication technology.
+
+Process Layer
+-------------
+
+The first step in creating a layer is to define the process step that
+it represents in mask fabrication. The layer **process** defines a specific
+fabrciation function, for examples **metalization**. There can be multiple
+different drawing layers for a single process. A process database object
+is created that contains all the different process steps in a specific
+fabrication process:
+
+.. code-block:: python
+
+ RDD.PROCESS = ProcessLayerDatabase()
+
+ RDD.PROCESS.R1 = ProcessLayer(name='Resistor 1', symbol='R1')
+ RDD.PROCESS.M1 = ProcessLayer(name='Metal 1', symbol='M1')
+ RDD.PROCESS.C1 = ProcessLayer(name='Contact 1', symbol='C1')
+
+Each process has a name that describes the process function, and
+a *symbol* that is used to identify the process.
+
+Purpose Layer
+-------------
+
+The **purpose** indicates the use of the layer. Multiple layers with
+the same process but different purposes can be created.
+Similar to a process value each purpose contains a name and a unique symbol.
+Purposes are defined using a purpose database object:
+
+.. code-block:: python
+
+ RDD.PURPOSE = PurposeLayerDatabase()
+
+ RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', symbol='METAL')
+ RDD.PURPOSE.VIA = PurposeLayer(name='Contact', symbol='VIA')
+
+Process Parameters
+------------------
+
+Parameters are added to a process by creating a *parameter* database object
+that has a key value equal to the symbol of a pre-defined process:
+
+.. code-block:: python
+
+ RDD.M1 = ParameterDatabase()
+ RDD.M1.MIN_SIZE = 0.7
+ RDD.M1.MAX_WIDTH = 20.0
+ RDD.M1.J5_MIN_SURROUND = 0.5
+ RDD.M1.MIN_SURROUND_OF_I5 = 0.5
+
+Any number of variables can be added to the database using the dot operator.
+The code above defines a set of design parameters for the **M1 process**.
+
+Physical Layers
+---------------
+
+*Physical Layers* are unique to SPiRA and is defined as a layer that has a
+defined process and purpose. A physical layer (PLayer) defines the different
+purposes that a single process can be used for in a layout design.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1 = PhysicalLayerDatabase()
+ RDD.PLAYER.C1 = PhysicalLayerDatabase()
+
+ RDD.PLAYER.C1.VIA = PhysicalLayer(process=RDD.PROCESS.C1, purpose=RDD.PURPOSE.VIA)
+ RDD.PLAYER.M1.METAL = PhysicalLayer(process=RDD.PROCESS.M1, purpose=RDD.PURPOSE.METAL)
+
+The code above illustrates that the layer ``M1`` is a metal layer on process ``M1``,
+and layer ``C1`` is a contact via on process ``C1``.
+
+Virtual Modelling
+~~~~~~~~~~~~~~~~~
+
+*Derived Layers* are used to define different PLayer boolean operations.
+They are typically used for virtual modelling and polygon operations,
+such as merged polygons or polygon holes.
+
+.. code-block:: python
+
+ RDD.PLAYER.M1.EDGE_CONNECTED = RDD.PLAYER.M1.METAL & RDD.PLAYER.M1.OUTSIDE_EDGE_DISABLED
+
+The code above defines a derived layer that is generated when a layer with process ``M1`` and
+purpose ``metal`` overlaps the outside edges of a ``M1`` layer.
+
+
+.. ---------------------------------------------------------------------------------------------------
+
+
+**********
+Parameters
+**********
+
+Designing a generated layout requires modeling its parameters. To create an effective design
+environment it becomes paramount to define parameter restrictions.
+SPiRA uses a meta-configuration to define object parameters, which enables the following features:
+
+* Default values can be set to each parameter.
+* Documentation for each parameter can be added.
+* Parameters can be cached to ensure they aren't calculated multiple times.
+
+Introduction
+============
+
+Parameters are derived from the :py:class:`spira.Parameter` class. The
+:py:class:`ParameterInitializer` is responsible for storing the parameters of an
+instance. To define parameters the class has to inherit from the :py:class:`ParameterInitializer`
+class. The following code creates a layer object with a number parameter.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter()
+
+ >>> layer = Layer(number=9)
+ >>> layer.number
+ 9
+
+At first glance this may not seem to add any value that Python by default does not already adds.
+The same example can be generated using native Python:
+
+.. code-block:: python
+
+ class Layer(object):
+ def __init__(self, number=0):
+ self.number = number
+
+The true value of the parameterized framework becomes clear when adding attributes to the parameter, such as the **default** value, **restrictions**, **preprocess** and **doc**.
+These attributes allow a parameter to be type-checked and documented.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.INTEGER,
+ preprocess=spira.ProcessorInt(),
+ doc='Advanced parameter.')
+
+The newly defined parameter has more advanced features that makes for
+a more powerful design framework:
+
+.. code-block:: python
+
+ # The default value of the parameter is 0.
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+
+ # The parameter can be updated with an integer.
+ >>> layer.number = 9
+ >>> layer.number
+ 9
+
+ # The string can be preprocessed to an interger.
+ >>> layer.number = '8'
+ >>> layer.number
+ 8
+
+ # The string cannot be preprocessed and throws an error.
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+
+Default
+=======
+
+When defining a parameter the default value can be explicitly set using the :py:data:`default` attribute.
+This is a simple method of declaring your parameter.
+For more complex functionality the default function attribute, :py:data:`fdef_name`, can be used.
+This attribute defines the name of a class method that will be used to derive the default value of the parameter.
+Advantages of this implementation is:
+
+* **Logic operations:** The default value can be derived from other defined parameters.
+* **Inheritance:** The default value can be overwritten using class inheritance.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0)
+ datatype = spira.Parameter(fdef_name='create_datatype')
+
+ def create_datatype(self):
+ return 2 + 3
+
+ >>> layer = Layer()
+ >>> (layer.number, layer.datatype)
+ (0, 5)
+
+
+Restrictions
+============
+
+The validity of a parameter value is calculated by the *restriction* attribute.
+In certain cases we want to restrict a parameter value to a certain type or range of values, for example:
+
+* Validate that the value has a specific type, such as a via PCell.
+* Validate that the value falls between a specified minimum and maximum.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, restrictions=spira.RestrictRange(2,5))
+
+The example above restricts the number parameter of the layer to be between 2 and 5:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number = 3
+ 3
+ >>> layer.number = 1
+ ValueError: Invalid parameter assignment 'number' of cell 'Layer' with value '1', which is not compatible with 'Range Restriction: [2, 5)'.
+
+Preprocessors
+=============
+
+The preprocess attribute converts a received value before assigning it to the parameter.
+Preprocessors are typically used to convert a value of invalid type to one of a valid type, such as converting a float to an integer.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0, preprocess=spira.ProcessorInt())
+
+ >>> layer = Layer()
+ >>> layer.number = 1
+ 1
+ >>> layer.number = 2.1
+ 2
+ >>> layer.number = 'Hi'
+ ValueError: invalid literal for int() with base 10: 'Hi'
+
+Documentation
+=============
+
+Documentation can be added to the parameter using the :py:data:`doc` attribute.
+The created class can also be documented using triple qoutation marks.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ """ This is a layer class. """
+ number = spira.Parameter(default=0, doc='Parameter documentation.')
+
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+ >>> layer.__doc__
+ This is a layer class.
+ >>> layer.number.__doc__
+ Parameter documentation.
+
+Cache
+=====
+
+SPiRA automatically caches parameters once they have been initialized.
+When using class methods to define default parameters using the :py:data:`fdef_name` attribute, the value is stored when called for the first time.
+Calling this value for the second time will not lead to a re-calculation, but rather the value will be retrieved from the cached dictionary.
+The cache is automatically cleared when **any** parameter in the instance is updated, since other parameters might be dependent on the changed parameters.
+
+.. ---------------------------------------------------------------
+
+*******************
+Parameterized Cells
+*******************
+
+GDSII layouts encapsulate element design in the visual domain.
+Parameterized cells encapsulates elements in the programming domain, and utilizes this domain to map external data to elements.
+This external data can be data from the PDK or values extracted from an already designed layout using simulation software, such as InductEx.
+The SPiRA framework uses a scripting framework approach to connect the visual domain with a programming domain.
+The implemented architecture of SPiRA mimics the physical layout patterns implicit in hand-designed layouts.
+This framework architecture evolved by developing code heuristics that emerged from the process of creating a PCell.
+
+Creating a PCell is done by defining the elements and parameters required to create the desired layout.
+The relationship between the elements and parameters are described in a template format.
+Template design is an innate feature of parameterizing cell layouts.
+This heuristic concludes to develop a framework to effectively describe the different constituents of a PCell, rather than developing an API.
+The SPiRA framework was built from the following concepts:
+
+1. **Defining Element Shapes** This step defines the geometrical shapes from which an element polygon is generated.
+The supported shapes are rectangles, triangles, circles, as well as regular and irregular polygons.
+Each of these shapes has a set of parameters that control the pattern dimensions, e.g. the parameterized rectangle has two parameters, ``width`` and ``length``, that defines its length and width, respectively.
+
+2. **Element Shape Transformations** This step describes the relation between the elements through a set of operations, that includes transformations of a shape in the x-y plane.
+Transforming an element involves: movement with a specific offset relative to its original location, rotation of a shape around its center with a specific angle,
+reflection of a shape around a idefined line, and aligning a shape to another shape with a specific offset and angle.
+
+3. **PDK Binding** The final step is binding data from the PDK to each created pattern. In SPiRA, process related data is defined in the RDD.
+From this database the required data can be linked to any specific pattern by defining parameters and their design restrictions.
+
+Shapes
+======
+
+A shape is a basic 2-dimentional geometric pattern that consists of a list of points.
+These points can be manipulated and transformed as required by the designer, before commiting it to a layout cell.
+
+.. code-block:: python
+
+ class ShapeExample(spira.Cell):
+
+ def create_points(self, points):
+ points = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ return points
+
+You can create your own shape by creating a class that inherits from :py:class:`spira.Shape`.
+The shape coordinates are calculated by the :py:data:`create_points` class method that is innate to any :py:class:`spira.Shape` derived instance.
+The :py:class:`spira.Shape` class offers a rich set of methods for basic and advanced shape manipulation:
+
+.. code-block:: python
+
+ >>> shape = ShapeExample()
+ >>> shape.points
+ [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ >>> shape.area
+ 88
+ >>> shape.move((10, 0))
+ [[10, 0], [12, 2], [12, 6], [4, 6], [4, -6], [6, -4], [6, 4], [10, 4]]
+ >>> shape.x_coords
+ [10 12 12 4 4 6 6 10]
+
+Elements
+========
+
+The purpose of elements are to wrap geometry data with GDSII layout data.
+In SPiRA the following elements are defined:
+
+* **Polygon**: Connects a shape object with layout data (layer number, datatype).
+* **Label**: Generates text data in a GDSII layout.
+* **SRef**: A structure references, or sometimes called a cell reference, refers to another cell object, but with difference transformations.
+
+There are other special objects, called *element groups* that can be used in the design environment.
+These objects are mainly a combination of polygons and relations between polygons.
+These special objects are referenced as if they represent a single shape, and its outline is determined by its bounding box dimensions.
+The following element groups are defined in the SPiRA framework:
+
+* **Cells**: Is the most generic group that binds different parameterized elements or clusters, while conserving the geometrical relations between these polygons or clusters.
+* **Group**: A set of elements can be grouped in a logical container.
+* **Ports**: A port is simply a polygon with a label on a dedicated process layer. Typically, port elements are placed on conducting metal layers.
+* **Routes**: A route is defined as a cell that consists of a polygon element and a set of edge ports, that resembles a path-like structure.
+
+The SPiRA design environment for creating a PCEll is broken down into the following basic templated steps:
+
+.. code-block:: python
+
+ class PCell(spira.Cell):
+ """ My first parameterized cell. """
+
+ # Define parameters here
+ number = spira.IntegerParameter(default=0, doc='Parameter example number.')
+
+ def create_elements(self, elems):
+ # Define elements here.
+ return elems
+
+ def create_ports(self, ports):
+ # Define ports here.
+ return ports
+
+The most basic SPiRA template to generate a PCell is shown above, and consists of three parts:
+
+1. Create a new cell by inheriting from :py:class:`spira.Cell`. This connects the class to the SPiRA framework when constructed.
+2. Define the PCell parameters as class attributes.
+3. Elements and ports are defined in the :py:data:`create_elements` and :py:data:`create_ports` class methods, which is automatically added to the cell instance.
+ The create methods are special SPiRA class methods that specify how the parameters are used to create the cell.
+
+.. code-block:: python
+
+ class PolygonExample(spira.Cell):
+
+ def create_elements(self, elems):
+ pts = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ shape = spira.Shape(points=pts)
+ elems += spira.Polygon(shape=shape, layer=spira.Layer(1))
+ return elems
+
+ >>> D = PolygonExample()
+ >>> D.gdsii_output()
+
+.. image:: _figures/_elements.png
+ :align: center
+
+The code above illustrates the creation of a polygon object, using the already defined shape.
+The polygon object connects the shape to a GDSII library with a GDSII layer number equal to :math:`1`.
+Once the polygon has been created it can be added to the cell instance using the ``+`` operator
+to increment the :py:data:`elems` list.
+
+Group
+=====
+
+Groups are used to apply an operation on a set of polygons, such a retrieving their combined bounding box.
+The following example illistrated the use of :py:class:`spira.Group` to generate a metal bounding box
+around a set of polygons:
+
+.. code-block:: python
+
+ class GroupExample(spira.Cell):
+
+ def create_elements(self, elems):
+
+ group = spira.Group()
+ group += spira.Rectangle(p1=(0,0), p2=(10,10), layer=spira.Layer(1))
+ group += spira.Rectangle(p1=(0,15), p2=(10,30), layer=spira.Layer(1))
+
+ elems += group
+
+ bbox_shape = group.bbox_info.bounding_box(margin=1)
+ elems += spira.Polygon(shape=bbox_shape, layer=spira.Layer(2))
+
+ return elems
+
+.. image:: _figures/_group.png
+ :align: center
+
+A group polygon is created around the two defined polygons with a marginal offset of 1 micrometer.
+
+Ports
+=====
+
+Port objects are unique to the SPiRA framework and are mainly used for connection purposes.
+
+.. code-block:: python
+
+ class Box(spira.Cell):
+
+ width = spira.NumberParameter(default=1)
+ height = spira.NumberParameter(default=1)
+ layer = spira.LayerParameter(default=spira.Layer(1))
+
+ def create_elements(self, elems):
+ shape = shapes.BoxShape(width=self.width, height=self.height)
+ elems += spira.Polygon(shape=shape, layer=self.layer)
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1_M1', midpoint=(-0.5,0), orientation=180, width=1)
+ ports += spira.Port(name='P2_M1', midpoint=(0.5,0), orientation=0, width=1)
+ return ports
+
+.. code-block:: python
+
+ >>> box = Box()
+ [SPiRA: Cell] (name ’Box ’, width 1, height 1, number 0, datatype 0)
+ >>> box.width
+ 1
+ >>> box. height
+ 1
+ >>> box. gds_layer
+ [SPiRA Layer] (name ’’, number 0, datatype 0)
+ >>> box.gdsii_output(name='Ports')
+
+.. image:: _figures/_ports.png
+ :align: center
+
+The above example illustrates constructing a parameterized box using the proposed framework:
+First, defining the parameters that the user would want to change when creating a box instance.
+Here, three parameter are given namely, the :py:data:`width`, the :py:data:`height` and the layer
+properties for GDSII construction. Second, a shape is generated from the defined parameters using the shape module.
+Third, this box shape is added as a polygon element to the cell instance. This polygon takes the shape and connects
+it to a set of methods responsible for converting it to a GDSII element. Fourth, two terminal ports are added to
+the left and right edges of the box, with their directions pointing away from the polygon interior.
+
+Routes
+======
+
+Most of the times in designing digital electronic circuit layouts it is required to define metal polygon connections between different *devices*.
+Defining the exact points connecting different devices can become a tedious task. **Routes** are polygon classes that automatically generates
+a polygon path between different devices. As previously explained, ports are used to define connection points to a cell instance.
+Therefore, routes can be defined as a **polygon** that connects to two **ports** through a path-dependent algorithm.
+SPiRA offers a variety of different route algorithms that can be generated depending on the relative port positions and the user requirements.
+
+.. code-block:: python
+
+ class RouteExample(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=self.ports, layer=spira.Layer(1))
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1', midpoint=(0,0), orientation=180)
+ ports += spira.Port(name='P2', midpoint=(20,10), orientation=0)
+ return ports
+
+.. image:: _figures/_routes.png
+ :align: center
+
+.. --------------------------------------------------------------------------------------
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Validate-by-Design
+.. ******************
+
+
+.. .. --------------------------------------------------------------------------------------
+
+*******
+Filters
+*******
+
+Filters are algorithms whos state can be toggled (enabled or disabled). These algorithms are
+typically used to add or remove extra information to an already working design, hence the name *filter*.
+
+Boolean
+=======
+
+Instead of individually looping through the entire tree hierarchy of a layout to apply
+boolean operations on all polygons, a *boolean filter* can be used to automate this process.
+
+
+Layer
+=====
+
+Sometimes we want to filter certain layers, since they only serve a temporary purpose, or
+because we only want to view layers in the design, for example a specific purpose type.
+In these cases we can use the *layer filter* to automatically filter certain layers in a cell.
+
+
+*******
+Netlist
+*******
+
+The netlist extraction algorithm consists of a chain of filtering methods.
+The basic algorithmic steps is divided into two categories:
+
+1. Extracting a netlist for each individual metal polygon.
+2. Chaining the metal netlists into a single mask netlist.
+
+For each of these steps there is a chain of filter algorithms applied to ensure the correct extraction:
+
+Polygon Netlist
+===============
+
+* Label all nodes in the netlist to the metal layer they represent.
+* Label the nodes that are represetative of detected devices.
+* Label the nodes that represents ERC connections between differenct metal polygons.
+* Calcaulte the cross-over nodes and determine the individual inductive branches.
+
+Mask Netlist
+============
+
+* Combine all metal netlists into a single netlist domain and connect shared nodes.
+* Calculate individual branches between device nodes.
+* Calculate cross-over nodes between different branches.
+* Recalcalate individual branches which includes the detected cross-over nodes.
+* Collapse all nodes belonging to the same branch into a single node representation.
+
+
+
+.. .. --------------------------------------------------------------------------------------
+
+.. ******************
+.. Virtual Modeelling
+.. ******************
+
+
+
+.. Derived Edges
+.. =============
+
+
+
+.. --------------------------------------------------------------------------------------
+
+************
+RDD Advanced
+************
+
+The goal of the advanced RDD tutorial is to discuss:
+
+* How to define filters.
+* How to define derived layers.
+* How to create a LVS database.
+
+Filters
+=======
+
+Filters leverages the *chain of responsiblity* design pattern to chain a number of
+algorithms that has to be executed in a sequential order on a specific layout object.
+
+.. code-block:: python
+
+ # First we create a filters database.
+ RDD.FILTERS = ParameterDatabase()
+
+ class PCellFilterDatabase(LazyDatabase):
+ """ Define the filters that will be used when creating a spira.PCell object. """
+
+ def initialize(self):
+ from spira.yevon import filters
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.DEVICE_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+ f += filters.ContactAttachFilter(name='contact_attach')
+
+ f['boolean'] = True
+ f['simplify'] = True
+ f['contact_attach'] = True
+
+ self.DEVICE = f
+
+ f = filters.ToggledCompositeFilter(filters=[])
+ f += filters.ProcessBooleanFilter(name='boolean', metal_purpose=RDD.PURPOSE.CIRCUIT_METAL)
+ f += filters.SimplifyFilter(name='simplify')
+
+ f['boolean'] = True
+ f['simplify'] = True
+
+ self.CIRCUIT = f
+
+ f = filters.ToggledCompositeFilter(name='mask_filters', filters=[])
+ f += filters.ElectricalAttachFilter(name='erc')
+ f += filters.PinAttachFilter(name='pin_attach')
+ f += filters.DeviceMetalFilter(name='device_metal')
+
+ f['erc'] = True
+ f['pin_attach'] = True
+ f['device_metal'] = False
+
+ self.MASK = f
+
+ RDD.FILTERS.PCELL = PCellFilterDatabase()
+
+The code above shows the creation of three composite filter algorithms:
+
+* The **device filters** will only be applied on detected device cells.
+* The **circuit filters** will only be aplied on non-device cell.
+* The **mask filters** will be executed on the top-level layout cell.
+
+The PCell filter class inherits from the :py:data:`LazyDatabase` class to delay its construction.
+Therefore, the PCell filter database is only instantiated when a specific filter is called using
+the dot operator as shown below:
+
+.. code-block:: python
+
+ f = RDD.FILTERS.PCELL.DEVICE
+
+Derived Layers
+==============
+
+Defining **derived layers** forms the basis of creating the LVS database, since derived layers
+almost by definition defines via connections.
+
+.. code-block:: python
+
+ RDD.VIAS.C5R = ParameterDatabase()
+
+ RDD.VIAS.C5R.LAYER_STACK = {
+ 'BOT_LAYER' : RDD.PLAYER.R5.METAL,
+ 'TOP_LAYER' : RDD.PLAYER.M6.METAL,
+ 'VIA_LAYER' : RDD.PLAYER.C5R.VIA
+ }
+ RDD.PLAYER.C5R.CLAYER_CONTACT = RDD.PLAYER.R5.METAL & RDD.PLAYER.M6.METAL & RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M1 = RDD.PLAYER.R5.METAL ^ RDD.PLAYER.C5R.VIA
+ RDD.PLAYER.C5R.CLAYER_M2 = RDD.PLAYER.M6.METAL ^ RDD.PLAYER.C5R.VIA
+
+ class C5R_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.via import ViaC5RA, ViaC5RS
+ self.DEFAULT = ViaC5RA
+ self.STANDARD = ViaC5RS
+
+ RDD.VIAS.C5R.PCELLS = C5R_PCELL_Database()
+
+The example above defines a C5R via which connects layer M6 to R5 through a contact layer C5R.
+The logic steps for creating this coding snippet is as follow:
+
+1. A layer stack is created to defined the top, bottom, and via layers.
+2. The derived layers are create that specifies the boolean operations between different layers required in order to detect a via connection. Note, that the :py:data:`RDD.PLAYER.C5R.CLAYER_CONTACT` is the via derived layer that specifies the via connection, while the other two derived layers is used for debugging purposes.
+3. A set of different via PCell classes is added to the database. These classes will be constructed and used during the device detection run.
+
+LVS Database
+============
+
+Defining devices in the LVS database is done similarly to defining vias as already explained:
+
+.. code-block:: python
+
+ RDD.DEVICES = ParameterDatabase()
+
+ RDD.DEVICES.JUNCTION = ParameterDatabase()
+
+ class Junction_PCELL_Database(LazyDatabase):
+ def initialize(self):
+ from ..devices.junction import Junction
+ self.DEFAULT = Junction
+
+ RDD.DEVICES.JUNCTION.PCELLS = Junction_PCELL_Database()
+
+A Josephson junction device is added to the LVS database by importing an already defined
+PCell class and can be constucted using the dot operator:
+
+.. code-block:: python
+
+ # Create a JTL instance from the definition in the RDD LVS database.
+ JtlPCell = RDD.DEVICES.JUNCTION.PCELLS.DEFAULT()
+
+ # View the created instance.
+ JtlPCell.gdsii_view()
+
+
+
+
+
+
diff --git a/docs/_build/html/_static/_2_basic.rst b/docs/_build/html/_static/_2_basic.rst
new file mode 100644
index 00000000..f6d61714
--- /dev/null
+++ b/docs/_build/html/_static/_2_basic.rst
@@ -0,0 +1,797 @@
+##############
+Basic Tutorial
+##############
+
+This tutorial consists of a set of examples that will guide you on how to create a basic PCell,
+manipulate layout elements, and connect process data to your design.
+
+******************
+Parameterized Cell
+******************
+
+First, we have to understand the basic PCell template structure innate to any SPiRA design environment.
+
+Demonstrates
+============
+
+* How to create a parameterized cell by inheriting form :py:class:`spira.PCell`.
+* How to add parameters to the cell.
+* How to validate received parameters.
+
+The first step in any SPiRA design environment is to import the framework:
+
+.. code-block:: python
+
+ import spira.all as spira
+
+The :py:mod:`spira` namespace contains all the important functions and classes provided by the framework.
+In order to create a layout cell all classes has to inherit from :py:class:`spira.PCell`:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+The :py:class:`spira.PCell` class connects the design to the **SPiRA core**. In the exampe above we created
+a parameterized cell of type :py:class:`Resistor` and a basic description given in qoutation marks.
+Now that a layout class has been constructed we need to define a set of *parameters* that will
+describe relations between layout elements.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+We defined two ``float`` restricted parameters, the :py:data:`width` and the :py:data:`length` of the resistor,
+along with documentation (using the :py:data:`doc` attribute) and a default value equal to :math:`0.3` and :math:`1.0`, respectively.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+By definition we want to make sure the length of of the resistor is larger than the width.
+To check the validity of the parameters in relation to eachother, we can use the :py:meth:`validate_parameters` method:
+This method consists of a series of *if-statements* that checks whether the defined parameters are valid or not after instantiation.
+
+.. code-block:: python
+
+ # 1. First create an instance of the resistor class.
+ >>> D = Resistor()
+
+ # 2. You van view the default values of the parameters.
+ >>> (D.width, D.length)
+ (0.3, 1.0)
+
+ # 3. The parameter is successfully updated if it is valid.
+ >>> D.width = 0.5
+ >>> (D.width, D.length)
+ (0.5, 1.0)
+
+ # 4. If an invalid value is received, an error is thrown.
+ >>> D.width = 1.1
+ ValueError: `Width` cannot be larger than `length`.
+
+
+***********************
+Connecting Process Data
+***********************
+
+Now that we have created a basic PCell and understand how to define parameters, we want to
+connect data from the fabrication process to these parameters.
+
+Demonstrates
+============
+
+* How to connect fabrication process data to a design.
+* How to change to a different fabrication process.
+
+The *Rule Deck Database* is a set of Python scripting files that contains all the required fabrication process data,
+and is accessed using the :py:mod:`RDD` module.
+SPiRA contains a default process that can be used directly from the :py:mod:`spira` namespace:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+We updated the parameter default values to equal that of the minimum design restrictions defined
+by the process for the resistor layer :py:data:`R1`.
+After having imported the :py:mod:`spira` namespace the default process database can be changed
+by importing the desired :py:mod:`RDD` object.
+
+.. code-block:: python
+
+ import spira.all as spira
+ from spira.technologies.mit.process.database import RDD
+
+ >>> RDD
+
+
+
+*****************
+Creating Elements
+*****************
+
+Next, we want to create geometric shapes based on the received instance parameters,
+before adding them to the cell instance as element objects.
+
+Demonstrates
+============
+
+* How to add elements to a cell instance.
+* How to create a shape geometry.
+* How to create a GDSII polygon from a shape.
+
+The :py:data:`create_elements` class method is a unique SPiRA method that automatically connects
+a list of elements to the class instance. Methods that starts with ``create_`` are special
+methods in SPiRA and are called *create methods*.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ w, l = self.width, self.length
+ shape = spira.Shape(points=[[0,0], [l,0], [l,w], [0,w]])
+ elems += spira.Polygon(shape=shape, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_3_layout.png
+ :align: center
+
+The defined parameters are used to create a geometeric shape inside the :py:data:`create_elements` method.
+Once the shape is defined it can be added to the layout as a polygon element. The purpose of a polygon
+is to add GDSII-related data to the defined shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+Instead of manually creating shapes SPiRA offers a set of predefined polygons that can be used.
+The code snippet above illustrates the use of the :py:meth:`spira.Box` polygon instead of creating
+a shape object and sending it the polygon container.
+
+
+**************
+Creating Ports
+**************
+
+Similar to the :py:data:`create_elements` method that connects element to your cell instance,
+the :py:data:`create_ports` method adds ports to your design. A port is defined as a vector object
+that is used to connect different layout elements.
+
+Demonstrates
+============
+
+* How to connect ports to your layout.
+* How to name and connect a process type to your port.
+* How to unlock edge specific ports.
+
+Ports are used to connect different layout elements, such as routing different device cells via a metal polygon.
+Therefore, defining the port position, its orientation, and to what process layer is connects are extremely important.
+These are some of the most commonly used port parameters:
+
+* :py:data:`name` The name of the port.
+* :py:data:`midpoint` The position of the port.
+* :py:data:`orientation` The direction of the port.
+* :py:data:`width` The width of the port.
+* :py:data:`process` The process to which the port object connects.
+
+In the example below we first define a box polygon and then add ports to the left and right edges of the shape.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ w, l = self.width, self.length
+ ports += spira.Port(name='P1_R1', midpoint=(-l/2,0), orientation=180, width=self.width)
+ ports += spira.Port(name='P2', midpoint=(l/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return ports
+
+.. image:: _figures/_4_ports_0_enabled.png
+ :align: center
+
+Port names has to contain one of the following formats:
+
+**Pname_Process**
+ The first letter is defines the **purpose** of the port followed by the port name, typically a number.
+ After the underscore character the **process** symbol is added (as defined in the RDD).
+ This port naming convention is used when no process parameter is added to the object, as shown in the
+ example above with port ``P1_R1``. This process symbol are compared to the defined processes in the
+ RDD and automatically updates the process parameter of the port instance.
+
+*Pname*
+ As shown with ``P2`` the port name does not have to contain the process symbol if a process parameter
+ is manually added to the creation of a port instance.
+
+The most important port purposes for PCell creation are:
+
+* **P** (PinPort): The default port used as a terminal to horizontally connect different elements.
+* **E** (EdgePort): Ports that are automatically generated from the edges of metal polygons.
+* **D** (DummyPort): Typically used to snap a one side of a route object to a specific position.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(alias='ply1', width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ # Process symbol will automatically be added to the port name.
+ ports += self.elements['ply1'].ports['E1_R1'].copy(name='P1')
+ ports += self.elements['ply1'].ports['E3_R1'].copy(name='P2')
+ return ports
+
+Defining the exact midpoint of a port required knowledge of the boundary of the shape we want to connect to.
+SPiRA automatically generates edge ports for metal polygons. The generated box element is given an alias
+that is used to access that specific element. These edges can be activated as ports by simply changing
+the port name. The example above illustrates changing edge port ``E1_R1`` to port ``P1``.
+
+.. image:: _figures/_4_ports_0.png
+ :align: center
+
+The image bove depicts the automatically generated edge ports that can be used for identifying which
+edges to convert to active port. In this example we are converting edges, ``E1_R1`` and ``E3_R1``,
+to ports ``P1_R1`` and ``P2_R1``, respectively. Note, that even though we only added ``P1`` as the port name,
+the process symbol to which the port belongs are automatically added by the SPiRA framework, since the process
+parameter is already set within the edge port. The end result is shown in the figure below:
+
+.. image:: _figures/_4_ports_1.png
+ :align: center
+
+
+***************
+Creating Routes
+***************
+
+Generally metal polygons are used to connect different circuit devices. In this example we first define
+two ports and then generate a metal polygon between them using the :py:class:`spira.Route` base class.
+SPiRA offers a variaty of different routing algorithm depending on the relative position between ports.
+
+Demonstrates
+============
+
+* How to create a route between two different ports.
+* How to externally cache parameters.
+
+First, we define the ports as two separate parameters, :py:data:`p1` and :py:data:`p2`. Second, we use create
+methods to generate port parameters. Doing so allows us to access the ports in both :py:data:`create_elements`
+and :py:data:`create_ports` without re-calculating the ports.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ # Create a straight route between ports p1 and p2.
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+.. image:: _figures/_5_routes_0.png
+ :align: center
+
+It is also possible to define all ports in a single method and externally cache the method using the ``spira.cache``
+decorator as shown in the following example.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ @spira.cache()
+ def get_ports(self):
+ p1 = spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+ p2 = spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return [p1, p2]
+
+ def create_elements(self, elems):
+ p1, p2 = self.get_ports()
+ elems += spira.RouteStraight(p1=p1, p2=p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_ports()
+ return ports
+
+
+**************
+Cell Hierarchy
+**************
+
+As layout designs becomes bigger and more complex with larger circuits, extending an maintaining PCells
+becomes a tedious task. Using basic object-oriented inheritance simplifies the overall structure of our designs.
+
+Demonstrates
+============
+
+* How to create a manhattan route between two ports.
+* How to use inheritance to mimic layout hierarchy.
+* How to extend a layout without changing the parent class.
+* How to pass cells as a parameter to another cell class.
+* How to connect different structures using their ports.
+
+If two ports are not aligned on the same axis, the :py:data:`spira.RouteManhattan` method can be used to
+generate a manhattan polygon between them. One prerequisite is that the absolute port orientation difference
+must equal :math:`180` degrees.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return port
+
+.. image:: _figures/_6_hierarchy_0.png
+ :align: center
+
+The created :py:class:`Resistor` cell can be extended by creating a new cell that inherits from this class.
+To extend the elements we have to add the parent class elements to the current instance. This is done
+using Python's :py:data:`super` method: ``elems = super().create_elements(elems)``. A second route can then
+be generated starting from :py:data:`p2` and ending at :py:data:`p3` with a rounded corner bend.
+
+.. code-block:: python
+
+ # ...
+
+ class ResistorExtended(Resistor):
+
+ p3 = spira.Parameter(fdef_name='create_p3')
+
+ def create_p3(self):
+ return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems = super().create_elements(elems)
+ elems += spira.RouteManhattan(ports=[self.p2, self.p3], corners='round', layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+.. image:: _figures/_6_hierarchy_1.png
+ :align: center
+
+Another method to mimic cell hierarchy is to pass a cell to another cell as a parameter:
+
+.. code-block:: python
+
+ class ResistorManhattan(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorStraight(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorConnect(spira.PCell):
+
+ res0 = spira.CellParameter(default=ResistorManhattan)
+ res1 = spira.CellParameter(default=ResistorStraight)
+
+ def create_elements(self, elems):
+ s1 = spira.SRef(reference=self.res0())
+ s2 = spira.SRef(reference=self.res1())
+ s2.connect(port=s2.ports['P1'], destination=s1.ports['P2'])
+ elems += [s1, s2]
+ return elem
+
+We start by creating two resistor classes, :py:class:`ResistorManhattan` and :py:class:`ResistorStraight`,
+then we add them to a single cell instance were we can snap the two structures into place
+by connecting their respective instance ports. An instance for each resistor cell is created
+using :py:class:`spira.SRef` and then :py:data:`P1` of instance :py:class:`ResistorStraight`
+is connect to :py:data:`P2` of instance :py:class:`ResistorManhattan` using the :py:meth:`connect` method.
+
+.. image:: _figures/RouteConnect.*
+ :align: center
+
+
+***************
+Transformations
+***************
+
+Transformations is SPiRA are not directly applied to layout elements. Instead, they are
+abstraction build as a layer on top of the SPiRA core, and are connected to Elements
+as parameters. Doing so enable us to transform elements without losing hierarchical
+data implicit in the layout structure.
+
+Demonstrates
+============
+
+* Understand why transformations are parameterized in SPiRA.
+* How to apply transformations to layout elements.
+* How to keep the hierarchical structure of a flatened layout.
+
+There are multiple different ways to apply a transformation to a layout element:
+
+* The first method creates a transform object and then applies it to an object.
+* The second directly uses a element method to apply the transform.
+
+.. code-block:: python
+
+ class TranslatePolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ """ Apply transformation by first creating a transform object. """
+ T = spira.Translation(Coord(-10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(T)
+ return ply
+
+ def create_t2(self):
+ """ Apply transformation by creating a generic transform.
+ Instead of using the `.ttransform` method, the transform
+ is directly added as a parameter."""
+ tf = spira.GenericTransform(translation=Coord(-22, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=tf)
+ return ply
+
+ def create_t3(self):
+ """ Directly transform the element using the corresponding transform method. """
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((-34, 0))
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+.. image:: _figures/_9_translate.png
+ :align: center
+
+The code snippet above illustrates the different ways to connect a transform to an element.
+The first method in :py:data:`create_t1` is typically used when we want to create a set of
+predefined transforms and later connect them to multiple elements.
+
+The second method in :py:data:`create_t2` is very similar to that of the first, but instead
+manually creates a generic transformation object and connect it to the element as a parameter.
+This method is just shown for illustration purposes and rarely used in practice, since a generic
+transform is automatically created by the framework when multiple transform objects are added.
+
+The thrid method in :py:data:`create_t3` uses the class method to automatically create the
+transform object and emidiately apply the transform to the subject element.
+
+.. code-block:: python
+
+ class TransformPolygon(spira.Cell):
+
+ ref_point = spira.Parameter(fdef_name='create_ref_point')
+ t1 = spira.Parameter(fdef_name='create_t1')
+ t2 = spira.Parameter(fdef_name='create_t2')
+ t3 = spira.Parameter(fdef_name='create_t3')
+
+ def create_ref_point(self):
+ return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1))
+
+ def create_t1(self):
+ T = spira.Rotation(30) + spira.Translation(Coord(10, 0))
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=2))
+ ply.transform(transformation=T)
+ return ply
+
+ def create_t2(self):
+ T = spira.GenericTransform(translation=(20, 0), rotation=60)
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=3), transformation=T)
+ return ply
+
+ def create_t3(self):
+ ply = spira.Rectangle(p1=(0,0), p2=(10, 50), layer=spira.Layer(number=4))
+ ply.translate((30, 0))
+ ply.rotate(90)
+ return ply
+
+ def create_elements(self, elems):
+ elems += self.ref_point
+ elems += self.t1
+ elems += self.t2
+ elems += self.t3
+ return elems
+
+Transformations can be compounded using the plus operator as shown in :py:data:`create_t1`.
+The result is a generic transformation that can be added to any element. A generic transform
+can also be explicitly defined as in :py:data:`create_t2`, or multiple transforms can be
+adding using the corresponding methods as shown in :py:data:`create_t3`.
+
+.. image:: _figures/_9_transform.png
+ :align: center
+
+
+**********
+Stretching
+**********
+
+This tutorial builds from the previous tutorial of transformations.
+Here, we will look at how to stretch a cell reference and specific polygons using ports.
+
+Demonstrates
+============
+
+* How to stretch layout elements.
+* How to use expanded transformations to view flattened ports.
+* How to stretch a specific polygon while maintaining the layout hierarchy.
+
+.. First, we will start by stretching basic flattened layout structures.
+
+In this example we are stretching an entire cell reference by some factor.
+We have created a basic Josephson Junction to demonstrate the stretching of different polygons
+inside the PCell, while maintaining the hierarchical structure.
+
+.. code-block:: python
+
+ class Jj(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Convex(radius=7.0, layer=RDD.PLAYER.C2.VIA)
+ return elems
+
+
+ class ResVia(spira.Cell):
+
+ def create_elements(self, elems):
+ elems += spira.Rectangle(p1=(-7.5, -13.2), p2=(7.5, -8.2), layer=RDD.PLAYER.R1.METAL)
+ elems += spira.Rectangle(p1=(-4, -12), p2=(4.1, -10), layer=RDD.PLAYER.C1.VIA)
+ return elems
+
+
+ class Top(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -8))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sj1', reference=Jj(), transformation=t1)
+ elems += spira.SRef(alias='Sr1', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -23), p2=(10, 10), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Bot(spira.Cell):
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -30))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.SRef(alias='Sr2', reference=ResVia(), transformation=t2)
+ elems += spira.Rectangle(p1=(-10, -55), p2=(10, -35), layer=RDD.PLAYER.M2.METAL)
+ return elems
+
+
+ class Junction(spira.Cell):
+ """ Josephson junction. """
+
+ def get_transforms(self):
+ t1 = spira.Translation((0, 0))
+ t2 = spira.Translation((0, -5))
+ return [t1, t2]
+
+ def create_elements(self, elems):
+ t1, t2 = self.get_transforms()
+ elems += spira.Rectangle(p1=(-13, -60), p2=(13, 12), layer=RDD.PLAYER.M1.METAL)
+ elems += spira.SRef(alias='S1', reference=Top(), transformation=t1)
+ elems += spira.SRef(alias='S2', reference=Bot(), transformation=t2)
+ return elems
+
+An instance of the :py:class:`Junction` cell can be created and added as a reference, which
+can be stretched using the :py:meth:`stretch_by_factor` method:
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ C += S.stretch_by_factor(factor=(2,1))
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded flattened view of the junction cell is shown below.
+
+.. image:: _figures/_9_expanded.png
+ :align: center
+
+All polygon elements that coalesces this cell is stretched by a factor of two in the horizontal direction (x-axis).
+
+.. image:: _figures/_9_factor.png
+ :align: center
+
+.. code-block:: python
+
+ junction = Junction()
+
+ C = spira.Cell(name='TestingCell')
+ S = spira.SRef(alias='Jj', reference=junction)
+
+ # Stretch the reference and add it to the cell.
+ S.stretch_p2p(port_name='S1:Sr1:E3_R1', destination_name='S2:Sr2:E1_R1')
+
+ # Generate an output using the build-in viewer.
+ C.gdsii_output()
+
+The expanded view is used to access flattened ports using their hierarchically derived names.
+The port names used in the code above are shown in the expanded view of the cell.
+In this example we want to stretch the two shunt resistor polygons so form a single resistor connection polygon.
+
+.. image:: _figures/_9_ports.png
+ :align: center
+
+
+
+
+
+
diff --git a/docs/_build/html/_static/_2_tutorials.rst b/docs/_build/html/_static/_2_tutorials.rst
new file mode 100644
index 00000000..26f5ceac
--- /dev/null
+++ b/docs/_build/html/_static/_2_tutorials.rst
@@ -0,0 +1,488 @@
+#########
+Tutorials
+#########
+
+
+******************
+Parameterized Cell
+******************
+
+Demonstrates
+============
+
+* How to create a parameterized cell by inheriting form ``spira.PCell``.
+* How to add parameters to the cell.
+* How to validate received parameters.
+
+The first step in any SPiRA design environment is to import the framework:
+
+.. code-block:: python
+
+ import spira.all as spira
+
+The ``spira`` namespace contains all the important functions and classes provided by the framework.
+In order to create a layout cell all classes has to inherit from ``spira.PCell``:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+The ``spira.PCell`` class connects the design to the **SPiRA core**. In the exampe above we created
+a parameterized cell of type ``Resistor`` and a basic description given in qoutation marks.
+Now that a layout class has been constructed we need to define a set of *parameters* that will
+describe how relations between layout elements in this class.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+We defined two parameters the ``width`` and the ``length`` of the resistor, along with a default
+value equal to 0.3 and 1.0, respectively. Each parameter is also documented using the ``doc`` attribute.
+As illistrated in this example the parameters are restricted to the ``float`` type. To check the validity
+of the parameters is relation to eachother, we can use the ``validate_parameters`` method:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+ """ My first parameterized resistor cell. """
+
+ width = spira.FloatParameter(default=0.3, doc='Width of the shunt resistance.')
+ length = spira.FloatParameter(default=1.0, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+The ``validate_parameters`` consists of a series of *if-statements* that check whether the defined
+parameters are valid or not. Here, by definition we want to make sure the length of of the resistor
+is larger than the width.
+
+.. code-block:: python
+
+ # 1. First create an instance of the resistor class.
+ >>> D = Resistor()
+
+ # 2. You van view the default values of the parameters.
+ >>> (D.width, D.length)
+ (0.3, 1.0)
+
+ # 3. The parameter value is changed if it is valid.
+ >>> D.width = 0.5
+ >>> (D.width, D.length)
+ (0.5, 1.0)
+
+ # 4. Is an invalid value is received, an error is thrown.
+ >>> D.width = 1.1
+ ValueError: `Width` cannot be larger than `length`.
+
+
+***********************
+Connecting Process Data
+***********************
+
+Demonstrates
+============
+
+* How to connect fabrication process data to a design.
+* How to change to a different fabrication process.
+
+The ``RDD`` database is a SPiRA object that contains all the required data of a fabrication process.
+SPiRA contains a default process that can be used directly from the ``spira`` namespace:
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+We updated the parameter default values to equal that of the minimum design restrictions defined
+by the process for the resistor layer, ``R1``.
+
+After having imported the ``spira`` namespace the default process database can be changed
+by importing the desired ``RDD`` object.
+
+.. code-block:: python
+
+ import spira.all as spira
+ from spira.technologies.mit.process.database import RDD
+
+ >>> RDD
+
+
+
+*****************
+Creating Elements
+*****************
+
+Demonstrates
+============
+
+* How to add elements to a cell instance.
+* How to create a shape geometry.
+* How to create a GDSII polygon from a shape.
+
+The ``create_elements`` class method is a unique SPiRA method that automatically connects
+a list of elements to the class instance. Methods that starts with ``create_`` are special
+methods in SPiRA and are called *create methods*.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ w, l = self.width, self.length
+ shape = spira.Shape(points=[[0,0], [l,0], [l,w], [0,w]])
+ elems += spira.Polygon(shape=shape, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+The defined parameters are used to create a geometeric shape inside the ``create_elements`` method.
+Once the shape is created it can be added to the layout as a polygon. The purpose of the ``Polygon``
+class is to add GDSII-related data to an abstract geometry.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+Instead of manually creating shapes SPiRA offers a set of predefined polygons that can be used.
+The code snippet above illustrates the use of the ``spira.Box()`` polygon instead of creating
+a shape object and sending it the polygon container.
+
+
+**************
+Creating Ports
+**************
+
+Demonstrates
+============
+
+* How to connect ports to you layout.
+* How to name and connect a process type to your port.
+* How to unlock edge specific ports.
+
+Similar to the ``create_elements`` method that connects element to your cell instance,
+the ``create_ports`` method adds ports to your design. A port is defined as a vector object
+that is used to connect different layout elements.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ w, l = self.width, self.length
+ ports += spira.Port(name='P1_R1', midpoint=(-l/2,0), orientation=180, width=self.width)
+ ports += spira.Port(name='P2', midpoint=(l/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return ports
+
+Port names has to be of the form *PortName_ProcessSymbol* is no process is added to the created object, as shown in
+the example above with port ``P1_R1``. The process symbol set in the name are compared to the defined processes
+in the RDD and automatically adds the process to the port object.
+
+As shown with the ``P2`` the port name does not have to contain the process symbol is a process parameter
+is added. The first letter of the port name defines its type. The 2 most important port types for PCell creation is:
+
+* **P** (PinPort): The default port used as a terminal to horizontally connect different elements.
+* **E** (EdgePort): Ports that are automatically generated from the edges of metal purpose layer polygons.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_elements(self, elems):
+ elems += spira.Box(alias='ply1', width=self.length, height=self.width, center=(0,0), layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ # Process symbol will automatically be added to the port name.
+ ports += self.elements['ply1'].ports['E1_R1'].copy(name='P1')
+ ports += self.elements['ply1'].ports['E3_R1'].copy(name='P2')
+ return ports
+
+Defining the exact midpoint of a port required knowledge of the boundary of the shape we want to connect to.
+SPiRA automatically generates edge ports for metal polygons. The generated box element is given an alias
+that is used to access that specific element. These edges can be activated as ports by simply changing
+the port name. The example above illustrates changing edge port ``E1_R1`` to port ``P1``.
+
+
+******
+Routes
+******
+
+Demonstrates
+============
+
+* How to create a routes between two different ports.
+* How to externally cache parameters.
+
+Generally metal polygons are used to connect different circuit devices. In this example we first define
+two ports and then generate a metal polygon between them using the ``spira.Route`` base class.
+SPiRA offers a variaty of different routing algorithm depending on the relative position between
+the ports. In this example we are generating a simple straight route, since the ports are already
+horizontally aligned.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+First, we define the ports as two separate parameters, ``p1`` and ``p2``. We use create methods to generate to ports
+before adding them to the instance. Doing so allows us to access the port objects from both the ``create_elements``
+method and the ``create_ports`` method.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ @spira.cache()
+ def get_ports(self):
+ p1 = spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+ p2 = spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+ return [p1, p2]
+
+ def create_elements(self, elems):
+ p1, p2 = self.get_ports()
+ elems += spira.RouteStraight(p1=p1, p2=p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_ports()
+ return ports
+
+It is also possible to define all ports in a single method and externally cache the method using the ``spira.cache``
+decorator as shown in the code snippet above.
+
+
+**************
+Cell Hierarchy
+**************
+
+Demonstrates
+============
+
+* How to create a manhattan route between two ports.
+* How to use inheritance to mimic layout hierarchy.
+* How to extend a layout without changing the parent class.
+* How to pass cells as a parameter to another cell class.
+* How to connect different structures using their ports.
+
+.. code-block:: python
+
+ class Resistor(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return port
+
+If two ports are not align on a single axis, the ``spira.RouteManhattan`` method can be used to
+generate a manhattan polygon between them. One prerequisite is that the port orientations difference must
+equal 180 degrees.
+
+The created ``Resistor`` cell can be extende by creating a new cell that inherits from this class:
+
+.. code-block:: python
+
+ class ResistorExtended(Resistor):
+
+ p3 = spira.Parameter(fdef_name='create_p3')
+
+ def create_p3(self):
+ return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems = super().create_elements(elems)
+ elems += spira.RouteManhattan(ports=[self.p2, self.p3], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+To extend the elements we have to add the parent class elements to the current instance. This is done
+using Python's ``super`` method: ``elems = super().create_elements(elems)``. A second route can then
+be generated starting from ``p2`` and ending at ``p3``.
+
+Another method to mimic cell hierarchy is to pass a cell to another cell as a parameter:
+
+
+.. code-block:: python
+
+ class ResistorManhattan(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorStraight(spira.PCell):
+
+ width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.')
+ length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.')
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+
+ def validate_parameters(self):
+ if self.width > self.length:
+ raise ValueError('`Width` cannot be larger than `length`.')
+ return True
+
+ def create_p1(self):
+ return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_p2(self):
+ return spira.Port(name='P2', midpoint=(self.length/2,0), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1)
+
+ def create_elements(self, elems):
+ elems += spira.RouteStraight(p1=self.p1, p2=self.p2, layer=spira.RDD.PLAYER.R1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+ ports += [self.p1, self.p2]
+ return ports
+
+
+ class ResistorConnect(spira.PCell):
+
+ res0 = spira.CellParameter(default=ResistorManhattan)
+ res1 = spira.CellParameter(default=ResistorStraight)
+
+ def create_elements(self, elems):
+ s1 = spira.SRef(reference=self.res0())
+ s2 = spira.SRef(reference=self.res1())
+ s2.connect(port=s2.ports['P1'], destination=s1.ports['P2'])
+ elems += [s1, s2]
+ return elem
+
+We start by creating two resistor classes, ``ResistorManhattan`` and ``ResistorStraight``.
+Then, we add them to a single cell instance were we can snap the two structures into place
+by connecting their respective instance ports. A instance for each resistor cell is created
+using ``spira.SRef`` and then ``P1`` of instance ``ResistorStraight`` is connect to ``P2``
+of instance ``ResistorManhattan`` using the ``connect`` method.
+
+
+
+
+
+
+
diff --git a/docs/_build/html/_static/_3_advanced.rst b/docs/_build/html/_static/_3_advanced.rst
new file mode 100644
index 00000000..7d33139c
--- /dev/null
+++ b/docs/_build/html/_static/_3_advanced.rst
@@ -0,0 +1,888 @@
+#################
+Advanced Tutorial
+#################
+
+This set of tutorials focuses on explaining more advanced features that the SPiRA framework
+has to offer. We go into more details on how to create **device** and **circuit** PCells,
+how to structure a design, and how to manipulate layout elements.
+
+In SPiRA PCells can be divided into two categorises, :py:class:`spira.Device` and :py:class:`spira.Circuit`.
+Each of these classes contains a set of different back-end algorithms that are automatically executed when
+the layout class is constructed. Typically, these algorithms consists of boolean operations and filtering algorithms.
+Also, inheriting from these classes defines the purpose of the layout, either a *device* or a *circuit*.
+
+**Devices:**
+
+Similar to creating a PCell, constructing a device cell required inheriting from :py:class:`spira.Device`
+instead of :py:class:`spira.PCell`. In superconducting circuits a device layout is usually a *Via* or a *Junction*.
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+ pass
+
+**Circuits:**
+
+A circuit PCell is designed similar to that of a device. By definition a circuit layout contains polygon
+routes that connects different device and ports instances. Therefore, a :py:class:`spira.Circuit` contains
+two extra, but optional, create methods to simplify the code structure:
+
+* :py:data:`create_structures`: Defines the device instances.
+* :py:data:`create_routes`: Defines the routing paths between different structures and ports.
+
+.. code-block:: python
+
+ class Jtl(spira.Circuit):
+
+ def create_structures(self, elems):
+ return elems
+
+ def create_routes(self, elems):
+ return elems
+
+Note, it is not required to use these methods, but designing large circuits can cause the
+:py:data:`create_elements` method to become cumbersome.
+
+
+*****************
+Library Structure
+*****************
+
+Every design environment connects to a specific fabrication process, also known as the PDK.
+In SPiPA, the PDK data is encapsulated in Python scripts and are collectively called the RDD.
+RDD script names start with ``db_`` as illustrated below.
+
+This section discusses how to organize your design project in SPiRA as a systematized library.
+Technically, your library can have any structure given that you compensates for the necessary
+importing changes. But it is highly adviced to use the proposed structure.
+
+.. code-block:: bash
+
+ technologies
+ |__ mitll
+ |__ devices
+ |__ junction.py
+ |__ vias.py
+ |__ circuits
+ |__ jtl.py
+ |__ dcsfq.py
+ |__ db_init.py
+ |__ db_process.py
+ |__ db_lvs.py
+
+The technology library is broken down into 3 parts:
+
+1. **Devices**: Contains defined device PCells for the specific technology.
+2. **Circuits**: Contains PCell circuits created using the specific technology.
+3. **Database**: Contains a set database files that make up the RDD.
+
+The :py:data:`technologies` folder is the base folder inside the SPiRA design environment that
+contains all the different technology processes and PCell designs in a single place. The library structure
+above contains the ``mitll`` library, which consists of defined junction and via devices, a long
+with a JTL and DCSFQ circuit.
+
+The ``db_init`` script is the first file to be executed when the RDD database is constructed.
+The ``db_process`` script contains most of the information required to design a PCell.
+This file contains the process layers, layer purposes, process parameters, etc.
+The ``db_lvs`` script defines the created device PCells to be used in the device detection
+algorithms when doing LVS extraction.
+
+
+*****
+YTron
+*****
+
+In this example we will start from the beginning. First, we will create a *yTron* shape
+and then using this shape we will create a device containing input/output ports.
+This device will then be used to create a full circuit layout.
+
+Demonstrates
+============
+
+* How to create your own shape class.
+* How to create a device and a circuit PCell.
+* How to restrict a design to only accept a specific shape or device.
+
+We create our own yTron shape by inheriting from :py:class:`spira.Shape`, which allows us
+to manipulate the shape once it has been instantiated.
+
+.. code-block:: python
+
+ class YtronShape(spira.Shape):
+ """ Class for generating a yTron shape. """
+
+ rho = NumberParameter(default=2, doc='Angle of concave bend between the arms.')
+ arm_lengths = CoordParameter(default=(5,3), doc='Length or the left and right arms, respectively.')
+ source_length = NumberParameter(default=5, doc='Length of the source arm.')
+ arm_widths = CoordParameter(default=(2,2), doc='Width of the left and right arms, respectively.')
+ theta = NumberParameter(default=10, doc='Angle of the left and right arms.')
+ theta_resolution = NumberParameter(default=10, doc='Smoothness of the concave bend.')
+
+ xc = Parameter(fdef_name='create_xc')
+ yc = Parameter(fdef_name='create_yc')
+ arm_x_left = Parameter(fdef_name='create_arm_x_left')
+ arm_y_left = Parameter(fdef_name='create_arm_y_left')
+ arm_x_right = Parameter(fdef_name='create_arm_x_right')
+ arm_y_right = Parameter(fdef_name='create_arm_y_right')
+ rad_theta = Parameter(fdef_name='create_rad_theta')
+ ml = Parameter(fdef_name='create_midpoint_left')
+ mr = Parameter(fdef_name='create_midpoint_right')
+ ms = Parameter(fdef_name='create_midpoint_source')
+
+ def create_rad_theta(self):
+ return self.theta * np.pi/180
+
+ def create_xc(self):
+ return self.rho * np.cos(self.rad_theta)
+
+ def create_yc(self):
+ return self.rho * np.sin(self.rad_theta)
+
+ def create_arm_x_left(self):
+ return self.arm_lengths[0] * np.sin(self.rad_theta)
+
+ def create_arm_y_left(self):
+ return self.arm_lengths[0] * np.cos(self.rad_theta)
+
+ def create_arm_x_right(self):
+ return self.arm_lengths[1] * np.sin(self.rad_theta)
+
+ def create_arm_y_right(self):
+ return self.arm_lengths[1] * np.cos(self.rad_theta)
+
+ def create_midpoint_left(self):
+ xc = -(self.xc + self.arm_x_left + self.arm_widths[0]/2)
+ yc = self.yc + self.arm_y_left
+ return [xc, yc]
+
+ def create_midpoint_right(self):
+ xc = self.xc + self.arm_x_right + self.arm_widths[1]/2
+ yc = self.yc + self.arm_y_right
+ return [xc, yc]
+
+ def create_midpoint_source(self):
+ xc = (self.arm_widths[1] - self.arm_widths[0])/2
+ yc = -self.source_length + self.yc
+ return [xc, yc]
+
+ def create_points(self, points):
+
+ theta = self.theta * np.pi/180
+ theta_resolution = self.theta_resolution * np.pi/180
+ theta_norm = int((np.pi-2*theta)/theta_resolution) + 2
+ thetalist = np.linspace(-(np.pi-theta), -theta, theta_norm)
+ semicircle_x = self.rho * np.cos(thetalist)
+ semicircle_y = self.rho * np.sin(thetalist)+self.rho
+
+ xpts = semicircle_x.tolist() + [
+ self.xc + self.arm_x_right,
+ self.xc + self.arm_x_right + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ self.xc + self.arm_widths[1],
+ 0, -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left + self.arm_widths[0]),
+ -(self.xc + self.arm_x_left)
+ ]
+
+ ypts = semicircle_y.tolist() + [
+ self.yc + self.arm_y_right,
+ self.yc + self.arm_y_right,
+ self.yc, self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc - self.source_length,
+ self.yc, self.yc + self.arm_y_left,
+ self.yc + self.arm_y_left
+ ]
+
+ points = np.array(list(zip(xpts, ypts)))
+
+ return points
+
+There is a few important aspects to note in the :py:class:`YtronShape` class:
+
+1. The :py:data:`create_points` create method is required by the :py:class:`spira.Shape` class and is similar
+ to the :py:class:`create_elements` method for creating a cell.
+2. In this example the importance of the :py:data:`doc` attribute when defining a parameter becomes apparent.
+3. Using create methods to dynamically define the shape parameters makes the shape instance easier to use.
+
+Once we have the desired shape we can use it to create a device cell, containing a GDSii layer and ports instances.
+
+.. code-block:: python
+
+ # ...
+
+ class YtronDevice(spira.Device):
+
+ shape = spira.ShapeParameter(restriction=spira.RestrictType([YtronShape]))
+
+ def create_elements(self, elems):
+ elems += spira.Polygon(shape=self.shape, layer=RDD.PLAYER.M1.METAL)
+ return elems
+
+ def create_ports(self, ports):
+
+ left_arm_width = self.shape.arm_widths[0]
+ rigth_arm_width = self.shape.arm_widths[1]
+ src_arm_width = self.shape.arm_widths[0] + self.shape.arm_widths[1] + 2*self.shape.xc
+
+ ports += spira.Port(name='Pl_M1', midpoint=self.shape.ml, width=left_arm_width, orientation=90)
+ ports += spira.Port(name='Pr_M1', midpoint=self.shape.mr, width=rigth_arm_width, orientation=90)
+ ports += spira.Port(name='Psrc_M1', midpoint=self.shape.ms, width=src_arm_width, orientation=270)
+
+ return ports
+
+ >>> shape = YtronShape(theta_resolution=100)
+ >>> D = YtronDevice(shape=shape)
+ >>> D.gdsii_output()
+
+.. image:: _figures/_adv_0_ytron.png
+ :align: center
+
+The :py:data:`shape` parameter defined in the :py:class:`YtronDevice` class restricts the instance to only receive
+a shape of type :py:class:`YtronShape`. Using the shape parameters the port instances for each arms
+can be defined and added to the PCell instance. The created yTron device can now be used in a circuit:
+
+.. code-block:: python
+
+ class YtronCircuit(spira.Circuit):
+
+ ytron = spira.Parameter(fdef_name='create_ytron', doc='Places an instance of the ytron device.')
+
+ @spira.cache()
+ def get_io_ports(self):
+ p1 = spira.Port(name='P1_M1', midpoint=(-10,10), orientation=0)
+ p2 = spira.Port(name='P2_M1', midpoint=(5,10), width=0.5, orientation=270)
+ p3 = spira.Port(name='P3_M1', midpoint=(0,-10), width=1, orientation=90)
+ return [p1, p2, p3]
+
+ def create_ytron(self):
+ shape = YtronShape(rho=0.5, theta=5)
+ D = YtronDevice(shape=shape)
+ return spira.SRef(alias='ytron', reference=D)
+
+ def create_elements(self, elems):
+ p1, p2, p3 = self.get_io_ports()
+
+ elems += self.ytron
+
+ elems += spira.RouteManhattan(
+ ports=[self.ytron.ports['Pl_M1'], p1],
+ width=self.ytron.ref.shape.arm_widths[0],
+ layer=RDD.PLAYER.M1.METAL,
+ corners=self.corners)
+
+ elems += spira.RouteStraight(p1=p2,
+ p2=self.ytron.ports['Pr_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ elems += spira.RouteStraight(p1=p3,
+ p2=self.ytron.ports['Psrc_M1'],
+ layer=RDD.PLAYER.M1.METAL,
+ path_type='sine', width_type='sine')
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.get_io_ports()
+ return ports
+
+The figure below shows the output of the yTron PCell if the class was constructed inheriting from
+:py:class:`spira.PCell`. The metal layers are separated and the connection ports are still visible.
+
+.. image:: _figures/_adv_0_ytron_pcell.png
+ :align: center
+
+The following figure is the final result when inheriting from :py:class:`spira.Circuit`
+rather than :py:class:`spira.PCell`. The contacting metal layers are merged and the redundant ports are filtered.
+
+.. image:: _figures/_adv_0_ytron_circuit.png
+ :align: center
+
+From the code above we can see that three routes are defined.
+The first, connects the left arm with the first port using a basic manhattan structure.
+The second and third, connects the right arm to the second port and the source arm to the third port,
+but uses a ``sine`` path type to generate the routing polygons.
+
+
+**********
+Via Device
+**********
+
+Via devices generally following the same design patterns, but still require explicit construction
+to describe how PDK data should be handled on instance creation. This example illustrated the
+creation of the *alternative resistor via contact* that is responsible to connecting resistive
+layer ``R5`` to inductive layer ``M6``.
+
+Demonstrates
+============
+
+* How to create a via device.
+* How to add range restrictions to parameters.
+* How to create a cell that validates design rules on instance creation.
+
+Recall, that by definition a PCell script is responsible for describing the interrelations between
+layout elements and defined parameters. These parameters can be design restrictions imposed by the
+specific fabrication technology.
+
+.. code-block:: python
+
+ class ViaC5RA(spira.Device):
+ """ Via component for the MiTLL process. """
+
+ width = spira.NumberParameter(default=RDD.R5.MIN_SIZE, restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE))
+
+ height = spira.Parameter(fdef_name='create_height')
+ via_width = spira.Parameter(fdef_name='create_via_width')
+ via_height = spira.Parameter(fdef_name='create_via_height')
+
+ m6_width = spira.Parameter(fdef_name='create_m6_width', doc='Width of the via layer polygon.')
+ m6_height = spira.Parameter(fdef_name='create_m6_height', doc='Width of the via layer polygon.')
+
+ def create_m6_width(self):
+ return (self.via_width + 2*RDD.C5R.M6_MIN_SURROUND)
+
+ def create_via_width(self):
+ return (self.width + 2*RDD.C5R.R5_MAX_SIDE_SURROUND)
+
+ def create_via_height(self):
+ return RDD.C5R.MIN_SIZE
+
+ def create_height(self):
+ return self.via_height + 2*RDD.R5.C5R_MIN_SURROUND
+
+ def create_elements(self, elems):
+ elems += spira.Box(layer=RDD.PLAYER.C5R.VIA, width=self.via_width, height=self.via_height, enable_edges=False)
+ elems += spira.Box(alias='M6', layer=RDD.PLAYER.M6.METAL, width=self.m6_width, height=self.height, enable_edges=False)
+ elems += spira.Box(alias='R5', layer=RDD.PLAYER.R5.METAL, width=self.width, height=self.height, enable_edges=False)
+ return elems
+
+ def create_ports(self, ports):
+ p0 = self.elements['M6'].ports.unlock
+ p1 = self.elements['R5'].ports.unlock
+ return ports
+
+Thus, the code for the via PCell defined above is responsible for describing how the top and bottom metal layers
+must be constructed in relation to the contact layer without violating any design rules. The PCell defines the specific
+design rules applicable to the creation of this via device.
+
+
+********
+Resistor
+********
+
+In Single Flux Quantum (SFQ) logic circuits, we typically use a shunt resistance for the biasing section
+of the circuit. Therefore, we would want to create a single resistor PCell that can be used as a template
+in more complex circuit PCells. Here, we design a resistor that parameterized its width, length, and
+type of via connection to other metal layers.
+
+Demonstrates
+============
+
+* How to design a circuit that can interchange different via devices.
+* How to restrict the circuit to only accept vias of a certain type.
+* How to activate specific port edges that can be used for external connetions.
+
+This PCell can iterate between two different vias connections that connect metal layer ``R5`` and ``M6``;
+the *alternative* version of the *standard* version.
+
+.. code-block:: python
+
+ class Resistor(spira.Circuit):
+ """ Resistor PCell of type Circuit between two vias connecting to layer M6. """
+
+ length = spira.NumberParameter(default=7)
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE),
+ doc='Width of the shunt resistance.')
+ via = spira.CellParameter(
+ default=dev.ViaC5RS,
+ restriction=spira.RestrictType([dev.ViaC5RA, dev.ViaC5RS]),
+ doc='Via component for connecting R5 to M6')
+ text_type = spira.NumberParameter(default=92)
+
+ via_left = spira.Parameter(fdef_name='create_via_left')
+ via_right = spira.Parameter(fdef_name='create_via_right')
+
+ def validate_parameters(self):
+ if self.length < self.width:
+ raise ValueError('Length cannot be less than width.')
+ return True
+
+ def create_via_left(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90)
+ S = spira.SRef(via, transformation=T)
+ return S
+
+ def create_via_right(self):
+ via = self.via(width=0.3+self.width)
+ T = spira.Rotation(rotation=-90, rotation_center=(self.length, 0))
+ S = spira.SRef(via, midpoint=(self.length, 0), transformation=T)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += [self.via_left, self.via_right]
+
+ elems += RouteStraight(
+ p1=self.via_left.ports['E0_R5'],
+ p2=self.via_right.ports['E2_R5'],
+ layer=RDD.PLAYER.R5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+
+ ports += self.via_left.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.via_left.ports['E2_M6'].copy(name='P2_M6')
+ ports += self.via_left.ports['E3_M6'].copy(name='P3_M6')
+
+ ports += self.via_right.ports['E0_M6'].copy(name='P4_M6')
+ ports += self.via_right.ports['E1_M6'].copy(name='P5_M6')
+ ports += self.via_right.ports['E3_M6'].copy(name='P6_M6')
+
+ return ports
+
+The :py:data:`length` parameter can be any value as long as it is larger than the width. Therefore, the
+length parameter has no restrictions, but are validated once all parameters have been defined using the
+:py:data:`validate_parameters` method. The :py:data:`width` parameter is restricted to a minimum size,
+which implicitly mean the length is also restricted to this size value. The :py:data:`via` parameter
+has to be a PCell class and has to be of type :py:class:`dev.ViaC5RA` or :py:class:`dev.ViaC5RS`.
+
+We only want to connect to the connection vias of the instance, and therefore we only activate the ports
+of the two via instance, instead of activating all possible edge ports, as shown in the :py:data:`create_ports` method.
+
+******************
+Josephson Junction
+******************
+
+The Josephson junction is the most important device in any SDE circuit. We want to create a junction PCell
+that parameterizes the following device attributes:
+
+* The shunt resistor width.
+* The shunt resistor length.
+* The junction layer radius.
+* Boolean parameters to include/exclude via connections to ground and skyplane.
+
+Demonstrates
+============
+
+* How to design a fully parameterized Josephson junction.
+* How to add a bounding box around a set of polygon objects.
+
+The design of the junction is broken down into three sections; a top section, a bottom section, and the shunt
+resistor that connects the top and bottom sections. The top and bottom section each are wrapped with a
+bounding box polygon of metal layer ``M6``.
+
+.. code-block:: python
+
+ class __Junction__(spira.Cell):
+ """ Base class for Junction PCell. """
+
+ radius = spira.NumberParameter()
+ width = spira.NumberParameter(doc='Shunt resistance width')
+ c5r = spira.Parameter(fdef_name='create_c5r')
+
+
+ class I5Contacts(__Junction__):
+ """ Cell that contains all the vias of the bottom halve of the Junction. """
+
+ i5 = spira.Parameter(fdef_name='create_i5')
+ i6 = spira.Parameter(fdef_name='create_i6')
+
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5(self):
+ via = dev.ViaI5()
+ V = spira.SRef(via, midpoint=(0,0))
+ return V
+
+ def create_i6(self):
+ c = self.i5.midpoint
+ w = (self.i5.ref.width + 4*RDD.I6.I5_MIN_SURROUND)
+ via = dev.ViaI6(width=w, height=w)
+ V = spira.SRef(via, midpoint=c)
+ return V
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ if self.sky_via is True:
+ V.connect(port=V.ports['E0_R5'], destination=self.i6.ports['E2_M6'], ignore_process=True)
+ else:
+ V.connect(port=V.ports['E0_R5'], destination=self.i5.ports['E2_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.i5, self.c5r]
+
+ # Add the skyplane via instance if required.
+ if self.sky_via is True:
+ elems += self.i6
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.i5.ports['E2_M5'].copy(name='P2_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+
+ class J5Contacts(__Junction__):
+ """ Cell that contains all the vias of the top halve of the Junction. """
+
+ j5 = spira.Parameter(fdef_name='create_j5')
+
+ def create_j5(self):
+ jj = dev.JJ(width=2*self.radius)
+ D = spira.SRef(jj, midpoint=(0,0))
+ return D
+
+ def create_c5r(self):
+ # via = dev.ViaC5RA(width=self.width)
+ via = dev.ViaC5RS()
+ V = spira.SRef(via)
+ V.connect(port=V.ports['E0_R5'], destination=self.j5.ports['E0_M5'], ignore_process=True)
+ return V
+
+ def create_elements(self, elems):
+
+ # Add the two via instances.
+ elems += [self.j5, self.c5r]
+
+ # Add bounding box around all elements.
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M6.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M5'].copy(name='P0_M5')
+ ports += self.c5r.ports['E2_R5'].copy(name='P2_R5')
+ return ports
+
+The :py:class:`J5Contacts` and :py:class:`I5Contacts` classes are the top and bottom sections, respectively.
+The :py:class:`__Junction__` class is a base class that contains parameters common to both of these classes.
+As shown in the :py:data:`create_elements` methods for both classes a metal bounding box is added around
+all defined elements.
+
+The results for :py:class:`J5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a junction via that contains the actually junction layer.
+
+.. image:: _figures/_adv_junction_top.png
+ :align: center
+
+The result for :py:class:`I5Contacts` is shown below and consists of a ``C5R`` via that connects
+layer ``R5`` and a ``I5`` via that connects layer ``M5`` to layer ``M6``. The skyplane via that connects
+``M6`` to ``M7`` is optional depending on the boolean value of the :py:data:`sky_via` parameter.
+
+.. image:: _figures/_adv_junction_bot.png
+ :align: center
+
+.. code-block:: python
+
+ class Junction(spira.Device):
+
+ text_type = spira.NumberParameter(default=91)
+
+ length = spira.NumberParameter(default=1.5, doc='Length of the shunt resistance.')
+
+ width = spira.NumberParameter(
+ default=RDD.R5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE, upper=RDD.R5.MAX_WIDTH),
+ doc='Width of the shunt resistance.')
+
+ radius = spira.NumberParameter(
+ default=RDD.J5.MIN_SIZE,
+ restriction=spira.RestrictRange(lower=RDD.J5.MIN_SIZE, upper=RDD.J5.MAX_SIZE),
+ doc='Radius of the circular junction layer.')
+
+ i5 = spira.Parameter(fdef_name='create_i5_cell')
+ j5 = spira.Parameter(fdef_name='create_j5_cell')
+
+ gnd_via = spira.BoolParameter(default=False)
+ sky_via = spira.BoolParameter(default=False)
+
+ def create_i5_cell(self):
+ D = I5Contacts(width=self.width, radius=self.radius, sky_via=self.sky_via)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0, self.length))
+ return S
+
+ def create_j5_cell(self):
+ D = J5Contacts(width=self.width, radius=self.radius)
+ S = spira.SRef(D)
+ S.move(midpoint=S.ports['P2_R5'], destination=(0,0))
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.i5
+ elems += self.j5
+
+ elems += RouteStraight(
+ p1=self.i5.ports['P2_R5'].copy(width=self.width),
+ p2=self.j5.ports['P2_R5'].copy(width=self.width),
+ layer=RDD.PLAYER.R5.METAL)
+
+ if self.gnd_via is True:
+ i4 = dev.ViaI4()
+ elems += spira.SRef(i4, midpoint=m5_block.center)
+
+ box_shape = elems.bbox_info.bounding_box(margin=0.1)
+ elems += spira.Polygon(shape=box_shape, layer=RDD.PLAYER.M5.METAL)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.j5.ports['E0_M6'].copy(name='P0_M6')
+ ports += self.j5.ports['E1_M6'].copy(name='P1_M6')
+ ports += self.j5.ports['E3_M6'].copy(name='P3_M6')
+ ports += self.i5.ports['E1_M6'].copy(name='P4_M6')
+ ports += self.i5.ports['E2_M6'].copy(name='P5_M6')
+ ports += self.i5.ports['E3_M6'].copy(name='P6_M6')
+ return ports
+
+The :py:class:`Junction` class is created and instances of the :py:class:`J5Contacts` and :py:class:`I5Contacts`
+cells are added and moved relative to eachother with a separation distance equal to the length of the shunt resistor.
+The instances of of these two cells are then connection via a resistive route. For debugging purposes we can disable
+the operations preformed by the :py:class:`spira.Device` class by setting ``pcell=False``. The output is shown below
+displays the individual layers of each instance.
+
+.. image:: _figures/_adv_junction_false.png
+ :align: center
+
+By enabling PCell operations again we can see that the overlapping metal layers are merged by similar process
+polygon, as shown in the figure below.
+
+.. image:: _figures/_adv_junction_true.png
+ :align: center
+
+
+
+***************************
+Josephson Transmission Line
+***************************
+
+The Josephson Transmission Line (JTL) is the most basic SFQ circuit and consist of two junctions, an
+input and output port, and a biasing port.
+
+Demonstrates
+============
+
+* How to define routes between different ports and devices.
+* How to parameterize the route widths.
+* How to include a device PCell into higher hierarchical designs.
+
+We define three width parameters to control the polygon routing width between:
+
+1. The input port and first junction.
+2. The ouput port and second junction.
+3. The first junction and second junction.
+
+Next, we create a set of *create methods* to define device and port instances.
+
+.. code-block:: python
+
+ class Jtl(spira.PCell):
+
+ w1 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of left inductor.'
+ )
+ w2 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of middle inductor.'
+ )
+ w3 = spira.NumberParameter(
+ default=RDD.M6.MIN_SIZE,
+ restriction=RestrictRange(lower=RDD.M6.MIN_SIZE, upper=RDD.M6.MAX_WIDTH),
+ doc='Width of rigth inductor.'
+ )
+
+ p1 = spira.Parameter(fdef_name='create_p1')
+ p2 = spira.Parameter(fdef_name='create_p2')
+ p3 = spira.Parameter(fdef_name='create_p3')
+ p4 = spira.Parameter(fdef_name='create_p4')
+
+ jj1 = spira.Parameter(fdef_name='create_jj_left')
+ jj2 = spira.Parameter(fdef_name='create_jj_right')
+
+ shunt = spira.Parameter(fdef_name='create_shunt')
+
+ bias_res = spira.Parameter(fdef_name='create_bias_res')
+ via1 = spira.Parameter(fdef_name='create_via1')
+
+ def create_p1(self):
+ p1 = spira.Port(name='P1_M6', width=self.w1)
+ return p1.distance_alignment(port=p1, destination=self.jj1.ports['P1_M6'], distance=-10)
+
+ def create_p2(self):
+ p2 = spira.Port(name='P2_M6', width=self.w1)
+ return p2.distance_alignment(port=p2, destination=self.jj2.ports['P3_M6'], distance=10)
+
+ def create_p3(self):
+ return spira.Port(name='P3_M6', midpoint=(0, 15), orientation=270, width=self.w1)
+
+ def create_p4(self):
+ return spira.Port(name='P4_M6', midpoint=(0, 1.5), orientation=90, width=self.w1)
+
+ def create_jj_left(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(-10,0))
+ S = spira.SRef(jj, midpoint=(-10,0), transformation=T)
+ return S
+
+ def create_jj_right(self):
+ jj = dev.Junction(length=1.9, width=1, radius=0.91)
+ T = spira.Rotation(rotation=180, rotation_center=(10,0))
+ S = spira.SRef(jj, midpoint=(10,0), transformation=T)
+ return S
+
+ def create_shunt(self):
+ D = Resistor(width=1, length=3.7)
+ S = spira.SRef(reference=D, midpoint=(0,0))
+ S.distance_alignment(port='P2_M6', destination=self.p3, distance=-2.5)
+ return S
+
+ def create_elements(self, elems):
+
+ elems += self.jj1
+ elems += self.jj2
+ elems += self.shunt
+
+ elems += RouteStraight(p1=self.p1,
+ p2=self.jj1.ports['P1_M6'].copy(width=self.p1.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.p2,
+ p2=self.jj2.ports['P3_M6'].copy(width=self.p2.width),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(
+ p1=self.jj1.ports['P3_M6'].copy(width=self.w2),
+ p2=self.jj2.ports['P1_M6'].copy(width=self.w2),
+ layer=RDD.PLAYER.M6.ROUTE)
+
+ elems += RouteStraight(p1=self.shunt.ports['P2_M6'], p2=self.p3, layer=RDD.PLAYER.M6.ROUTE)
+ elems += RouteStraight(p1=self.shunt.ports['P4_M6'], p2=self.p4, layer=RDD.PLAYER.M6.ROUTE)
+
+ return elems
+
+ def create_ports(self, ports):
+ ports += self.p1
+ ports += self.p2
+ ports += self.p3
+ ports += self.p4
+ return ports
+
+This examples place two junctions, :py:data:`jj_left` and :py:data:`jj_right`, at positions (-10,0) and
+(10,0). The input port is placed a ditance of -10 to the left of :py:data:`jj_left`, and the ouput port
+a distance of 10 to the right of :py:data:`jj_right`.
+
+The biasing port, :py:data:`p3` is place at position (0,15) and port ``P2_M6`` of the biasing resistor PCell
+is place a distance of 2.5 to the bottom of :py:data:`p3`.
+
+.. image:: _figures/_adv_jtl_false.png
+ :align: center
+
+
+************************
+Electrical Rule Checking
+************************
+
+The electrical rule checking algorithm is applied on an instance using a filtering method.
+Therefore, it is easily enabled/disabled for debugging purposes.
+
+Demonstrates
+============
+
+* How to toggle the ERC algorithm.
+* How to view the electrical rule checking results using **virtual modeling**.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ f = RDD.FILTERS.PCELL.MASK
+
+ D = f(D)
+
+ from spira.yevon.vmodel.virtual import virtual_connect
+ v_model = virtual_connect(device=D)
+
+ v_model.view_virtual_connect(show_layers=True)
+
+.. image:: _figures/_adv_jtl_erc.png
+ :align: center
+
+The resultant layout or view of a cicuit that contains *virtual elements* that will not be included in the final design, is called a **virtual model**.
+The above example illustrates how electrical rule checking can be debugged using virtually constructed polygons.
+
+
+******************
+Netlist Extraction
+******************
+
+Netlists for PCells can be extracted and viewed in a graph representation.
+
+Demonstrates
+============
+
+* How to extract the netlist graph of a PCell.
+* How to view the extracted graph.
+
+.. code-block:: python
+
+ # Create an instance of the PCell class.
+ D = Jtl()
+
+ # Apply the ERC and Port Excitation algorithms to the cell.
+ D = RDD.FILTERS.PCELL.MASK(D)
+
+ # Extract the physical netlist.
+ net = D.extract_netlist
+
+ # View the netlist.
+ D.netlist_view(net=net)
+
+Before running the netlist extraction algorithm it is important to first apply the required filters to the pcell instance.
+These filters includes running electrical rule checking algorithm and compressing terminal ports down onto their corresponding polygon instances.
+It is also possible to toggle certain filters for debugging purposes:
+
+.. code-block:: python
+
+ D = Jtl()
+
+ f = RDD.FILTERS.PCELL.MASK
+
+ f['pin_attach'] = False
+
+ D = f(D)
+
+ net = D.extract_netlist
+
+ D.netlist_view(net=net)
+
+The above example illustrates the extracted netlist if the **pin attach** algorithm is disabled.
+The added terminal ports are not detected by the netlist run, since they are not compressed down the layout hierarchy onto their corresponding polygons.
+The following image shows the different extracted netlists for a basic JTL layout using the code snippets previously discussed.
+
+.. image:: _figures/_adv_jtl_net.png
+ :align: center
+
+
diff --git a/docs/_build/html/_static/_3_reference.rst b/docs/_build/html/_static/_3_reference.rst
new file mode 100644
index 00000000..a47c1b39
--- /dev/null
+++ b/docs/_build/html/_static/_3_reference.rst
@@ -0,0 +1,5 @@
+#########
+Reference
+#########
+
+
diff --git a/docs/_build/html/_static/_4_reference.rst b/docs/_build/html/_static/_4_reference.rst
new file mode 100644
index 00000000..a47c1b39
--- /dev/null
+++ b/docs/_build/html/_static/_4_reference.rst
@@ -0,0 +1,5 @@
+#########
+Reference
+#########
+
+
diff --git a/docs/_build/html/_static/_5_developers.rst b/docs/_build/html/_static/_5_developers.rst
new file mode 100644
index 00000000..1e3a224c
--- /dev/null
+++ b/docs/_build/html/_static/_5_developers.rst
@@ -0,0 +1,69 @@
+Developers
+==========
+
+Documentation for developers for maintaining and extending.
+
+Distribtuion
+------------
+
+Uploading package to PyPi using *twine*.
+Remember to remove all Eggs before doing a push to PyPi.
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 setup.py bdist_wheel
+ twine upload dist/*
+
+To install package systemwide set the prefix value when running setuptools:
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 setup.py install --prefix=/usr
+
+.. code-block:: bash
+ :linenos:
+
+ sudo python3 -m pip install --upgrade .
+
+* https://docs.python.org/3.3/install/index.html
+
+Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
+
+Documentation
+-------------
+
+If you want to generate the docs make sure the Napoleon package is installed:
+
+.. code-block:: bash
+ :linenos:
+
+ pip install sphinxcontrib-napoleon
+
+Coding standards for parsing the correct docs is given in:
+
+* https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
+
+* https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+Introduction to Python Virtual Enviroments:
+
+* https://realpython.com/python-virtual-environments-a-primer/
+* https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
+
+.. ---------------------------------------------------------------------------------------------
+
+Mixins
+------
+
+The following are useful links to some of the mixin implementations used in the SPiRA framework,
+
+* http://tobyho.com/2009/01/18/auto-mixin-in-python/
+* http://code.activestate.com/recipes/577730-mixin-and-overlay/
+* https://stackoverflow.com/questions/6966772/using-the-call-
+* method-of-a-metaclass-instead-of-new
+
+
+
+
diff --git a/docs/_build/html/_static/_figures/RouteConnect.png b/docs/_build/html/_static/_figures/RouteConnect.png
new file mode 100644
index 00000000..202b7875
Binary files /dev/null and b/docs/_build/html/_static/_figures/RouteConnect.png differ
diff --git a/docs/_build/html/_static/_figures/_3_layout.png b/docs/_build/html/_static/_figures/_3_layout.png
new file mode 100644
index 00000000..66051e2b
Binary files /dev/null and b/docs/_build/html/_static/_figures/_3_layout.png differ
diff --git a/docs/_build/html/_static/_figures/_4_ports_0.png b/docs/_build/html/_static/_figures/_4_ports_0.png
new file mode 100644
index 00000000..67f52142
Binary files /dev/null and b/docs/_build/html/_static/_figures/_4_ports_0.png differ
diff --git a/docs/_build/html/_static/_figures/_4_ports_0_enabled.png b/docs/_build/html/_static/_figures/_4_ports_0_enabled.png
new file mode 100644
index 00000000..6f26290a
Binary files /dev/null and b/docs/_build/html/_static/_figures/_4_ports_0_enabled.png differ
diff --git a/docs/_build/html/_static/_figures/_4_ports_1.png b/docs/_build/html/_static/_figures/_4_ports_1.png
new file mode 100644
index 00000000..842a40b3
Binary files /dev/null and b/docs/_build/html/_static/_figures/_4_ports_1.png differ
diff --git a/docs/_build/html/_static/_figures/_5_routes_0.png b/docs/_build/html/_static/_figures/_5_routes_0.png
new file mode 100644
index 00000000..fa2baba4
Binary files /dev/null and b/docs/_build/html/_static/_figures/_5_routes_0.png differ
diff --git a/docs/_build/html/_static/_figures/_6_hierarchy_0 b/docs/_build/html/_static/_figures/_6_hierarchy_0
new file mode 100644
index 00000000..cba03721
Binary files /dev/null and b/docs/_build/html/_static/_figures/_6_hierarchy_0 differ
diff --git a/docs/_build/html/_static/_figures/_6_hierarchy_0.png b/docs/_build/html/_static/_figures/_6_hierarchy_0.png
new file mode 100644
index 00000000..cba03721
Binary files /dev/null and b/docs/_build/html/_static/_figures/_6_hierarchy_0.png differ
diff --git a/docs/_build/html/_static/_figures/_6_hierarchy_1.png b/docs/_build/html/_static/_figures/_6_hierarchy_1.png
new file mode 100644
index 00000000..23f4c9eb
Binary files /dev/null and b/docs/_build/html/_static/_figures/_6_hierarchy_1.png differ
diff --git a/docs/_build/html/_static/_figures/_9_expanded.png b/docs/_build/html/_static/_figures/_9_expanded.png
new file mode 100644
index 00000000..71510e79
Binary files /dev/null and b/docs/_build/html/_static/_figures/_9_expanded.png differ
diff --git a/docs/_build/html/_static/_figures/_9_factor.png b/docs/_build/html/_static/_figures/_9_factor.png
new file mode 100644
index 00000000..a60600dc
Binary files /dev/null and b/docs/_build/html/_static/_figures/_9_factor.png differ
diff --git a/docs/_build/html/_static/_figures/_9_ports.png b/docs/_build/html/_static/_figures/_9_ports.png
new file mode 100644
index 00000000..3557c8bd
Binary files /dev/null and b/docs/_build/html/_static/_figures/_9_ports.png differ
diff --git a/docs/_build/html/_static/_figures/_9_transform.png b/docs/_build/html/_static/_figures/_9_transform.png
new file mode 100644
index 00000000..892bedea
Binary files /dev/null and b/docs/_build/html/_static/_figures/_9_transform.png differ
diff --git a/docs/_build/html/_static/_figures/_9_translate.png b/docs/_build/html/_static/_figures/_9_translate.png
new file mode 100644
index 00000000..2ff7e1f8
Binary files /dev/null and b/docs/_build/html/_static/_figures/_9_translate.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_0_ytron.png b/docs/_build/html/_static/_figures/_adv_0_ytron.png
new file mode 100644
index 00000000..ada91a91
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_0_ytron.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_0_ytron_circuit.png b/docs/_build/html/_static/_figures/_adv_0_ytron_circuit.png
new file mode 100644
index 00000000..69b2104d
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_0_ytron_circuit.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_0_ytron_pcell.png b/docs/_build/html/_static/_figures/_adv_0_ytron_pcell.png
new file mode 100644
index 00000000..6dde0f95
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_0_ytron_pcell.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_erc_jtl.png b/docs/_build/html/_static/_figures/_adv_erc_jtl.png
new file mode 100644
index 00000000..63cb81b4
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_erc_jtl.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_erc_jtl_m5.png b/docs/_build/html/_static/_figures/_adv_erc_jtl_m5.png
new file mode 100644
index 00000000..0cac9019
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_erc_jtl_m5.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_jtl_erc.png b/docs/_build/html/_static/_figures/_adv_jtl_erc.png
new file mode 100644
index 00000000..78717e2e
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_jtl_erc.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_jtl_false.png b/docs/_build/html/_static/_figures/_adv_jtl_false.png
new file mode 100644
index 00000000..e60a2bf5
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_jtl_false.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_jtl_net.png b/docs/_build/html/_static/_figures/_adv_jtl_net.png
new file mode 100644
index 00000000..644ee118
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_jtl_net.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_jtl_netlist.png b/docs/_build/html/_static/_figures/_adv_jtl_netlist.png
new file mode 100644
index 00000000..b71d6677
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_jtl_netlist.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_junction_bot.png b/docs/_build/html/_static/_figures/_adv_junction_bot.png
new file mode 100644
index 00000000..7f0852e2
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_junction_bot.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_junction_false.png b/docs/_build/html/_static/_figures/_adv_junction_false.png
new file mode 100644
index 00000000..8c828730
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_junction_false.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_junction_top.png b/docs/_build/html/_static/_figures/_adv_junction_top.png
new file mode 100644
index 00000000..7a711b61
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_junction_top.png differ
diff --git a/docs/_build/html/_static/_figures/_adv_junction_true.png b/docs/_build/html/_static/_figures/_adv_junction_true.png
new file mode 100644
index 00000000..9e5053ff
Binary files /dev/null and b/docs/_build/html/_static/_figures/_adv_junction_true.png differ
diff --git a/docs/_build/html/_static/_figures/_elements.png b/docs/_build/html/_static/_figures/_elements.png
new file mode 100644
index 00000000..b724d5f0
Binary files /dev/null and b/docs/_build/html/_static/_figures/_elements.png differ
diff --git a/docs/_build/html/_static/_figures/_group.png b/docs/_build/html/_static/_figures/_group.png
new file mode 100644
index 00000000..df08934a
Binary files /dev/null and b/docs/_build/html/_static/_figures/_group.png differ
diff --git a/docs/_build/html/_static/_figures/_ports.png b/docs/_build/html/_static/_figures/_ports.png
new file mode 100644
index 00000000..7efaa364
Binary files /dev/null and b/docs/_build/html/_static/_figures/_ports.png differ
diff --git a/docs/_build/html/_static/_figures/_routes.png b/docs/_build/html/_static/_figures/_routes.png
new file mode 100644
index 00000000..a2b599c1
Binary files /dev/null and b/docs/_build/html/_static/_figures/_routes.png differ
diff --git a/docs/_build/html/_static/_figures/spira_logo.png b/docs/_build/html/_static/_figures/spira_logo.png
new file mode 100644
index 00000000..d0815aee
Binary files /dev/null and b/docs/_build/html/_static/_figures/spira_logo.png differ
diff --git a/docs/_build/html/_static/ajax-loader.gif b/docs/_build/html/_static/ajax-loader.gif
deleted file mode 100644
index 61faf8ca..00000000
Binary files a/docs/_build/html/_static/ajax-loader.gif and /dev/null differ
diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css
index 104f076a..ea6972d5 100644
--- a/docs/_build/html/_static/basic.css
+++ b/docs/_build/html/_static/basic.css
@@ -4,7 +4,7 @@
*
* Sphinx stylesheet -- basic theme.
*
- * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@@ -231,6 +231,16 @@ a.headerlink {
visibility: hidden;
}
+a.brackets:before,
+span.brackets > a:before{
+ content: "[";
+}
+
+a.brackets:after,
+span.brackets > a:after {
+ content: "]";
+}
+
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
@@ -279,6 +289,12 @@ img.align-center, .figure.align-center, object.align-center {
margin-right: auto;
}
+img.align-default, .figure.align-default {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
.align-left {
text-align: left;
}
@@ -287,6 +303,10 @@ img.align-center, .figure.align-center, object.align-center {
text-align: center;
}
+.align-default {
+ text-align: center;
+}
+
.align-right {
text-align: right;
}
@@ -358,6 +378,11 @@ table.align-center {
margin-right: auto;
}
+table.align-default {
+ margin-left: auto;
+ margin-right: auto;
+}
+
table caption span.caption-number {
font-style: italic;
}
@@ -391,6 +416,16 @@ table.citation td {
border-bottom: none;
}
+th > p:first-child,
+td > p:first-child {
+ margin-top: 0px;
+}
+
+th > p:last-child,
+td > p:last-child {
+ margin-bottom: 0px;
+}
+
/* -- figures --------------------------------------------------------------- */
div.figure {
@@ -460,11 +495,58 @@ ol.upperroman {
list-style: upper-roman;
}
+li > p:first-child {
+ margin-top: 0px;
+}
+
+li > p:last-child {
+ margin-bottom: 0px;
+}
+
+dl.footnote > dt,
+dl.citation > dt {
+ float: left;
+}
+
+dl.footnote > dd,
+dl.citation > dd {
+ margin-bottom: 0em;
+}
+
+dl.footnote > dd:after,
+dl.citation > dd:after {
+ content: "";
+ clear: both;
+}
+
+dl.field-list {
+ display: grid;
+ grid-template-columns: fit-content(30%) auto;
+}
+
+dl.field-list > dt {
+ font-weight: bold;
+ word-break: break-word;
+ padding-left: 0.5em;
+ padding-right: 5px;
+}
+
+dl.field-list > dt:after {
+ content: ":";
+}
+
+dl.field-list > dd {
+ padding-left: 0.5em;
+ margin-top: 0em;
+ margin-left: 0em;
+ margin-bottom: 0em;
+}
+
dl {
margin-bottom: 15px;
}
-dd p {
+dd > p:first-child {
margin-top: 0px;
}
@@ -537,6 +619,12 @@ dl.glossary dt {
font-style: oblique;
}
+.classifier:before {
+ font-style: normal;
+ margin: 0.5em;
+ content: ":";
+}
+
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
diff --git a/docs/_build/html/_static/comment-bright.png b/docs/_build/html/_static/comment-bright.png
deleted file mode 100644
index 15e27edb..00000000
Binary files a/docs/_build/html/_static/comment-bright.png and /dev/null differ
diff --git a/docs/_build/html/_static/comment-close.png b/docs/_build/html/_static/comment-close.png
deleted file mode 100644
index 4d91bcf5..00000000
Binary files a/docs/_build/html/_static/comment-close.png and /dev/null differ
diff --git a/docs/_build/html/_static/comment.png b/docs/_build/html/_static/comment.png
deleted file mode 100644
index dfbc0cbd..00000000
Binary files a/docs/_build/html/_static/comment.png and /dev/null differ
diff --git a/docs/_build/html/_static/conf.py b/docs/_build/html/_static/conf.py
index 62b2d003..4396c2c7 100644
--- a/docs/_build/html/_static/conf.py
+++ b/docs/_build/html/_static/conf.py
@@ -2,31 +2,23 @@
import sys
sys.path.insert(0, os.path.abspath('.'))
-# -- General configuration ------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
# extensions = ['sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'sphinx.ext.napoleon']
extensions = ['sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc']
import sphinx_rtd_theme
-# from yuna import __version__
+from spira.settings import __version__, __release__
templates_path = ['_templates']
source_suffix = ['.rst', '.md']
-# source_suffix = '.rst'
master_doc = 'index'
project = u'SPiRA'
-copyright = u'2018, Ruben van Staden'
+copyright = u'2019, Ruben van Staden'
author = u'Ruben van Staden'
-# The short X.Y version.
-# version = __version__
-version = u'0.0.2'
-release = u'Auron'
+version = __version__
+release = __release__
language = None
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
@@ -34,80 +26,29 @@
todo_include_todos = True
html_theme = 'sphinx_rtd_theme'
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#
-# html_theme_options = {}
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['']
-# Custom sidebar templates, must be a dictionary that maps document names
-# to template names.
-#
-# This is required for the alabaster theme
-# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
- 'relations.html', # needs 'show_related': True theme option to display
+ 'relations.html',
'searchbox.html',
]
}
-
-# -- Options for HTMLHelp output ------------------------------------------
-
-# Output file base name for HTML help builder.
htmlhelp_basename = 'spiradoc'
+latex_elements = {}
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- #
- # 'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- #
- # 'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- #
- # 'preamble': '',
-
- # Latex figure (float) alignment
- #
- # 'figure_align': 'htbp',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title,
-# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'spira.tex', u'SPiRA Documentation',
u'Ruben van Staden', 'manual'),
]
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'spira', u'SPiRA Documentation',
[author], 1)
]
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'spira', u'SPiRA Documentation',
author, 'spira', 'One line description of project.',
diff --git a/docs/_build/html/_static/css/badge_only.css b/docs/_build/html/_static/css/badge_only.css
index 323730ae..3c33cef5 100644
--- a/docs/_build/html/_static/css/badge_only.css
+++ b/docs/_build/html/_static/css/badge_only.css
@@ -1 +1 @@
-.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
+.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
diff --git a/docs/_build/html/_static/css/theme.css b/docs/_build/html/_static/css/theme.css
index b19dbfe5..aed8cef0 100644
--- a/docs/_build/html/_static/css/theme.css
+++ b/docs/_build/html/_static/css/theme.css
@@ -1,6 +1,6 @@
-/* sphinx_rtd_theme version 0.4.2 | MIT license */
-/* Built 20181005 13:10 */
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*!
+/* sphinx_rtd_theme version 0.4.3 | MIT license */
+/* Built 20190212 16:02 */
+*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*!
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")}
+ */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content .code-block-caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content .code-block-caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#3a7ca8;height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin:12px 0 0 0;display:block;font-weight:bold;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after,.rst-content .code-block-caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after,.rst-content .code-block-caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")}
diff --git a/docs/_build/html/_static/developers.rst b/docs/_build/html/_static/developers.rst
index 76837c85..6ee0e8a8 100644
--- a/docs/_build/html/_static/developers.rst
+++ b/docs/_build/html/_static/developers.rst
@@ -4,69 +4,69 @@ Developers
Documentation for developers for maintaining and extending. Extra information is added
to better understand specific code implementations.
-Distribtuion
-------------
+.. Distribtuion
+.. ------------
-Uploading package to PyPi using *twine*.
-Remember to remove all Eggs before doing a push to PyPi.
+.. Uploading package to PyPi using *twine*.
+.. Remember to remove all Eggs before doing a push to PyPi.
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 setup.py bdist_wheel
- twine upload dist/*
+.. sudo python3 setup.py bdist_wheel
+.. twine upload dist/*
-To install package systemwide set the prefix value when running setuptools:
+.. To install package systemwide set the prefix value when running setuptools:
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 setup.py install --prefix=/usr
+.. sudo python3 setup.py install --prefix=/usr
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- sudo python3 -m pip install --upgrade .
+.. sudo python3 -m pip install --upgrade .
-* https://docs.python.org/3.3/install/index.html
+.. * https://docs.python.org/3.3/install/index.html
-Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
+.. Unit testing overview: http://docs.python-guide.org/en/latest/writing/tests/
-Documentation
--------------
+.. Documentation
+.. -------------
-If you want to generate the docs make sure the Napoleon package is installed:
+.. If you want to generate the docs make sure the Napoleon package is installed:
-.. code-block:: bash
- :linenos:
+.. .. code-block:: bash
+.. :linenos:
- pip install sphinxcontrib-napoleon
+.. pip install sphinxcontrib-napoleon
-Coding standards for parsing the correct docs is given in:
+.. Coding standards for parsing the correct docs is given in:
-* https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
+.. * https://sphinxcontrib-napoleon.readthedocs.io/en/latest/
-* https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+.. * https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
-Introduction to Python Virtual Enviroments:
+.. Introduction to Python Virtual Enviroments:
-* https://realpython.com/python-virtual-environments-a-primer/
-* https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
+.. * https://realpython.com/python-virtual-environments-a-primer/
+.. * https://stackoverflow.com/questions/15746675/how-to-write-a-python-module-package
-.. ---------------------------------------------------------------------------------------------
+.. .. ---------------------------------------------------------------------------------------------
-Mixins
-------
+.. Mixins
+.. ------
-The following are useful links to some of the mixin implementations used in the SPiRA framework,
+.. The following are useful links to some of the mixin implementations used in the SPiRA framework,
-* http://tobyho.com/2009/01/18/auto-mixin-in-python/
-* http://code.activestate.com/recipes/577730-mixin-and-overlay/
-* https://stackoverflow.com/questions/6966772/using-the-call-
-* method-of-a-metaclass-instead-of-new
+.. * http://tobyho.com/2009/01/18/auto-mixin-in-python/
+.. * http://code.activestate.com/recipes/577730-mixin-and-overlay/
+.. * https://stackoverflow.com/questions/6966772/using-the-call-
+.. * method-of-a-metaclass-instead-of-new
-Metaprogramming
----------------
+.. Metaprogramming
+.. ---------------
diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js
index ffadbec1..b33f87fc 100644
--- a/docs/_build/html/_static/doctools.js
+++ b/docs/_build/html/_static/doctools.js
@@ -4,7 +4,7 @@
*
* Sphinx JavaScript utilities for all documentation.
*
- * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@@ -87,14 +87,13 @@ jQuery.fn.highlightText = function(text, className) {
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
- var bbox = span.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
- rect.x.baseVal.value = bbox.x;
+ var bbox = node.parentElement.getBBox();
+ rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
- var parentOfText = node.parentNode.parentNode;
addItems.push({
"parent": node.parentNode,
"target": rect});
diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js
index c194d755..1ae4a629 100644
--- a/docs/_build/html/_static/documentation_options.js
+++ b/docs/_build/html/_static/documentation_options.js
@@ -1,296 +1,10 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
- VERSION: 'Auron',
+ VERSION: 'Auron [Beta]',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
- NAVIGATION_WITH_KEYS: false,
- SEARCH_LANGUAGE_STOP_WORDS: ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]
-};
-
-
-
-/* Non-minified version JS is _stemmer.js if file is provided */
-/**
- * Porter Stemmer
- */
-var Stemmer = function() {
-
- var step2list = {
- ational: 'ate',
- tional: 'tion',
- enci: 'ence',
- anci: 'ance',
- izer: 'ize',
- bli: 'ble',
- alli: 'al',
- entli: 'ent',
- eli: 'e',
- ousli: 'ous',
- ization: 'ize',
- ation: 'ate',
- ator: 'ate',
- alism: 'al',
- iveness: 'ive',
- fulness: 'ful',
- ousness: 'ous',
- aliti: 'al',
- iviti: 'ive',
- biliti: 'ble',
- logi: 'log'
- };
-
- var step3list = {
- icate: 'ic',
- ative: '',
- alize: 'al',
- iciti: 'ic',
- ical: 'ic',
- ful: '',
- ness: ''
- };
-
- var c = "[^aeiou]"; // consonant
- var v = "[aeiouy]"; // vowel
- var C = c + "[^aeiouy]*"; // consonant sequence
- var V = v + "[aeiou]*"; // vowel sequence
-
- var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
- var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
- var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
- var s_v = "^(" + C + ")?" + v; // vowel in stem
-
- this.stemWord = function (w) {
- var stem;
- var suffix;
- var firstch;
- var origword = w;
-
- if (w.length < 3)
- return w;
-
- var re;
- var re2;
- var re3;
- var re4;
-
- firstch = w.substr(0,1);
- if (firstch == "y")
- w = firstch.toUpperCase() + w.substr(1);
-
- // Step 1a
- re = /^(.+?)(ss|i)es$/;
- re2 = /^(.+?)([^s])s$/;
-
- if (re.test(w))
- w = w.replace(re,"$1$2");
- else if (re2.test(w))
- w = w.replace(re2,"$1$2");
-
- // Step 1b
- re = /^(.+?)eed$/;
- re2 = /^(.+?)(ed|ing)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- re = new RegExp(mgr0);
- if (re.test(fp[1])) {
- re = /.$/;
- w = w.replace(re,"");
- }
- }
- else if (re2.test(w)) {
- var fp = re2.exec(w);
- stem = fp[1];
- re2 = new RegExp(s_v);
- if (re2.test(stem)) {
- w = stem;
- re2 = /(at|bl|iz)$/;
- re3 = new RegExp("([^aeiouylsz])\\1$");
- re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
- if (re2.test(w))
- w = w + "e";
- else if (re3.test(w)) {
- re = /.$/;
- w = w.replace(re,"");
- }
- else if (re4.test(w))
- w = w + "e";
- }
- }
-
- // Step 1c
- re = /^(.+?)y$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(s_v);
- if (re.test(stem))
- w = stem + "i";
- }
-
- // Step 2
- re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- suffix = fp[2];
- re = new RegExp(mgr0);
- if (re.test(stem))
- w = stem + step2list[suffix];
- }
-
- // Step 3
- re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- suffix = fp[2];
- re = new RegExp(mgr0);
- if (re.test(stem))
- w = stem + step3list[suffix];
- }
-
- // Step 4
- re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
- re2 = /^(.+?)(s|t)(ion)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(mgr1);
- if (re.test(stem))
- w = stem;
- }
- else if (re2.test(w)) {
- var fp = re2.exec(w);
- stem = fp[1] + fp[2];
- re2 = new RegExp(mgr1);
- if (re2.test(stem))
- w = stem;
- }
-
- // Step 5
- re = /^(.+?)e$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(mgr1);
- re2 = new RegExp(meq1);
- re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
- if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
- w = stem;
- }
- re = /ll$/;
- re2 = new RegExp(mgr1);
- if (re.test(w) && re2.test(w)) {
- re = /.$/;
- w = w.replace(re,"");
- }
-
- // and turn initial Y back to y
- if (firstch == "y")
- w = firstch.toLowerCase() + w.substr(1);
- return w;
- }
-}
-
-
-
-
-
-var splitChars = (function() {
- var result = {};
- var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
- 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
- 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
- 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
- 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
- 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
- 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
- 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
- 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
- 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
- var i, j, start, end;
- for (i = 0; i < singles.length; i++) {
- result[singles[i]] = true;
- }
- var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
- [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
- [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
- [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
- [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
- [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
- [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
- [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
- [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
- [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
- [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
- [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
- [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
- [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
- [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
- [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
- [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
- [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
- [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
- [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
- [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
- [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
- [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
- [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
- [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
- [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
- [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
- [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
- [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
- [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
- [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
- [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
- [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
- [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
- [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
- [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
- [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
- [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
- [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
- [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
- [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
- [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
- [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
- [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
- [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
- [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
- [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
- [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
- [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
- for (i = 0; i < ranges.length; i++) {
- start = ranges[i][0];
- end = ranges[i][1];
- for (j = start; j <= end; j++) {
- result[j] = true;
- }
- }
- return result;
-})();
-
-function splitQuery(query) {
- var result = [];
- var start = -1;
- for (var i = 0; i < query.length; i++) {
- if (splitChars[query.charCodeAt(i)]) {
- if (start !== -1) {
- result.push(query.slice(start, i));
- start = -1;
- }
- } else if (start === -1) {
- start = i;
- }
- }
- if (start !== -1) {
- result.push(query.slice(start));
- }
- return result;
-}
-
-
+ NAVIGATION_WITH_KEYS: false
+};
\ No newline at end of file
diff --git a/docs/_build/html/_static/down-pressed.png b/docs/_build/html/_static/down-pressed.png
deleted file mode 100644
index 5756c8ca..00000000
Binary files a/docs/_build/html/_static/down-pressed.png and /dev/null differ
diff --git a/docs/_build/html/_static/down.png b/docs/_build/html/_static/down.png
deleted file mode 100644
index 1b3bdad2..00000000
Binary files a/docs/_build/html/_static/down.png and /dev/null differ
diff --git a/docs/_build/html/_static/framework.rst b/docs/_build/html/_static/framework.rst
new file mode 100644
index 00000000..5219fea2
--- /dev/null
+++ b/docs/_build/html/_static/framework.rst
@@ -0,0 +1,491 @@
+#########
+Framework
+#########
+
+
+
+******************
+Process Design Kit
+******************
+
+The process design kit (PDK) is a set of technology files needed to implement
+the physical aspects of a layout design. Application-specific rules specified
+in the PDK controls how physical design applications work.
+
+A new PDK scheme is introduced. The Python programming language is used to
+bind PDK data to a set of classes, called data trees, that uniquely categorises
+PDK data. This new PDK scheme is called the Rule Deck Database (RDD), also
+refered to as the Rule Design Database. By having a native PDK in Python it
+becomes possible to use methods from the SPiRA framework to create a
+more descriptive PDK database. A design process typically contains the
+following aspects:
+
+* *GDSII Data*: Contains general settings required by the GDSII library, such as grid size.
+* *Process Data*: Contains the process layers, layer purposes, layer parameters, and layer mappings.
+* *Virtual Modelling*: Define derived layers that describes layer boolean operations.
+
+
+Initialization
+==============
+
+All caps are used to represent the *RDD* syntax. The reason being to make the
+script structure clearly distinguishable from the rest of the framework source
+code. First, the RDD object is initialized, followed by the process name and
+description. Second, the GDSII related variables are defined.
+
+.. code-block:: python
+
+ RDD.GDSII = ParameterDatabase()
+ RDD.GDSII.UNIT = 1e-6
+ RDD.GDSII.GRID = 1e-12
+ RDD.GDSII.PRECISION = 1e-9
+
+
+Process Data
+============
+
+.. ---------- Define Processes ----------
+
+Define Processes
+----------------
+
+The first step in creating a layer is to define the process step that
+it represents in mask fabrication. The layer process defines a specific
+fabrciation function, for examples **metalization**. There can be multiple
+different drawing layers for a single process. A *Process* database object
+is created that contains all the different process steps in a specific
+fabrication process:
+
+.. code-block:: python
+
+ RDD.PROCESS = ProcessLayerDatabase()
+
+ RDD.PROCESS.GND = ProcessLayer(name='Ground Plane', symbol='GND')
+ RDD.PROCESS.SKY = ProcessLayer(name='Sky Plane', symbol='SKY')
+ RDD.PROCESS.R5 = ProcessLayer(name='Resistor 1', symbol='R5')
+ RDD.PROCESS.M1 = ProcessLayer(name='Metal 1', symbol='M1')
+
+Each process has a name that describes the process function, and
+a *symbol* that is used to identify the process.
+
+.. ---------- Define Purposes ----------
+
+The purpose indicates the use of the layer. Multiple layers with
+the same process but different purposes can be created. Purposes are defined
+using a *Purpose* database object:
+
+.. code-block:: python
+
+ RDD.PURPOSE = PurposeLayerDatabase()
+
+ RDD.PURPOSE.GROUND = PurposeLayer(name='Ground plane polygons', symbol='GND')
+ RDD.PURPOSE.METAL = PurposeLayer(name='Polygon metals', symbol='METAL')
+ RDD.PURPOSE.ROUTE = PurposeLayer(name='Metal routes', symbol='ROUTE')
+ RDD.PURPOSE.RESISTOR = PurposeLayer(name='Polygon resistor', symbol='RES')
+
+Similar to a **process** value each purpose contains a name and a unique symbol.
+
+.. ---------- Process Parameters ----------
+
+Parameters are added to a process by creating a *parameter* database object
+that has a key value equal to the symbol of a pre-defined process:
+
+.. code-block:: python
+
+ RDD.M5 = ParameterDatabase()
+ RDD.M5.MIN_SIZE = 0.7
+ RDD.M5.MAX_WIDTH = 20.0
+ RDD.M5.J5_MIN_SURROUND = 0.5
+ RDD.M5.MIN_SURROUND_OF_I5 = 0.5
+
+Any number of variables can be added to the tree using the dot operator.
+The code above defines a set of design parameters for the *M5* process.
+
+.. ---------- Physical Layers ----------
+
+*Physical Layers* are unique to SPiRA and is defined as a layer that has a
+defined process and purpose. A physical layer (PLayer) defines the different
+purposes that a single process can be used for in a layout design.
+
+.. code-block:: python
+
+ RDD.PLAYER.M6 = PhysicalLayerDatabase()
+
+ RDD.PLAYER.I5.VIA = PhysicalLayer(process=RDD.PROCESS.I5, purpose=RDD.PURPOSE.VIA)
+
+ RDD.PLAYER.M6.METAL = PhysicalLayer(process=RDD.PROCESS.M6, purpose=RDD.PURPOSE.METAL)
+ RDD.PLAYER.M6.HOLE = PhysicalLayer(process=RDD.PROCESS.M6, purpose=RDD.PURPOSE.HOLE)
+
+The code above illustrated the different purposes that process layer
+**M6** can have in a layout design.
+
+Virtual Modelling
+~~~~~~~~~~~~~~~~~
+
+*Derived Layers* are used to define different PLayer boolean operations.
+They are typically used for virtual modelling and polygon operations,
+such as merged polygons or polygon holes.
+
+.. code-block:: python
+
+ RDD.PLAYER.M5.EDGE_CONNECTED = RDD.PLAYER.M5.METAL & RDD.PLAYER.M5.OUTSIDE_EDGE_DISABLED
+ RDD.PLAYER.M6.EDGE_CONNECTED = RDD.PLAYER.M6.METAL & RDD.PLAYER.M6.OUTSIDE_EDGE_DISABLED
+
+The code above defines a derived layer that is generated when a layer with
+process **M5** and purpose metal overlaps the outside edges of a all
+process **M5** layers.
+
+
+.. ---------------------------------------------------------------
+
+
+Parameters
+----------
+
+When we’re designing PCells we need to model its parameters. An important characteristic
+of a parameter is that it often only accepts a select range of values. When the parameter
+corresponds to something physical the value often makes no sense when it’s zero or negative.
+To avoid that users create designs which have no meaning, we want to inhibit that the user
+assigns an invalid value to the parameter. This is exactly what we use properties for:
+restricting the range and type of values you can assign to a parameter
+
+In addition IPKISS’ properties help you as well with the following tasks:
+
+* providing defaults for your parameters
+* adding documentation for your parameters
+* implement caching to ensure that calculations don’t need to be run twice ( when not required )
+
+Define Parameters
+~~~~~~~~~~~~~~~~~
+
+Parameters are derived from the ``Parameter`` class. The
+``ParameterInitializer`` is responsible for storing the parameters of an
+instance. To define parameters the class has to inherit from the ``ParameterInitializer``
+class. The following code creates a layer object with a number as a parameter.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter()
+
+ >>> layer = Layer(number=9)
+ >>> layer.number
+ 9
+
+At first glance this may not seem to add any value that default Python already adds.
+The same example can be generated using native Python:
+
+.. code-block:: python
+
+ class Layer(object):
+ def __init__(self, number=0):
+ self.number = number
+
+The true value of the parameterized framework comes into play when adding
+parameter attributes, such as the **default** value, **restrictions**,
+**preprocess** and **doc**. With these attributes parameters can be
+type-checked and documented using customized values.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.INTEGER,
+ preprocess=spira.ProcessorInt(),
+ doc='Advanced parameter.')
+
+The newly defined parameter has more advanced features that makes for
+a more powerful design framework:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number
+ 0
+ >>> layer.number = 9
+ >>> layer.number
+ 9
+ >>> layer.number = '8'
+ >>> layer.number
+ 8
+ >>> layer.number = 'Hi'
+ ValueError:
+
+
+Default
+~~~~~~~
+
+When defining a parameter the default value can be explicitly set using
+the ``default`` attribute. This is a simple method of declaring your parameter.
+For more complex functionality the default function attribute, ``fdef_name``,
+can be used. This attribute defines the name of a class method that is used To
+derive the default value of the parameter. Advantages of this technique is:
+
+* **Logic operations:** The default value can be derived from other defined parameters.
+* **Inheritance:** The default value can be overwritten using class inheritance.
+
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0)
+ datatype = spira.Parameter(fdef_name='create_datatype')
+
+ def create_datatype(self):
+ return 1
+
+ >>> layer = Layer()
+ >>> (layer.number, layer.datatype)
+ (0, 1)
+
+
+Restrictions
+~~~~~~~~~~~~
+
+**Restrictions** are Python objects that validates the received value of a parameter.
+In certain cases we want to restrict a parameter value to a certain type or range
+of values, for example:
+
+* Validate that the value is of specific object.
+* Validate that the value falls between then minimum and maximum.
+
+.. code-block:: python
+
+ import spira.all as spira
+ class Layer(spira.ParameterInitializer):
+ number = spira.Parameter(default=0,
+ restrictions=spira.RestrictRange(2,5))
+
+The example above restricts the number parameter of the layer to be between 2 and 5:
+
+.. code-block:: python
+
+ >>> layer = Layer()
+ >>> layer.number = 3
+ 3
+ >>> layer.number = 1
+ ValueError:
+
+Preprocessors
+~~~~~~~~~~~~~
+
+**Preprocessors** converts a received value before assigning it to the parameter.
+Preprocessors are typically used to convert a value of invalid type to one of
+a valid type, such as converting a float to an integer.
+
+Cache
+~~~~~
+
+SPiRA automatically caches parameters once they have been initialized.
+When using class methods to define default parameters using the ``fdef_name``
+attribute, the value is stored when called for the first time. Calling this
+value for the second time will not lead to a re-calculation, but rather the
+value will be retrieved from the cached dictionary.
+
+The cache is automatically cleared when **any** parameter in the class is
+updated, since other parameters might be dependent on the changed parameters.
+
+.. ---------------------------------------------------------------
+
+Parameterized Cells
+-------------------
+
+The SPiRA definition of a Parameterized Cell (PCell) in general terms:
+
+ A PCell is a cell that defines how layout elementals must be generated.
+ When instantiated it constructs itself according to the defined parameters.
+
+GDSII layouts encapsulate elemental design in the visual domain. Parameterized cells encapsulates elementals in the programming domain, and utilizes this domain to map external data to elementals.
+This external data can be data from the PDK or values extracted from an already designed layout using simulation software, such as InductEx.
+The SPiRA framework uses a scripting framework approach to connect the visual domain with a programming domain.
+The implemented architecture of SPiRA mimics the physical layout patterns implicit in hand-designed layouts.
+This framework architecture evolved by developing code heuristics that emerged from the process of creating a PCell.
+
+Creating a PCell is done by defining the elements and parameters required to create the desired layout.
+The relationship between the elements and parameters are described in a template format.
+Template design is an innate feature of parameterizing cell layouts.
+This heuristic concludes to develop a framework to effectively describe the different constituents of a PCell, rather than developing an API.
+The SPiRA framework was built from the following concepts:
+
+1. **Defining Element Shapes** This step defines the geometrical shapes from which an element polygon is generated.
+The supported shapes are rectangles, triangles, circles, as well as regular and irregular polygons.
+Each of these shapes has a set of parameters that control the pattern dimensions, e.g. the parameterized rectangle has two parameters, width and length , that defines its length and width, respectively.
+
+2. **Element Shape Transformations** This step describes the relation between the elements through a set of operations, that includes transformations of a shape in the x-y plane.
+Transforming an element involves: movement with a specific offset relative to its original location, rotation of a shape around its center with a specific angle,
+reflection of a shape around a idefined line, and aligning a shape to another shape with a specific offset and angle.
+
+3. **PDK Binding** The final step is binding data from the PDK to each created pattern. In SPiRA data from the PDK is parsed into the RDD.
+From this database the required process data can be linked to any specific pattern, such as the layer type of the defined rectangle, by defining
+parameters and placing design restrictions on them.
+
+Shapes
+~~~~~~
+
+
+.. code-block:: python
+
+ class ShapeExample(spira.Cell):
+
+ def create_elementals(self, elems):
+ pts = [[0, 0], [2, 2], [2, 6], [-6, 6], [-6, -6], [-4, -4], [-4, 4], [0, 4]]
+ shape = spira.Shape(points=pts)
+ elems += spira.Polygon(shape=shape, layer=spira.Layer(1))
+ return elems
+
+
+Elements
+~~~~~~~~
+
+In the aboth example the ``spira.Polygon`` class was used to connect the shape with GDSII-related data, such as a layer number.
+This is the purpose of elementals; to wrap geometry data with GDSII layout data.
+In SPiRA the following elementals are defined:
+
+* **Polygon**: Connects a shape object with layout data (layer number, datatype).
+* **Label**: Generates text data in a GDSII layout.
+* **SRef**: A structure references, or sometimes called a cell reference, refers to another cell object, but with difference transformations.
+
+There are other special shapes that can be used in the pattern creation.
+These shapes are mainly a combination polygons and relations between polygons.
+These special shapes are referenced as if they represent a single shape and its outline is determined by its bounding box dimensions.
+The following elemental groups are defined in the SPiRA framework:
+
+* **Cells**: Is the most generic group that binds different parameterized elementals or clusters, while conserving the geometrical relations between these polygons or clusters.
+* **Group**: A set of elementals can be grouped in a logical container, called ``Group``.
+* **Ports**: A port is simply a polygon with a label on a dedicated process layer. Typically, port elementals are placed on conducting metal layers.
+* **Routes**: A route is defined as a cell that consists of a polygon elemental and a set of edge ports, that resembles a path-like structure.
+
+Group
+~~~~~
+
+Groups are used to apply an operation on a set of polygons, such a retrieving their combined bounding box.
+The following example illistrated the use of ``Group`` to generate a metal bounding box around a set of polygons:
+
+.. code-block:: python
+
+ class GroupExample(spira.Cell):
+
+ def create_elementals(self, elems):
+
+ group = spira.Group()
+ group += spira.Rectangle(p1=(0,0), p2=(10,10), layer=spira.Layer(1))
+ group += spira.Rectangle(p1=(0,15), p2=(10,30), layer=spira.Layer(1))
+
+ group.transform(spira.Rotation(45))
+
+ elems += group
+
+ bbox_shape = group.bbox_info.bounding_box(margin=1)
+ elems += spira.Polygon(shape=bbox_shape, layer=spira.Layer(2))
+
+ return elems
+
+Ports
+~~~~~
+
+Port objects are unique to the SPiRA framework and are mainly used for connection purposes.
+
+.. code-block:: python
+
+ class PortExample(spira.Cell):
+
+ def create_elementals(self, elems):
+ elems += spira.Rectangle(p1=(0,0), p2=(20,5), layer=spira.Layer(1))
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='P1', midpoint=(0,2.5), orientation=180)
+ ports += spira.Port(name='P2', midpoint=(20,2.5), orientation=0)
+ return ports
+
+Routes
+~~~~~~
+
+
+
+PCell creation is broken down into the following basic steps:
+
+.. code-block:: python
+
+ class PCell(spira.Cell):
+ """ My first parameterized cell. """
+
+ # Define parameters here.
+ number = spira.IntegerParameter(default=0, doc=’Parameter example number.’)
+
+ def create_elementals(self, elems):
+ # Define elementals here.
+ return elems
+
+ def create_ports(self, ports):
+ # Define ports here.
+ return ports
+
+.. code-block:: python
+
+ >>> pcell = PCell()
+ [SPiRA: Cell] (name ’PCell’, elementals 0, ports 0)
+ >>> pcell.number
+ 0
+ >>> pcell.__doc__
+ My first parameterized cell.
+ >>> pcell.number.__doc__
+ Parameter example number.
+
+The most basic SPiRA template to generate a PCell is shown above, and consists of three parts:
+
+1. Create a new cell by inheriting from ``spira.Cell``. This connects the class to the SPiRA framework when constructed.
+
+2. Define the PCell parameters as class attributes.
+
+3. Elementals and ports are defined in the ``create_elementals`` and ``create_ports`` class methods, which is automatically added to the cell instance.
+ The create methods are special SPiRA class methods that specify how the parameters are used to create the cell.
+
+
+.. code-block:: python
+
+ class Box(spira.Cell):
+
+ width = param. NumberField(default=1)
+ height = param. NumberField(default=1)
+ gds_layer = param. LayerField(number=0, datatype=0)
+
+ def create_elementals(self, elems):
+ shape = shapes.BoxShape(width=self.width, height=self.height)
+ elems += spira.Polygon(shape=shape, gds_layer=self.gds_layer)
+ return elems
+
+ def create_ports(self, ports):
+ ports += spira.Port(name='Input', midpoint=(-0.5,0), orientation=90)
+ ports += spira.Port(name='Output', midpoint=(0.5,0), orientation=270)
+ return ports
+
+.. code-block:: python
+
+ >>> box = Box()
+ [SPiRA: Cell] (name ’Box ’, width 1, height 1, number 0, datatype 0)
+ >>> box.width
+ 1
+ >>> box. height
+ 1
+ >>> box. gds_layer
+ [SPiRA Layer] (name ’’, number 0, datatype 0)
+
+
+The above example illustrates constructing a parameterized box using the proposed framework:
+First, defining the parameters that the user would want to change when creating a box instance.
+Here, three parameter are given namely, the width, the height and the layer properties for GDSII construction.
+Second, a shape is generated from the defined parameters using the shape module.
+Third, this box shape is added as a polygon elemental to the cell instance.
+This polygon takes the shape and connects it to a set of methods responsible for converting it to a GDSII elemental.
+Fourth, two terminal ports are added to the left and right edges of the box, with their directions pointing away from the polygon interior.
+
+
+Validate-by-Design
+------------------
+
+
+
diff --git a/docs/_build/html/_static/gdsii.rst b/docs/_build/html/_static/gdsii.rst
index 52d2ef6c..f90782d0 100644
--- a/docs/_build/html/_static/gdsii.rst
+++ b/docs/_build/html/_static/gdsii.rst
@@ -2,28 +2,28 @@ GDSII Elementals
################
-Classes
-*******
+.. Classes
+.. *******
-.. .. py:function:: create_elements
-.. Creates an elemental.
+.. .. .. py:function:: create_elements
+.. .. Creates an elemental.
-.. .. function:: format_exception(etype, value, tb[, limit=None])
+.. .. .. function:: format_exception(etype, value, tb[, limit=None])
-.. Format the exception with a traceback.
+.. .. Format the exception with a traceback.
-.. :param etype: exception type
-.. :param value: exception value
-.. :param tb: traceback object
-.. :param limit: maximum number of stack frames to show
-.. :type limit: integer or None
-.. :rtype: list of strings
+.. .. :param etype: exception type
+.. .. :param value: exception value
+.. .. :param tb: traceback object
+.. .. :param limit: maximum number of stack frames to show
+.. .. :type limit: integer or None
+.. .. :rtype: list of strings
-.. autoclass:: spira.Cell
- :members:
- :undoc-members:
-.. :inherited-members:
-.. :show-inheritance:
+.. .. autoclass:: spira.Cell
+.. :members:
+.. :undoc-members:
+.. .. :inherited-members:
+.. .. :show-inheritance:
diff --git a/docs/_build/html/_static/gettingstarted.rst b/docs/_build/html/_static/gettingstarted.rst
new file mode 100644
index 00000000..6528e547
--- /dev/null
+++ b/docs/_build/html/_static/gettingstarted.rst
@@ -0,0 +1,46 @@
+Getting Started
+===============
+
+GDSII files contain a hierarchical representation of any polygonal geometry.
+They are mainly used in the microelectronics industry for the design of mask layouts, but are also employed in other areas.
+
+Because it is a hierarchical format, repeated structures, such as identical transistors, can be defined once and referenced multiple times in the layout, reducing the file size.
+
+There is one important limitation in the GDSII format: it only supports `weakly simple polygons `_, that is, polygons whose segments are allowed to intersect, but not cross.
+
+In particular, curves and shapes with holes are *not* directly supported.
+Holes can be defined, nonetheless, by connecting their boundary to the boundary of the enclosing shape.
+In the case of curves, they must be approximated by a polygon.
+The number of points in the polygonal approximation can be increased to better approximate the original curve up to some acceptable error.
+
+The original GDSII format limits the number of vertices in a polygon to 199.
+Most modern software disregards this limit and allows an arbitrary number of points per polygon.
+Gdspy follows the modern version of GDSII, but this is an important issue to keep in mind if the generated file is to be used in older systems.
+
+The units used to represent shapes in the GDSII format are defined by the user.
+The default unit in gdspy is 1 µm (10⁻⁶ m), but that can be easily changed by the user.
+
+
+First GDSII
+-----------
+
+Let's create our first GDSII file:
+
+.. code-block:: python
+
+ import gdspy
+
+ # Create the geometry: a single rectangle.
+ rect = gdspy.Rectangle((0, 0), (2, 1))
+ cell = gdspy.Cell('FIRST')
+ cell.add(rect)
+
+ # Save all created cells in file 'first.gds'.
+ gdspy.write_gds('first.gds')
+
+ # Optionally, display all cells using the internal viewer.
+ gdspy.LayoutViewer()
+
+
+
+
diff --git a/docs/_build/html/_static/index.rst b/docs/_build/html/_static/index.rst
index 8d9b21bb..3bb1e328 100644
--- a/docs/_build/html/_static/index.rst
+++ b/docs/_build/html/_static/index.rst
@@ -1,26 +1,57 @@
-Welcome to the SPiRA documentation!
-===================================
+Welcome to the SPiRA Framework!
+===============================
+
+Parameterized Cells (PCells) are key components used to increase flexibility and productivity during layout design.
+Creating a parameterized cell integrates all design information into one place.
+The development and maintenance of PCell libraries typically requires device knowledge and advanced programming skills.
+
+Integrated circuit design requires many different levels of analysis. A lot of component design is done using a manual
+design flow, from SPICE simulations, to parameter extraction. While at the same time, circuit design requires abstraction
+at a much higher level.
+
+**SPiRA** is a parametric design framework for Superconductor and Quantum Integrated Circuit (SQIC) design.
+It revolves around the sound engineering concept that creating circuit layouts are prone to unexpected design errors.
+The design process is highly dependent on data provided by the fabrication process.
+In SPiRA, parameterized cells can be generated that interactively binds data from any fabrication process.
+A novel design method is introduced, called *validate-by-design*, that integrates parameter restrictions
+into the design flow, which limits a designer from breaking process design rules.
+
+SPiRA integrates different aspects into a single framework, where a parameterized cell can be defined once
+and then used throughout the design process, performing automatic device detection, netlist extraction, and
+design rule checking. Consequently, errors are significantly reduced by using the same component definition throughout the entire design flow.
+
+Lore
+----
+
+*Spira* is the fictional world of the Square role-playing video game Final Fantasy X.
+The name Spira refers to the word "spiral", alluding to one of the main themes of Final Fantasy X: *continuity*.
+The word "spiral" has multiple meanings depending on context. In geometry, it is a curve acting as the focus
+of a point rotating around a fixed point that continuously extends from that point.
+The inspiration behind the fictional Spira world, according to the producer Yoshinori Kitase,
+is the heuristic that players prefer a "*simple fantasy world*" over a more science fiction world.
+
+**The reason for naming this framework SPiRA:**
+
+The aim is to develop a *continuous design environment* for IC engineers to design circuit layouts,
+with focus falling on a *simple script-based methodology*. The **SPiRA core** is the *focus point*
+that revolves around the single idea of parameterizing layout geometries.
+
+**Basic termnology before getting started:**
+
+1. **PCell** (Parameterized Cell): Also refered to as a *layout generator* is a cell that defines how layout elements must be generated based on a given set of parameters.
+2. **RDD** (Rule Deck Database): A novel script-based approach to develop a Process Design Kit (PDK).
.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
- installation
- overview
- rdd_schema
- parameters
- tutorials
- pcell_examples
- developers
-
-.. installation
-.. overview
-.. rdd_schema
-.. gdsii
-.. parameters
-.. tutorials
-.. pcell_examples
-.. developers
+ :maxdepth: 2
+ :caption: Contents:
+
+ _0_methodology
+ _1_overview
+ _2_basic
+ _3_advanced
+ _4_reference
+ _5_developers
+
Indices and tables
==================
diff --git a/docs/_build/html/_static/installation.rst b/docs/_build/html/_static/installation.rst
deleted file mode 100644
index dedee205..00000000
--- a/docs/_build/html/_static/installation.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-Installation
-============
-
-This page gives more information about installing and setting up the SPiRA framework.
-
-Environment Setup
------------------
-
-SPiRA package descriptions:
-
-* `gdspy `_ Library for GDS file manipulations.
-* `pyclipper `_ Python wrapper for Angusj Clipper library.
-* `pygmsh `_ The goal of pygmsh is to combine the power of Gmsh with the versatility of Python and to provide useful abstractions from the Gmsh scripting language so you can create complex geometries more easily.
-* `meshio `_ A package to read and write different mesh formats.
-* `NetworkX `_ A Python package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks.
-
-Ubuntu
-------
-
-The following packages has to be installed for Ubuntu systems.
-
-.. code-block:: bash
- :linenos:
-
- sudo apt-get install python-dev
- sudo apt-get install python3-dev
- sudo apt-get install --reinstall build-essential
- sudo apt-get install python-tk # Ubuntu
- sudo apt-get update
-
-ArchLinux
----------
-
-On ArchLinux install the following:
-
-.. code-block:: bash
- :linenos:
-
- sudo pacman -S tk
-
-FreeBSD
--------
-
-Support to be added in Q1 2019.
-
-
diff --git a/docs/_build/html/_static/jquery-3.4.1.js b/docs/_build/html/_static/jquery-3.4.1.js
new file mode 100644
index 00000000..773ad95c
--- /dev/null
+++ b/docs/_build/html/_static/jquery-3.4.1.js
@@ -0,0 +1,10598 @@
+/*!
+ * jQuery JavaScript Library v3.4.1
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2019-05-01T21:04Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var document = window.document;
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var concat = arr.concat;
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML