BLAZE - Band-structure LOBPCG Accelerated Zone Eigensolver for 2D Photonic Crystals
Project description
BLAZE - Band-structure LOBPCG Accelerated Zone Eigensolver
High-performance 2D photonic crystal band structure solver with Python bindings. Also supports Envelope Approximation (EA) eigenproblems for moiré lattice research.
v0.3.0: EA mode now emits eigenvectors alongside eigenvalues!
Installation
pip install blaze2d
Quick Start
Maxwell Mode (Photonic Crystals)
from blaze import BulkDriver
# Load configuration from TOML file
driver = BulkDriver("config.toml")
print(f"Will run {driver.job_count} jobs, solver: {driver.solver_type}")
# Stream results as they complete (for live plotting)
for result in driver.run_streaming():
if result['result_type'] == 'maxwell':
print(f"Job {result['job_index']}: {result['num_bands']} bands")
# result['bands'] is a 2D array [k_index][band_index]
# result['distances'] is the k-path distance for plotting
# Or collect all results at once
results, stats = driver.run_collect()
print(f"Completed {len(results)} jobs in {stats['total_time_secs']:.2f}s")
EA Mode (Envelope Approximation for Moiré Lattices)
from blaze import BulkDriver
import numpy as np
# Load EA configuration
driver = BulkDriver("ea_moire.toml")
print(f"Solver type: {driver.solver_type}") # "ea"
# Stream eigenvalue and eigenvector results
for result in driver.run_streaming():
if result['result_type'] == 'ea':
eigenvalues = result['eigenvalues']
eigenvectors = result['eigenvectors'] # List of complex 2D arrays
grid_dims = result['grid_dims'] # [nx, ny]
print(f"Job {result['job_index']}: {len(eigenvalues)} eigenvalues")
print(f" Lowest 3: {eigenvalues[:3]}")
print(f" Converged: {result['converged']}")
# Eigenvectors are complex arrays of shape (nx*ny, 2) -> [re, im]
# Reshape to 2D field:
psi_0 = np.array(eigenvectors[0]) # First eigenvector
psi_0_complex = psi_0[:, 0] + 1j * psi_0[:, 1]
psi_0_2d = psi_0_complex.reshape(grid_dims)
Configuration
BLAZE uses TOML configuration files.
Maxwell Mode Example (photonic crystal sweep)
# Section-less entries at top
polarization = "TM"
[bulk]
threads = 4
verbose = true
[grid]
nx = 32
ny = 32
lx = 1.0
ly = 1.0
[geometry]
eps_bg = 12.0
[geometry.lattice]
type = "square"
a = 1.0
[[geometry.atoms]]
pos = [0.5, 0.5]
radius = 0.3
eps_inside = 1.0
[path]
preset = "square"
segments_per_leg = 12
[eigensolver]
n_bands = 8
tol = 1e-6
max_iter = 200
[ranges]
eps_bg = { min = 10.0, max = 14.0, step = 1.0 }
polarization = ["TM", "TE"]
[output]
mode = "full"
directory = "./results"
prefix = "job"
EA Mode Example (moiré lattice)
# EA mode requires [solver] type = "ea"
# Eigenvectors are always emitted alongside eigenvalues
[bulk]
threads = 4
verbose = true
[solver]
type = "ea"
[grid]
nx = 64
ny = 64
lx = 10.0
ly = 10.0
[ea]
potential = "data/potential.bin" # V(R) - binary f64 file
mass_inv = "data/mass_inv.bin" # M⁻¹(R) - binary f64 file
# vg = "data/group_velocity.bin" # Optional drift term
eta = 0.1
domain_size = [10.0, 10.0]
periodic = true
[eigensolver]
n_bands = 12
tol = 1e-6
max_iter = 500
[output]
mode = "full"
directory = "./ea_output"
prefix = "ea_job"
API Reference
BulkDriver
driver = BulkDriver(config_path: str, threads: int = 0)
config_path: Path to TOML configuration filethreads: Thread count (-1 = adaptive, 0 = auto, >0 = fixed)
Properties
| Property | Type | Description |
|---|---|---|
job_count |
int | Number of jobs to execute |
config_path |
str | Path to configuration file |
solver_type |
str | "maxwell" or "ea" |
is_ea |
bool | True if EA solver |
Methods
| Method | Description |
|---|---|
run_streaming() |
Iterator yielding results as they complete |
run_streaming_filtered(k_indices, band_indices) |
Filtered streaming (Maxwell only) |
run_collect(k_indices, band_indices) |
Collect all results into list |
run_batched(buffer_size_mb) |
Run with buffered disk I/O |
run() |
Synchronous execution |
dry_run() |
Count jobs without executing |
Result Dictionary
Each result is a dictionary. Common fields:
| Key | Type | Description |
|---|---|---|
job_index |
int | Job identifier |
result_type |
str | "maxwell" or "ea" |
params |
dict | Simulation parameters |
num_bands |
int | Number of bands/eigenvalues |
Maxwell-specific fields (result_type == "maxwell")
| Key | Type | Description |
|---|---|---|
k_path |
list | K-points as (kx, ky) tuples |
distances |
list | Cumulative k-path distance |
bands |
list | 2D array [k_index][band_index] |
num_k_points |
int | Number of k-points |
EA-specific fields (result_type == "ea")
| Key | Type | Description |
|---|---|---|
eigenvalues |
list | Computed eigenvalues (sorted) |
eigenvectors |
list | List of eigenvectors, each as (N, 2) array [re, im] |
grid_dims |
list | Grid dimensions [nx, ny] for reshaping eigenvectors |
n_iterations |
int | LOBPCG iterations used |
converged |
bool | Whether solver converged |
num_eigenvalues |
int | Number of eigenvalues |
Plotting Example
Maxwell Band Structure
import matplotlib.pyplot as plt
from blaze import BulkDriver
driver = BulkDriver("sweep.toml")
# Live plotting with streaming
plt.ion()
fig, ax = plt.subplots()
for result in driver.run_streaming():
if result['result_type'] != 'maxwell':
continue
ax.clear()
for band_idx in range(result['num_bands']):
band = [result['bands'][k][band_idx] for k in range(result['num_k_points'])]
ax.plot(result['distances'], band)
ax.set_xlabel('k-path')
ax.set_ylabel('ω (normalized)')
ax.set_title(f"Job {result['job_index']}")
plt.pause(0.01)
plt.ioff()
plt.show()
EA Eigenvalue Spectrum and Eigenvector Visualization
import matplotlib.pyplot as plt
import numpy as np
from blaze import BulkDriver
driver = BulkDriver("ea_config.toml")
results, stats = driver.run_collect()
result = results[0]
eigenvalues = result['eigenvalues']
eigenvectors = result['eigenvectors']
nx, ny = result['grid_dims']
# Plot eigenvalue spectrum
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].plot(eigenvalues, 'o-')
axes[0].set_xlabel('Eigenvalue index')
axes[0].set_ylabel('Energy')
axes[0].set_title('EA Eigenvalue Spectrum')
# Plot ground state |ψ|²
psi_0 = np.array(eigenvectors[0]) # Shape: (nx*ny, 2)
psi_0_complex = psi_0[:, 0] + 1j * psi_0[:, 1]
psi_0_2d = psi_0_complex.reshape((nx, ny))
im = axes[1].imshow(np.abs(psi_0_2d)**2, origin='lower', cmap='hot')
axes[1].set_title(f'Ground state |ψ₀|² (E = {eigenvalues[0]:.4f})')
axes[1].set_xlabel('x')
axes[1].set_ylabel('y')
plt.colorbar(im, ax=axes[1])
plt.tight_layout()
plt.show()
Filtered Streaming
For large simulations, filter to only the k-points and bands you need:
# Stream only Gamma (0), X (10), M (15) and first 4 bands
# Note: Filtering only applies to Maxwell results
for result in driver.run_streaming_filtered(
k_indices=[0, 10, 15],
band_indices=[0, 1, 2, 3]
):
if result['result_type'] == 'maxwell':
assert result['num_k_points'] == 3
assert result['num_bands'] == 4
EA Input Data Format
EA mode requires binary input files for the effective Hamiltonian components. All files are raw f64 (little-endian) in row-major (C-order):
- Potential (
potential.bin):Nx × Nyvalues = V(x, y) - Mass inverse (
mass_inv.bin):Nx × Ny × 4values = [m_xx, m_xy, m_yx, m_yy] - Group velocity (
vg.bin, optional):Nx × Ny × 2values = [vg_x, vg_y]
Python example to generate input data:
import numpy as np
nx, ny = 64, 64
Lx, Ly = 10.0, 10.0
# Coordinate grids
x = np.linspace(0, Lx, nx, endpoint=False)
y = np.linspace(0, Ly, ny, endpoint=False)
X, Y = np.meshgrid(x, y, indexing='ij')
# Periodic potential
G = 2 * np.pi / Lx
V = 0.1 * (np.cos(G * X) + np.cos(G * Y))
# Isotropic mass (m* = 0.05)
m_star = 0.05
m_inv = np.zeros((nx, ny, 4))
m_inv[:, :, 0] = 1.0 / m_star # m_xx
m_inv[:, :, 3] = 1.0 / m_star # m_yy
# Save
V.astype(np.float64).tofile('data/potential.bin')
m_inv.astype(np.float64).tofile('data/mass_inv.bin')
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file blaze2d-0.3.0.tar.gz.
File metadata
- Download URL: blaze2d-0.3.0.tar.gz
- Upload date:
- Size: 273.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9db616472b12a2c80c46bf97f0f9914a85a42848215c698525b82f95faaaa721
|
|
| MD5 |
a6ea4c795fab55ac311eb6db1cd68d9e
|
|
| BLAKE2b-256 |
26ca395db620f27433236aa47aba213f149ccf0798888bdd8a26b979a4258abf
|
File details
Details for the file blaze2d-0.3.0-cp312-cp312-manylinux_2_39_x86_64.whl.
File metadata
- Download URL: blaze2d-0.3.0-cp312-cp312-manylinux_2_39_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.12, manylinux: glibc 2.39+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b5ed3e12f7d77dbe9cea5dd651fc19d2a3c3f1fd555944057663726722fd754
|
|
| MD5 |
b57f2df8a7aead98d60b5ab76111f5e5
|
|
| BLAKE2b-256 |
9749f7b311a5714c63bce9575614d9be2e319c1932c28feb37bca86690d1d021
|