Metadata-Version: 2.4
Name: MoireStudio
Version: 1.0.4
Summary: Universal Twisted Electronic Structure Calculation Package
Author: Junxi Yu
License: Copyright (C) <2026> <Junxi Yu>
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: scipy>=1.9
Requires-Dist: matplotlib>=3.7
Dynamic: license-file

# General Toolkit for Twisted / Moiré Electronic Structure: MoireStudio

This repository provides a general-purpose toolkit for **twisted / moiré (moire) systems**, including both **k·p** and **tight-binding (TB/Wannier)** workflows, plus geometry utilities (commensurate-angle scan, moiré supercell generation) and basic visualization.

> Target users: theorists and computational researchers working on 2D materials and twisted/moire systems.  
> Platforms: Linux / macOS / Windows (including WSL).

---

## Features

- **k·p workflow**
  - Band structures along high-symmetry paths
  - Chern number computation on k-meshes

- **TB / Wannier workflow**
  - POSCAR-driven TB models (structure-based)
  - Wannier90-driven models (using `.win` / `_hr.dat`)

- **Geometry module**
  - Real-space moiré point distribution
  - Commensurate-angle scan
  - Moiré supercell generation (POSCAR)

- **Visualization**
  - Band plots
  - Moiré lattice point plots
  - Commensurate-angle distribution plots

- **Parallelism & cross-platform**
  - Process/thread-based parallel backends with BLAS thread pinning
  - Windows-friendly multiprocessing (uses `spawn` mode)

---

## Environment & Installation

- Python ≥ 3.9
- Required packages (minimal):
  - `numpy`
  - `scipy`
  - `matplotlib`

Install via:

```bash
pip install numpy scipy matplotlib
```

For better linear-algebra performance, a NumPy/SciPy build with MKL or another optimized BLAS is recommended.

---

## Quick Start

From the project root:

```bash
python driver.py --input input.json
```

The main calculation mode is selected by the top-level JSON key `"mode"` and sub-key `"task"`:

- `kp.band` – k·p band structure
- `kp.chern` – k·p Chern number
- `tb.band` – TB/Wannier band structure (POSCAR or Wannier90)
- `struc.find_com` – scan commensurate twist-angle distribution
- `struc.gen_pos` – generate a moiré supercell (POSCAR + schematic plot)

Default output directory: `./outputs` (configurable via `io.output_dir`).

---

## Recommended Project Layout

```text
project/
  driver.py
  solver.py
  twist_tb.py
  twist_kp.py
  twist_geometry.py
  read_tb_model.py
  twist_viz.py
  inputs/
    POSCAR                 # or Wannier90: *.win / *_hr.dat / FERMI_ENERGY
  outputs/                 # generated after running
```

- **Wannier90 input**: requires `*.win` and `*_hr.dat`.  
  - Fermi level can be provided via `inputs/FERMI_ENERGY` or via `tb.wannier.fermi_energy`.
- **POSCAR input**: single-layer or bilayer structures are supported (controlled by `struc.read_layer`).

---

## Input File `input.json`

### Top-level structure

```json
{
  "mode": "kp | tb | struc",
  "task": "...",
  "io":   { ... },
  "kp":   { ... },
  "tb":   { ... },
  "struc":{ ... }
}
```

### Common section `io`

- `output_dir`: output directory (default `./outputs`)  
- `input_dir`: input directory (default `./inputs`)  
- `fig_band`: filename for band plot (default `<task>.png`)  
- `fig_moire`: filename for moiré-point plot (default `moire_points.png`)  
- `fig_comm`: filename for commensurate-angle plot (default `comm_angles.png`)  
- `show_plots`: whether to show figures interactively (`true/false`)  
- **Heterobilayer (optional)**:
  - `t_prefix` / `b_prefix`: Wannier file prefixes for top/bottom layers
  - `t_fermi_energy` / `b_fermi_energy`: corresponding Fermi energies

### Geometry & Supercell `struc`

- `read_mode`: `"POSCAR"` or `"model"` (Wannier)  
- `read_layer`: `"bilayer"` / `"monolayer"` (only in POSCAR mode)  
- `ihetero`: whether the system is heterobilayer (`true/false`)  
- `pos_path` / `pos_prefix`: path and prefix for POSCAR input  
- `d_AA` / `d_AB`: out-of-plane AA/AB interlayer distances (units consistent with input)

**Supercell generation & search:**

- `zero_point`: reference lattice indices for moiré center
- `lim`, `search`, `accurate`, `if_gen_pos`, `write_by_hand`:  
  parameters controlling supercell search, commensurability scan and whether to dump a POSCAR.

**Commensurate-angle scan:**

- `max_angle`, `min_angle`: scan range in degrees  
- `lim`: integer cutoff for commensurate search  
- `step`: scan step (deg)  
- `accurate`: numerical matching tolerance

### Tight-Binding / Wannier `tb`

- `theta_deg`: twist angle in degrees  
- `cores`: number of CPU cores for TB tasks  
- `isparse`: whether to use sparse workflow (recommended for large systems)  
- `k_path`: list of high-symmetry points in fractional coordinates  
- `nk`: total number of k-points along the path  
- `labels`: labels for each waypoint (e.g. `["G","M","K","G"]`)  
- `ylim`: energy window for plotting, e.g. `[-0.2, 0.2]`

**Wannier options** (when `struc.read_mode="model"`):

- `wannier.prefix`: e.g. `"wannier90"` for `inputs/wannier90.win` and `inputs/wannier90_hr.dat`  
- `wannier.fermi_energy`: Fermi level; if omitted, the program attempts to read `inputs/FERMI_ENERGY`, otherwise defaults to 0.0.

### k·p section `kp`

- `theta_deg`: twist angle (deg)  
- `tr`: truncation index for reciprocal shells (default ≈3)  
- `valley_pos`: valley position in reduced coordinates, e.g. `[2/3, 1/3]`  
- `mono_lat`: 2×2 real-space primitive lattice of the monolayer  
- `valley_name`: `"K"` or `"M"` (controls mapping of the moiré reciprocal lattice)  
- `V_z` / `m_z`: layer potential and mass term for simple 2×2 Dirac-like models

**Coupling definition:**

- `inter_idxs` / `intra_idxs`: lists of integer index pairs for moiré reciprocal vectors (e.g. `[[0,0],[1,0],...]`)  
- `inter_coes`: list of coupling matrices corresponding to `inter_idxs`, as:
  - real numbers,
  - complex numbers `[re, im]`,
  - or 2D complex matrices (nested lists).  
- `intra_coes`: `[top_list, bottom_list]`, each element aligned with `intra_idxs`.  
- k-path parameters: `path`, `nk`, `labels`, `ylim` (same as TB).

---

### Complex numbers in JSON

- A bare scalar `x` is interpreted as a real number.  
- `[re, im]` is interpreted as a complex number `re + i·im`.  
- Complex matrices are written as nested lists of `[re, im]` entries.

---

## Complete Example `input.json`

Below are shortened examples; you can adapt them to your own systems.

### 1. Geometry: scan commensurate angles – `struc.find_com`

```json
{
  "mode": "struc",
  "task": "find_com",
  "io": { "input_dir": "./inputs", "output_dir": "./outputs", "fig_comm": "comm_angles.png" },
  "struc": {
    "read_mode": "POSCAR",
    "read_layer": "bilayer",
    "pos_path": "./inputs",
    "pos_prefix": "POSCAR",
    "ihetero": false,
    "d_AA": 3.5,
    "d_AB": 3.35,
    "max_angle": 5.0,
    "min_angle": 0.5,
    "lim": 12,
    "step": 0.02,
    "accurate": 0.01
  },
  "tb": { "theta_deg": 1.10 }
}
```

Output: `outputs/commensurate_angle.txt` and `outputs/comm_angles.png`.

### 2. Geometry: generate moiré supercell – `struc.gen_pos`

```json
{
  "mode": "struc",
  "task": "gen_pos",
  "io": { "input_dir": "./inputs", "output_dir": "./outputs", "fig_moire": "moire_points.png" },
  "struc": {
    "read_mode": "POSCAR",
    "read_layer": "bilayer",
    "pos_path": "./inputs",
    "pos_prefix": "POSCAR",
    "ihetero": false,
    "d_AA": 3.5,
    "d_AB": 3.35,
    "zero_point": [0, 0],
    "lim": 20,
    "search": 0,
    "accurate": 0.01,
    "if_gen_pos": true
  },
  "tb": { "theta_deg": 1.10 }
}
```

Outputs: moiré point plot `outputs/moire_points.png`, and a generated/overwritten `POSCAR` at the project root.

### 3. TB: band structure from POSCAR – `tb.band`

```json
{
  "mode": "tb",
  "task": "band",
  "io": {
    "input_dir": "./inputs",
    "output_dir": "./outputs",
    "fig_band": "tb_band.png",
    "show_plots": false
  },
  "struc": {
    "read_mode": "POSCAR",
    "read_layer": "bilayer",
    "pos_path": "./inputs",
    "pos_prefix": "POSCAR",
    "ihetero": false,
    "d_AA": 3.5,
    "d_AB": 3.35,
    "if_gen_pos": true
  },
  "tb": {
    "theta_deg": 1.10,
    "cores": 4,
    "isparse": false,
    "k_path": [[0,0],[0.5,0],[0.3333333,0.3333333],[0,0]],
    "nk": 201,
    "labels": ["G","M","K","G"],
    "ylim": [-0.2, 0.2]
  }
}
```

### 4. TB: band structure from Wannier90 – `tb.band`

```json
{
  "mode": "tb",
  "task": "band",
  "io": { "input_dir": "./inputs", "output_dir": "./outputs", "fig_band": "tb_band_w90.png" },
  "struc": { "read_mode": "model", "ihetero": false },
  "tb": {
    "theta_deg": 1.10,
    "cores": 4,
    "isparse": false,
    "wannier": { "prefix": "wannier90", "fermi_energy": 0.0 },
    "k_path": [[0,0],[0.5,0],[0.3333333,0.3333333],[0,0]],
    "nk": 201,
    "labels": ["G","M","K","G"]
  }
}
```

If `fermi_energy` is not specified, the code tries to read `inputs/FERMI_ENERGY`; if missing, it defaults to 0.0.

### 5. k·p: band structure – `kp.band`

```json
{
  "mode": "kp",
  "task": "band",
  "io": { "output_dir": "./outputs", "fig_band": "kp_band.png" },
  "kp": {
    "theta_deg": 1.10,
    "tr": 3,
    "valley_pos": [0.6666667, 0.3333333],
    "mono_lat": [[2.46, 0.0], [1.23, 2.13162820728]],
    "valley_name": "K",
    "V_z": 0.0,
    "m_z": 0.0,
    "inter_idxs": [[0,0],[1,0],[0,1]],
    "inter_coes": [[[0,0],[10,0]], [[0,0],[10,0]], [[0,0],[10,0]]],
    "intra_idxs": [[0,0]],
    "intra_coes": [
      [[[0,0],[0,0]], [[0,0],[0,0]]],
      [[[0,0],[0,0]], [[0,0],[0,0]]]
    ],
    "path": [[0,0],[0.5,0],[0.3333333,0.3333333],[0,0]],
    "nk": 201,
    "labels": ["G","M","K","G"],
    "ylim": [-0.2, 0.2]
  }
}
```

### 6. k·p: Chern number – `kp.chern`

```json
{
  "mode": "kp",
  "task": "chern",
  "io": { "output_dir": "./outputs" },
  "kp": {
    "theta_deg": 1.10,
    "tr": 3,
    "valley_pos": [0.6666667, 0.3333333],
    "mono_lat": [[2.46, 0.0], [1.23, 2.13162820728]],
    "valley_name": "K",
    "V_z": 0.0,
    "m_z": 0.0,
    "inter_idxs": [[0,0]],
    "inter_coes": [[[0,0],[10,0]]],
    "intra_idxs": [],
    "intra_coes": [[],[]],
    "chern": { "n": 31, "band_index": 0 }
  }
}
```

Output: `outputs/chern_number.txt` (integer Chern number).

---

## Outputs & Visualization

- **Band structures and k-path**
  - `band.txt`: real matrix of shape `(nk, nbands)`
  - `k_vec.txt`: k-points in reduced coordinates
  - `k_dist.txt`: accumulated arc length along the path
  - `k_node.txt`: positions of high-symmetry points (x-axis ticks)
  - `fig_band`: band plot (PNG), name set via `io.fig_band`

- **Geometry**
  - `commensurate_angle.txt`: twist angle, number of commensurate solutions, and a proxy for supercell size
  - `fig_moire`: moiré point distribution plot
  - `POSCAR`: generated/overwritten when running `struc.gen_pos`

To display plots interactively, set `io.show_plots=true`, or open the PNG files directly from the `outputs/` directory.

---

## Parallelism, Sparse Workflow & Large Systems

- `tb.cores`: number of CPU cores used in TB calculations.

**Sparse workflow** (recommended for large systems, with `tb.isparse=true`):

1. Use methods on `TwistTB` (in `twist_tb.py`) to build sparse blocks:
   - `TwistTB.gen_r_ham_sparse_parallel(...)`: generate real-space sparse blocks
   - `TwistTB.export_sparse_blocks(out_dir)`: export `H0.npz`, `HRm.npz`, and `R_vectors.npy`
2. At run time, assemble `H(k)` from these blocks via a helper such as `build_ham_from_npz(k, out_dir)` and/or compute low-energy eigenpairs using:
   - `solver.solve_low_energy_streaming_parallel(...)` (sparse, streaming).

**Dense workflow**:

- Build all dense Hamiltonians `H(k)` at once, e.g. `gen_all_k_ham(k_vec)`  
- Diagonalize using `solver.solve_all_parallel(...)`.

**Windows note**: wrap parallel entry points in

```python
if __name__ == "__main__":
    main()
```

to be compatible with the `spawn` start method on Windows.

---

## FAQ (short)

- **Q1: POSCAR vs. Wannier90?**  
  - If you already have high-quality Wannier parameters → use `read_mode="model"`.  
  - If you start from structural geometry or only need moiré geometry → use `read_mode="POSCAR"`.

- **Q2: Parallel runs crash on Windows?**  
  - Wrap calls in `if __name__ == "__main__":` as above.  
  - Test with `tb.cores = 1` first, then increase gradually.

- **Q3: Band calculation is too slow / runs out of memory?**  
  - Reduce `nk` or simplify the high-symmetry path.  
  - Use sparse workflow (`tb.isparse=true`) plus streaming solvers.  
  - Check BLAS thread counts (the code tries to clamp them, but it’s still good practice to set reasonable values in the environment).

- **Q4: How to write complex matrices in JSON?**  
  - Use `[re, im]` for each entry and nested lists for matrices (see “Complex numbers in JSON”).

- **Q5: No figures appear?**  
  - Set `io.show_plots=true`, or open the PNG files in `outputs/`.

---

## Acknowledgements & Contributions

- Issues and pull requests are welcome for improving documentation, examples, and code quality.  
- If this toolkit is useful for your research, a citation or acknowledgement is greatly appreciated.
