Skip to content

Commit 2754537

Browse files
authored
Merge pull request #421 from pfebrer/heteroribbons
Function to build heteroribbons
2 parents e086e20 + eefa952 commit 2754537

File tree

5 files changed

+659
-2
lines changed

5 files changed

+659
-2
lines changed

docs/api/default_geom.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ geometries via a `pull request <pr>`_.
1414

1515
All methods return a `Geometry` object.
1616

17+
Some of the geometries are created in section based geometries, such as `heteroribbon`.
18+
This functionality is provided through the `composite_geometry`
19+
1720

1821
Bulk
1922
====
@@ -51,6 +54,8 @@ Surfaces (slabs)
5154
zgnr
5255
graphene_nanoribbon
5356
nanotube
57+
heteroribbon
58+
graphene_heteroribbon
5459

5560

5661
2D materials
@@ -62,3 +67,14 @@ Surfaces (slabs)
6267
honeycomb
6368
bilayer
6469
graphene
70+
71+
72+
Helpers
73+
=======
74+
75+
.. autosummary::
76+
:toctree: generated/
77+
78+
composite_geometry
79+
CompositeGeometrySection
80+

src/sisl/geom/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
graphene
4343
4444
"""
45+
from ._composite import *
4546
from .basic import *
4647
from .bilayer import *
4748
from .category import *

src/sisl/geom/_composite.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from abc import abstractmethod
2+
from dataclasses import copy, dataclass, fields
3+
4+
from sisl.messages import SislError, warn
5+
6+
__all__ = ["composite_geometry", "CompositeGeometrySection"]
7+
8+
9+
@dataclass
10+
class CompositeGeometrySection:
11+
12+
@abstractmethod
13+
def build_section(self, geometry):
14+
...
15+
16+
@abstractmethod
17+
def add_section(self, geometry, geometry_addition):
18+
...
19+
20+
def _junction_error(self, prev, msg, what):
21+
"""Helper function to raise an error if the junction is not valid.
22+
23+
It extends the error by specifying details about the sections that
24+
are being joined.
25+
"""
26+
msg = f"Error at junction between sections {prev} and {self}. {msg}"
27+
if what == "raise":
28+
raise SislError(msg)
29+
elif what == "warn":
30+
warn(msg)
31+
32+
33+
def composite_geometry(sections, section_cls, **kwargs):
34+
"""Creates a composite geometry from a list of sections.
35+
36+
The sections are added one after another in the provided order.
37+
38+
Parameters
39+
----------
40+
sections: array-like of (_geom_section or tuple or dict)
41+
A list of sections to be added to the ribbon.
42+
43+
Each section is either a `composite_geometry.section` or something that will
44+
be parsed to a `composite_geometry.section`.
45+
section_cls: class, optional
46+
The class to use for parsing sections.
47+
**kwargs:
48+
Keyword arguments used as defaults for the sections when the .
49+
"""
50+
# Parse sections into Section objects
51+
def conv(s):
52+
# If it is some arbitrary type, convert it to a tuple
53+
if not isinstance(s, (section_cls, tuple, dict)):
54+
s = (s, )
55+
# If we arrived here with a tuple, convert it to a dict
56+
if isinstance(s, tuple):
57+
s = {field.name: val for field, val in zip(fields(section_cls), s)}
58+
# At this point it is either a dict or already a section object.
59+
if isinstance(s, dict):
60+
return section_cls(**{**kwargs, **s})
61+
62+
return copy.copy(s)
63+
64+
# Then loop through all the sections.
65+
geom = None
66+
prev = None
67+
for i, section in enumerate(sections):
68+
section = conv(section)
69+
70+
new_addition = section.build_section(prev)
71+
72+
if i == 0:
73+
geom = new_addition
74+
else:
75+
geom = section.add_section(geom, new_addition)
76+
77+
prev = section
78+
79+
return geom
80+
81+
82+
composite_geometry.section = CompositeGeometrySection

0 commit comments

Comments
 (0)