q2D-Materials is a template-driven library for stacking quasi-2D and bulk perovskites. Instead of shipping a single geometry, we provide a set of hackable layer types (L1, RP1, M1, …) that you can arrange however you want—much like an architecture studio that swaps floor plates. Our tooling then handles ion assignment, molecular alignment, Glazer tilts, spacer orientation, and export. Because everything is encoded as JSON templates you can version-control, you are free to invent new stack types without editing the core library. Our framework providing a fully hackable, layer-sequence-driven approach that decouples geometry from composition.
# Recommended: one command, pinned dependencies
nix develop
# Or the classic pip workflow
pip install ase numpy rdkitWhy Nix? Repeatable builds. No “works on my machine”. You still get the same hackable Python environment—just deterministic.
Our entire philosophy boils down to stacking. Pick a template, choose a layer_sequence, repeat along c. The three frames below (generated by Examples/plot.py) show the same cubic template rendered after placing only L1, then L1-L2, then L1-L2-L1.
Every other tour (Glazer tilts, DJ spacers, RP steps) is just this storyboard with different layers and surface metadata.
Templates live in q2D_Materials/builders/data/*.json. Each template defines named_layers with [site, x_frac, y_frac] entries. You can add S# sites for spacers, Ap for surface cations, additional B offsets, or whatever else fits your chemistry. Examples/2_Templates.md walks through two canonical examples (cubic and Jagodzinski), and you can expand that pattern to reduced cells, Glazer-ready primitives, or your own experimental stacking faults.
Because the templates are just JSON, you can script their creation, lint them in CI, and share them like any other data asset. Provide either a Python list (["L2", "M1", "RP1", "RP2"]) or a hyphenated string ("L2-M1-RP1-RP2") as layer_sequence—we normalize both.
Templates carry more than A/B/X positions—they also mark spacer anchors. In q2D_Materials/builders/data/reduced.json, for example, the M1 layer contains:
"M1": [
["S1", 0.25, 0.75],
["S2", 0.75, 0.25],
["X", 0.25, 0.25],
["X", 0.75, 0.75]
]Those S# tags define ground anchor points. Any layer that follows and reuses the same labels becomes the sky for that pair. We reuse this simple idea for two families:
- Dion–Jacobson (DJ) stacks place two spacer-bearing layers back-to-back (think
M1followed immediately by anotherM1). Double-NH₃ molecules connect matching labels, so one end binds to the ground, the other to the sky. It feels like drawing a section: one bridge perS#. SeeExamples/images/dj_bulk.pngfor the reduced-template render. - Ruddlesden–Popper (RP) alternates a perovskite slab, then two surface layers (
RP1/RP2) that exposeS#only on one side. The following layer exposes the matching labels, so you always know which side is the spacer “ceiling.” We show the same RP block in plan (Examples/images/rp_glazer_top.png), elevation (Examples/images/rp_base_side.png), and an isometric cut (Examples/images/rp_atomic_side.png). Because every layer is typed (L1,M1,RP1, …), you can remix DJ and RP logic in one template without touching the core code.
Whenever you edit a template or layer_sequence, run Examples/plot.py to refresh every figure used throughout the docs.
from q2D_Materials.core.creator import q2D_creator
from ase.io import write
q2d = q2D_creator()
bulk = q2d.create_perovskite(
structure_type="bulk",
A_ions="MA",
B_ions="Pb",
X_ions="I",
xy_expansion=(1, 1),
template="cubic",
glazer_angles=[0, 0, 5],
glazer_pattern=["0", "0", "+"],
)
write("bulk.vasp", bulk, sort=True)- Bulk: 3D perovskites (tiling via
xy_expansion, optionalBp, Glazer tilts) - Monolayer: 2D slabs with
thickness,vacuum,spacer,penetration - Twist: Build twisted stacks from monolayers via
twist(...)
Get recommendations for compatible ions based on database occurrence:
q2d = q2D_creator()
# Get recommendations based on X = Cl
recommendations = q2d.recommend(X='Cl', top_n=5)
print(recommendations['B']) # Top 5 B-site cations
print(recommendations['A']) # Top 5 A-site cations
print(recommendations['spacer']) # Top 5 spacersRegenerate every figure with nix develop -c python3 Examples/plot.py and browse the Markdown references:
Examples/1_Creator.mdExamples/2_Templates.mdExamples/3_Glazer.mdExamples/4_Jagodzinski.mdExamples/5_Monolayer.mdExamples/6_Twist.mdExamples/7_DionJacobson.mdExamples/8_Ruddlessden_Popper.md
[1] Kunz, S. L., Haefner, M., & Clemens, O. "``hexagonal'' perovskites: From stacking sequence to space group symmetry and new opportunities." Chem. Mater. 36, 23 (2024).
[2] Stanton, R., & Trivedi, D. J. "Pyrovskite: A software package for the high-throughput construction, analysis, and featurization of two- and three-dimensional perovskite systems." J. Chem. Phys. 159, 6 (2023).
MIT License









