Skip to main content

physikmdb

Photoemission momentum maps and molecular orbitals from PhysikMDB, in Python.

The same C physics kernels the website runs, plus a client for the database behind it. Look up a calculation, ask for an orbital by name, get a numpy array.

pip install physikmdb

numpy is the only dependency, and no compiler is needed — a prebuilt kernel library ships for Linux, macOS and Windows, and is built from source only on a platform without one.

Five lines

import physikmdb

db = physikmdb.Database()
calc = db.calculation(21)

image = calc.momentum_map("HOMO")   # (200, 200); every argument but the
                                    # orbital has a default (hnu=30 eV, k_max=3 Å⁻¹, ...)

basis.bin and the HOMO's coefficients are downloaded on first use and cached, so the obvious loop costs one small request per orbital:

for name in ("HOMO", "HOMO-1", "HOMO-2"):
    image = calc.momentum_map(name)

Finding a calculation

db.systems()                                   # every molecule
db.systems(short_name="2A")
db.systems(xc_functional="B3LYP", basis_set="cc-pVTZ", charge=0)

db.calculations()                              # every calculation
db.calculations(system_id=7)                   # one molecule's
db.calculations(code="Orca", xc_functional="B3LYP")

db.filters()                                   # what those filters can be set to

calc = db.calculation(21)                      # by database id — the number in
                                               # an entry page's URL

Both listings return plain records and do no downloading.

One calculation

calc.formula, calc.code, calc.xc_functional, calc.basis_set
calc.charge, calc.spin, calc.spin_restricted
calc.total_energy, calc.homo_energy, calc.lumo_energy, calc.gap    # eV

calc.orbitals                        # every orbital
calc.orbital("HOMO-2")               # by name, case-insensitive
calc.orbital(21)                     # by row index
calc.homo, calc.lumo

calc.basis                           # the basis set
calc.coefficients                    # the full (Nmo, Nbasis) matrix

An orbital is a record — index, name, energy (eV) and energy_hartree, occupation, symmetry, spin. For an unrestricted calculation a bare "HOMO" is the up channel, the one the website shows first; pass calc.orbital("HOMO", spin="down") for the other.

calc.basis/calc.coefficients cover basis.bin/coefficients.bin. Any other stored file — the archival HDF5, the .xyz geometry, or the code's own input/output — downloads (and caches) with calc.download():

calc.download(".hdf5")   # geometry + full basis + MO coefficients
calc.download(".xyz")    # geometry
calc.download(".out")    # ORCA's output; NWChem uses ".nwo", ".molden"
calc.download(".inp")    # ORCA's input; NWChem uses ".nwi"

Computing

Every compute method takes an orbital name, an index, an Orbital, or a list of them. Every other argument has a default:

calc.momentum_map("HOMO", hnu=30.0,           # photon energy [eV]
                  k_max=3.0, points=200,
                  angles=(0, 30, 0),          # orientation (phi, theta, psi) [deg]
                  substrate="fcc110",         # average over its domains
                  polarisation=(45, 0),       # (polar, azimuth) of A [deg]
                  polarisation_type="linear", # or "circular", "toroid"
                  s_share=0.0,                # s-polarised share [%]
                  handedness="left",          # or "right", "cd"
                  gamma=None,                 # IMFP damping [Å⁻¹]; None computes
                                              # it from the kinetic energy, as the
                                              # website itself does
                  normalise=False)

calc.momentum_map(["HOMO", "HOMO-1"], weights=[1.0, 0.5])   # incoherent sum

calc.momentum_map("HOMO", kinetic_energy=15.5)   # E_kin directly, instead of hν

calc.wavefunction("HOMO", extent=8.0, points=64)       # signed ψ(r)
calc.density(["HOMO", "HOMO-1"], extent=8.0)           # Σ|ψ(r)|²
calc.momentum_density("HOMO", k_max=3.0)               # |ψ̃(k)|²

kinetic_energy, if given, is used directly instead of deriving it from hnu. E_kin = hnu + orbital.energy, with the binding energy negative, as on the entry page. Several orbitals are summed incoherently, each at its own kinetic energy; one the photon cannot emit contributes nothing.

gamma (the inelastic-mean-free-path damping) is computed automatically from each orbital's kinetic energy unless you override it — the same "universal curve" the website's own JS uses. handedness="cd" depends on it, so it is zero everywhere only if you explicitly pass gamma=0.

Energy spectrum

A broadened density of states, like the entry page's energy plot:

energies, intensity = calc.energy_spectrum(fwhm=0.15, shape="gaussian")   # both eV

shape is "gaussian" or "lorentzian"; energy_range=(low, high) restricts the window, otherwise it is sized around the orbital energies automatically.

Excited states

A TD-DFT (casida) calculation carries its excited states, and each is a coherent sum of one-electron transitions. calc.calculation_type is "groundstate" or "casida"; find casida calculations directly rather than checking .excitations for a non-empty list as a side effect:

casida_calcs = db.calculations(calculation_type="casida")
state = calc.excitation(5)             # the 5th root, as the code numbered it
state.energy, state.oscillator_strength, state.tda
state.holes()                          # every occupied orbital it empties

Photoemission from an exciton is one map per photohole, each at its own kinetic energy hν + ε_j + Ω — an entangled state genuinely looks different at each of them, which is the point of measuring it:

for hole in state.holes():
    image = calc.exciton_momentum_map(state, hole, hnu=35.0)

Underneath, the coherent sum over conduction orbitals is a linear combination of coefficient rows, so it is a coefficient row — one field evaluation per photohole, not one per transition:

row = calc.dyson_row(state, hole=32)   # same shape as any coefficients.bin row

coverage= is the target fraction of the state's weight its kept pairs must cover (0.95 by default, matching the website; the stored file itself covers 0.99, so that is the ceiling). Omit hole= to sum every photohole of the state, which is what an analyser with no energy resolution would see.

Working offline

calc.save("naphthalene/")              # basis.bin + coefficients.bin + calculation.json
calc = physikmdb.load("naphthalene/")  # same object, no network at all

load() also opens a folder holding just basis.bin and coefficients.bin — the website's download button, or your own writer. Without calculation.json there are no orbital names or energies, so address orbitals by index and pass kinetic_energy=.

Units

eV and Ångström, the same units the website's own controls are labelled in. Energies in eV, k_max and gamma in Å⁻¹, extent in Å.

Orbitals carry both: orbital.energy is eV, orbital.energy_hartree is Hartree. physikmdb.units holds the two constants and the four conversions, and is the only place in the package where a number changes meaning.

Plotting

Optional, and deliberately small — enough to see whether a map looks right:

pip install physikmdb[plot]
from physikmdb import plot

ax = plot.momentum_map(image, k_max=3.0, title="HOMO")
ax.figure.savefig("homo.png")   # it's a plain matplotlib Axes - use it as usual

Each function takes and returns an ordinary Axes (ax= to draw into an existing one), so once matplotlib is installed you drive it directly - import matplotlib.pyplot as plt for multi-panel figures, ax.figure for anything else. Nothing outside physikmdb.plot imports matplotlib.

The kernels, unconverted

For your own basis and coefficients, or when you want nothing at all between you and the C:

from physikmdb import kernels        # Hartree, Bohr, Bohr⁻¹ throughout

basis = kernels.read_basis("basis.bin")
rows  = kernels.read_coefficients("coefficients.bin", basis)
image = kernels.momentum_map(basis, rows[21], E_kin=0.779, k_max=1.59)

kernels.Basis is nine plain numpy arrays, so a basis you built yourself works the same way. physikmdb.binary reads and writes the basis.bin / coefficients.bin format the website serves.

Examples

examples/ in the source distribution, simplest first:

01_first_map.py one orbital, one map
02_browse.py systems, calculations, filters, orbitals
03_orbital_series.py a map per orbital, and plotting
04_experiment.py tilt, substrate, polarisation, dichroism, damping
05_offline_and_fields.py save/load, and the 3D fields
06_energy_spectrum.py the broadened density of states
07_kernels_directly.py the atomic-units layer, and your own basis

Licence

EUPL-1.2. See LICENSE.

The scientific data served by a PhysikMDB instance is licensed separately — see physikmdb.uni-graz.at/license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

physikmdb-1.5.0.tar.gz (81.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

physikmdb-1.5.0-py3-none-win_amd64.whl (113.7 kB view details)

Uploaded Python 3Windows x86-64

physikmdb-1.5.0-py3-none-manylinux_2_28_x86_64.whl (81.9 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

physikmdb-1.5.0-py3-none-macosx_11_0_universal2.whl (94.1 kB view details)

Uploaded Python 3macOS 11.0+ universal2 (ARM64, x86-64)

File details

Details for the file physikmdb-1.5.0.tar.gz.

File metadata

  • Download URL: physikmdb-1.5.0.tar.gz
  • Upload date:
  • Size: 81.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for physikmdb-1.5.0.tar.gz
Algorithm Hash digest
SHA256 4cdadb85d5e29915fa7d4b2196f644b01941cdb8991f3aaac5884e58c46e053c
MD5 fe12830de2a99d54fe5f1cb4ccc2b2d3
BLAKE2b-256 eaa666663ea010c737b50336786dee2336a426c6a0a600a763b8bb1a634270b0

See more details on using hashes here.

File details

Details for the file physikmdb-1.5.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: physikmdb-1.5.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 113.7 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for physikmdb-1.5.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 f7f0ef51e41723e2c3fb5ecc74fc3ab6023d2b861b32f9b797922af6d54c0e64
MD5 fb57743326ecf7aded4f818f7b57bee2
BLAKE2b-256 118587fb2fb80c90c47f178f4c3b1f682e1a0da8607b1bc853f20f7b9b2b3401

See more details on using hashes here.

File details

Details for the file physikmdb-1.5.0-py3-none-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: physikmdb-1.5.0-py3-none-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 81.9 kB
  • Tags: Python 3, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for physikmdb-1.5.0-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 768313a033f3d1134ee390153d823b416fdac6e2cffd5f89ddbd7c1a253d7671
MD5 53312d407ff6c1243895bb7d16b1c325
BLAKE2b-256 962c4b71dc5e68aed2a0b889fed13e84fcec8864a4ecf6e11b70dc8daca10f4c

See more details on using hashes here.

File details

Details for the file physikmdb-1.5.0-py3-none-macosx_11_0_universal2.whl.

File metadata

  • Download URL: physikmdb-1.5.0-py3-none-macosx_11_0_universal2.whl
  • Upload date:
  • Size: 94.1 kB
  • Tags: Python 3, macOS 11.0+ universal2 (ARM64, x86-64)
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for physikmdb-1.5.0-py3-none-macosx_11_0_universal2.whl
Algorithm Hash digest
SHA256 e33a0b1cf1eb9b56b2b851e2e1a94d4ef9f7a48508f1dcb8bd64234d9caeadf6
MD5 5e097866142bf2c305e1076e3f17e14f
BLAKE2b-256 59c733caabf9a651d00c2563c2a0ad5b7083bfcda19c27057390ddb7340a7ff6

See more details on using hashes here.

Release history Release notifications | RSS feed

1.8.3

4 files

1.8.2

4 files

1.8.0

4 files

1.6.1

4 files

1.6.0

4 files

This release

1.5.0 This release

4 files

1.2.0

4 files

1.0.0

4 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page