About
Geometry in PLaSK is represented by a directed, acyclic graph, which has geometry objects in its vertices (see plask::GeometryObject and Geometry Objects). Very often this graph is a tree, in which each object has pointers to its children. PLaSK uses terminology inheritted from the tree theory i.e. object C is a child of P only if there is arc from P to C, and then P is called the parent of C).
Each vertex is represented by an object of class inherited from the plask::GeometryObject type. Each such object must be held by plask::shared_ptr (which automatically deletes it in the proper time).
There are following types of geometry objects / vertices (see also plask::GeometryObjectType):
- leafs (terminal nodes) : don't have children and store information about material;
- transformation nodes : each has exactly one child, and represents this child after transformation (sometimes transformation object is in different space than it's child);
- containers : each has one or more children and represents a substructure which consist of these children (e.g. a stack).
Each geometry object (vertex) has local coordinate system (in 2D or 3D space). Systems of all geometry objects which use Cartesian coordinates have common orientation of axes. All 2D objects lie in the tran-up (or R-Z) plane.
Geometry representation in XML format
Geometry can be read from an XML content (for details about reading XML see How to create and use geometry graph? (examples)).
Example of XML which describes geometry:
<geometry axes="xy">
<cartesian2d name="cartesian geometry" length="2">
<container2d name="trans_cont">
<rectangle x="5" y="3" name="block_5_3" material="exampleMaterial"/>
<item x="3" y="3">
<again ref="block_5_3"/>
</item>
</container2d>
</cartesian2d>
<cylindrical name="cylindrical geometry">
<stack2d repeat="4" name="mystack">
<again ref="block_5_3"/>
<item x="-5">
<again ref="c1"/>
</item>
<rectangle x="8" y="12" material="exampleMaterial"/>
</stack2D>
</cylindrical>
</geometry>
Above XML describes 2 geometries, each is in 2D space, and each contains one container. First geometry is Cartesian, has name "cartesian geometry", and length equal to 2. Second geometry is cylindrical and has name "cylindrical geometry".
Container in first geometry (described by the container2D
tag), has name "trans_cont" (see name
attribute) and has 2 (identical) children. They are actually the same rectangular block (rectangle
tag) with name "block_5_3" and size 5x3 (see x
and y
attributes). Its first instance is locates at point (0, 0) (which is a default), and the second one is located at point (3, 3) (which is given in the child
tag attributes). Second appearance of the block in container is given by the again
tag. This tag represents reference to an earlier defined object and it requires only one attribute, namely the name of the object which was earlier defined.
Container in second geometry is described by a tag stack2D
and is named "mystack". Because it has a repeat
attribute it will be represented by an object of class plask::MultiStackContainer. This container has two children: earlier defined objects with names "block_5_3" and "c1" (the second one is translated inside "mystack" in x direction by -5), and a block with size 8x12.
Geometry tag has an axes
attribute which defines names of the axes. Each other tag inside geometry also can have an axes
attribute. In such cases this attribute defines local names of axes (i.e. valid up to end of this tag).
How to create and use geometry graph? (examples)
Geometry graph can be created:
- manually in Python (by constructing its object), for example we construct the same container as the one in the example from section Geometry representation in XML format :
block_5_3 = plask.geometry.Rectangle(5.0, 3.0, exampleMaterial)
assert block_5_3.boundingBox.lower ==
plask.vec(0.0, 0.0)
assert block_5_3.boundingBox.upper ==
plask.vec(5.0, 3.0)
assert block_5_3.getMaterial(4.0, 2.0) == exampleMaterial
assert block_5_3.getMaterial(6.0, 2.0) == None
container = plask.geometry.TranslationContainer2D();
container.append(block_5_3)
container.append(block_5_3,
plask.vec(3.0, 3.0))
assert container.boundingBox == plask.geometry.Box2D(0.0, 0.0, 8.0, 6.0)
assert container.getMaterial(6.0, 6.0) == exampleMaterial
assert container.getMaterial(6.0, 2.0) == None
- manually from C++. The same example as the Python code above:
assert(block_5_3->getBoundingBox().lower ==
plask::vec(0.0, 0.0));
assert(block_5_3->getBoundingBox().upper ==
plask::vec(5.0, 3.0));
assert(block_5_3->getMaterial(
plask::vec(4.0, 2.0)) == exampleMaterial);
assert(block_5_3->getMaterial(
plask::vec(6.0, 2.0)) ==
nullptr);
container->add(block_5_3);
assert(container->getBoundingBox() ==
plask::(
plask::vec(0.0, 0.0),
plask::vec(8.0, 6.0)));
assert(container->getMaterial(
plask::vec(6.0, 6.0)) == exampleMaterial);
assert(container->getMaterial(
plask::vec(6.0, 2.0)) ==
nullptr);
- from XML file in Python using Geometry class, for example (we suppose that example_file_name.xml file contains content showed in Geometry representation in XML format section):
geometry = plask.geometry.Geometry("example_file_name.xml")
block_5_3 = geometry.object("block_5_3")
assert block_5_3.boundingBox.lower ==
plask.vec(0.0, 0.0)
assert block_5_3.boundingBox.upper ==
plask.vec(5.0, 3.0)
assert block_5_3.getMaterial(
plask.vec(4.0, 2.0)) == exampleMaterial
assert block_5_3.getMaterial(
plask.vec(6.0, 2.0)) ==
None
container = geometry.object("trans_cont")
assert container.boundingBox == plask.geometry.Box2D(
plask.vec(0.0, 0.0),
plask.vec(8.0, 6.0))
assert container.getMaterial(
plask.vec(6.0, 6.0)) == exampleMaterial
assert container.getMaterial(
plask.vec(6.0, 2.0)) ==
None
- from XML content in C++, by using plask::Manager, for example:
geometry.loadFromFile("example_file_name.xml");
assert(block_5_3->getBoundingBox().lower ==
plask::vec(0.0, 0.0));
assert(block_5_3->getBoundingBox().upper ==
plask::vec(5.0, 3.0));
assert(block_5_3->getMaterial(
plask::vec(4.0, 2.0)) == exampleMaterial);
assert(block_5_3->getMaterial(
plask::vec(6.0, 2.0)) ==
nullptr);
assert(container->getBoundingBox() ==
plask::(
plask::vec(0.0, 0.0),
plask::vec(8.0, 6.0)));
assert(container->getMaterial(
plask::vec(6.0, 6.0)) == exampleMaterial);
assert(container->getMaterial(
plask::vec(6.0, 2.0)) ==
nullptr);
Paths
You can add each geometry object object to graph more than one time. If you do this, you will sometimes need to use paths to point to particular instance of this object, which can appear more than once in the graph.
Each path is represented by an object of plask::PathHints class.
plask::PathHints consist of zero or more hints (objects of plask::PathHints::Hint class). Each hint is a pair which represent a connection between the container and one of its children. Hints are returned by methods which adds new objects to containers, and can be added to plask::PathHints by a += operator:
mypath += container_object.push_back(child_object);
container_object.push_back(child_object);
container_object.push_back(child_object);
container_object.remove(mypath);
container_object.remove(child_object);
In Python this can be done in similar way (see User Manual for more examples):
mypath += container_object.append(child_object)
container_object.append(child_object)
container_object.append(child_object)
del container_object[mypath]
del container_object[child_object]
Writing new geometry objects
To write new geometry object you should:
- write a class which directly or indirectly inherit from plask::GeometryObject and implement all its abstract methods,
- write a reader function which allow to read your object from XML (see plask::GeometryReader and plask::GeometryReader::object_read_f for details),
- register your reader in global registry, creating global instance of plask::GeometryReader::RegisterObjectReader class.
- write Python binding to your class using boost::python::class_ construction. This class should be registered in geometry scope.
Good base classes for geometries objects are, for example: