diff --git a/.gitignore b/.gitignore index 353d06f..20f1cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ nul /.claude/ /temp - untracked/ /logs +.claudeignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 68f34ec..fba6c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,64 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht ## [Unreleased] +## [0.4.0] - 2026-06-18 + +Interactive-visualization and offline-readiness release. Adds molecular-orbital +isosurfaces and an interactive pre-optimization preview, reworks the 3D viewers +to preserve camera orientation across frames, makes all 3D rendering work +offline, and substantially speeds up startup. + +### Added + +- **Molecular-orbital isosurfaces (py3Dmol)** — interactive HOMO / LUMO / MO + isosurface viewer rendered with py3Dmol; the downsampled Plotly path remains a + fallback. +- **Interactive classical pre-optimization** — a **Preview** button relaxes the + geometry with a fast bonded force field (RDKit MMFF94 → UFF) and animates the + relaxation in place; **Keep this geometry** adopts it as the active structure + or **Revert** discards it. Stepper controls (play/pause, prev/next, scrub + slider, and an input ⇄ relaxed flip) let you compare geometries, and the + captured trajectory is sampled at even RMSD spacing for smooth playback. +- **Cancel button** — stop a running calculation cooperatively at the next SCF + cycle / optimization step. +- **Live vibrational-animation framerate** — the Vib fps setting updates the + running animation immediately. + +### Changed + +- **Single persistent 3D viewers** — the trajectory and vibrational-mode viewers + now load all frames into one py3Dmol viewer and switch frames/modes + client-side, so the camera (rotation/zoom) is preserved across steps and modes + and there is no per-frame rebuild or flicker. +- **Pre-optimization is Preview-only** — the silent "classical pre-optimize" + checkbox is gone; pre-optimization happens only through the transparent + Preview → Keep/Revert flow, so nothing relaxes the geometry invisibly. (The + separate QM "geometry optimization before calculation" option is unchanged.) +- **Offline-first 3D rendering** — 3Dmol.js is vendored and loaded per-view from + a local `data:` URI instead of a CDN, so every 3D view works with no network + (the build fails if the vendored asset is missing). Native launchers tolerate + offline `pip install`. +- **Faster startup** — GPU detection and History/Compare population are deferred + off the synchronous construction path, so the UI paints in ~1 s instead of + ~15 s; the GPU status badge and dropdowns fill in shortly after. +- **Clear** of the live calculation log is disabled while a calculation runs. + +### Fixed + +- **GPU-offloaded result extraction** — HOMO–LUMO gap, dipole moment, and + Mulliken charges are now reported for GPU runs. CuPy arrays are copied to host + before extraction, and Mulliken falls back to the CPU object (gpu4pyscf does + not implement population analysis on the GPU). +- **Vibrational animation glitchiness** — stacked animation loops (a new loop + started on every mode switch) made playback jittery and too fast and ignored + the framerate setting; exactly one loop now runs. +- **Cancel status** no longer sticks on "Cancelling…" after a calculation is + cancelled. +- **Stale run status** — "Pre-optimized geometry accepted." is cleared when a new + molecule is loaded or a preview is reverted. +- Structure provenance is reported and the input viewer is persisted across + reloads. + ## [0.3.0] - 2026-06-11 Structure-sourcing release. Repairs the external-database structure search and diff --git a/README.md b/README.md index 450bc20..20d9bb0 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,22 @@ research and classroom use. ## What it does -- **Molecule input** — paste XYZ coordinates, draw from a 20+ preset library, - or search PubChem by name or SMILES +- **Molecule input** — paste XYZ coordinates, browse an indexed three-tier + bundled library (20 presets + 156 curated molecules + ~1,900 QM9 structures, + searchable by name/formula), or run a structure search by name, SMILES, + InChI, PubChem CID, InChIKey, or CAS number (PubChem → NCI CACTUS → offline + bundled-library fallback; SMILES/InChI resolve locally with no network) +- **Offline-first** — runs with no internet: the bundled molecule library and + the 3D viewer's JavaScript (3Dmol.js) are vendored, so structure lookup and + every 3D view work in an air-gapped classroom. (Network is used only for the + optional live PubChem/CACTUS search.) - **3D visualization** — interactive py3Dmol viewer (py3Dmol-first; optional plotlymol3d fallback for non-trajectory tasks). A capability-aware backend router picks the right renderer per task, and a Status-tab toggle persists your default-backend preference between sessions -- **In-session calculations** — RHF, UHF, 9 DFT functionals, MP2, NMR - shielding, TD-DFT UV-Vis, and 1D PES scans via PySCF, running in your - Python kernel (no batch submission) +- **In-session calculations** — RHF, UHF, 9 DFT functionals, MP2, CCSD, + CCSD(T), NMR shielding, TD-DFT UV-Vis, and 1D PES scans via PySCF, running + in your Python kernel (no batch submission) - **Implicit solvent** — PCM solvation (Water, Ethanol, THF, DMSO, Acetonitrile) via a single checkbox - **Rich results** — total energy, HOMO-LUMO gap, Mulliken charges, dipole @@ -320,6 +327,8 @@ Five step-by-step notebooks in [`notebooks/tutorials/`](notebooks/tutorials/): | HSE06 | DFT screened hybrid | Band gaps, large molecules | | PBE-D3 | DFT GGA + dispersion | Van der Waals complexes, stacking | | MP2 | Post-HF | Accurate energetics for small molecules (O(N⁵)) | +| CCSD | Post-HF coupled cluster | High-accuracy small-molecule energies (O(N⁶)) | +| CCSD(T) | Post-HF coupled cluster | Benchmark "gold standard" energies (O(N⁷); CPU only) | ### Calculation types @@ -378,10 +387,14 @@ quantui/ Main package optimizer.py QM geometry optimization with trajectory visualization_py3dmol.py 3D viewer (py3Dmol-first; plotlymol fallback) viz_backend_router.py Capability-aware backend router (pure function) + viz_assets.py Offline-safe 3Dmol.js loading (vendored, no CDN) user_settings.py Persistent user preferences (~/.quantui/settings.json) vib_cache.py On-disk cache of rendered vib-mode HTML orbital_visualization.py Orbital energy diagrams + cube-file viewer - pubchem.py PubChem molecule search + pubchem.py Structure search client (PubChem + RDKit) + cactus.py NCI CACTUS resolver (fallback structure source) + structure_providers.py Unified resolver chain with offline fallback + molecule_library.py Indexed 3-tier bundled molecule library comparison.py Side-by-side result tables results_storage.py Timestamped result persistence (schema v2) calc_log.py Performance + event logging, time estimation @@ -389,11 +402,12 @@ quantui/ Main package benchmarks.py Timing calibration benchmark suite config.py Methods, basis sets, solvent/NMR options, presets ase_bridge.py ASE structure I/O - preopt.py LJ force-field pre-optimization + preopt.py RDKit MMFF94/UFF force-field pre-optimization + data/ Bundled library (SQLite + manifests) + vendored 3Dmol.js notebooks/ molecule_computations.ipynb Main user-facing interface (3-cell launcher) tutorials/ Step-by-step guided notebooks (01–05) -tests/ pytest test suite (~1000 tests) +tests/ pytest test suite (~1500 tests; run in parallel via pytest-xdist) apptainer/ Container definition for reproducible deployment local-setup/ Conda environment definition pyproject.toml Package metadata and tool config diff --git a/apptainer/README.md b/apptainer/README.md index 262f624..dcdeadd 100644 --- a/apptainer/README.md +++ b/apptainer/README.md @@ -1,10 +1,17 @@ # QuantUI — Apptainer Container -The Apptainer container packages Python, PySCF, ASE, py3Dmol, and Voilà +The Apptainer container packages Python, PySCF, RDKit, ASE, py3Dmol, and Voilà into a single portable `.sif` file. It is the **recommended path for Windows users** (via WSL) and for anyone who wants a zero-installation experience — students copy one file and run it. +**Runs fully offline.** The container bundles everything it needs — the +3-tier molecule library and the 3D viewer's JavaScript (3Dmol.js) are vendored, +so structure lookup and every 3D view (molecules, trajectories, vibrations, +orbital isosurfaces) work with **no internet connection**. Network is only ever +used for the optional live PubChem/CACTUS structure search. Ideal for an +air-gapped or restricted-network classroom. + --- ## Contents @@ -85,8 +92,8 @@ bash apptainer/build.sh --clean --test bash apptainer/build.sh --fakeroot ``` -Build time: **~6 minutes** on a modern laptop with a good internet connection. -Final image size: **~4–5 GB**. +Build time: **~20–40 minutes** (dominated by the conda solve + PySCF download) +on a modern laptop with a good internet connection. Final image size: **~4–5 GB**. The script must be run from the **repo root** (not from `apptainer/`) because the `.def` file copies the entire repo root into the container with @@ -247,6 +254,14 @@ B3LYP/STO-3G: -75.312587 Ha converged: True | `PBE` | DFT GGA | Large molecules, speed-critical | | `PBE0` | DFT hybrid | Charge transfer, band gaps | | `M06-2X` | DFT meta-hybrid | Reaction barriers, thermochemistry | +| `wB97X-D`, `CAM-B3LYP` | DFT range-separated | Non-covalent / charge-transfer / UV-Vis | +| `M06-L`, `HSE06`, `PBE-D3` | DFT (meta-GGA / screened / dispersion) | Large systems, band gaps, vdW complexes | +| `MP2` | Post-HF | Accurate small-molecule energetics (O(N⁵)) | +| `CCSD`, `CCSD(T)` | Post-HF coupled cluster | Benchmark-quality energies (O(N⁶)/O(N⁷); (T) is CPU-only) | + +Six calculation types run over these: Single Point, Geometry Opt, Frequency +(+ thermochemistry / IR), UV-Vis (TD-DFT), NMR shielding, and 1D PES scan; PCM +implicit solvent (Water, Ethanol, THF, DMSO, Acetonitrile) is a single checkbox. ### Basis sets @@ -377,12 +392,14 @@ sudo apt-get install -y apptainer | Layer | Contents | | --- | --- | | Base | `continuumio/miniconda3:latest` (Debian + conda) | -| conda-forge | jupyter, jupyterlab, ipywidgets, pyscf, numpy, scipy, matplotlib, plotly, h5py | +| conda-forge | jupyter, jupyterlab, ipywidgets, notebook, pyscf, numpy, scipy, matplotlib, plotly, h5py, rdkit | | pip | voila, ase, py3dmol, requests | -| QuantUI | installed from `/opt/quantui` (the repo root, copied at build time) | +| QuantUI | installed from `/opt/quantui` (the repo root, copied at build time) — bundles the molecule library + vendored 3Dmol.js for offline use | -The `.git` directory and `__pycache__` folders are removed during build to -keep the image lean. +The `.git` directory, `__pycache__` folders, and internal dev files are removed +during build to keep the image lean. A build-time check asserts the vendored +3Dmol.js is present and the viewer is CDN-free, so a broken offline build fails +fast instead of shipping blank 3D views. --- @@ -392,12 +409,12 @@ Edit `%labels` in `quantui.def` to bump the version string, then rebuild: ```singularity %labels - Version "0.2.0" + Version "0.3.0" ``` Tag the git commit and push so the version is traceable: ```bash -git tag v0.2.0 -git push origin v0.2.0 +git tag v0.3.0 +git push origin v0.3.0 ``` diff --git a/apptainer/quantui.def b/apptainer/quantui.def index f37036a..b67cc96 100644 --- a/apptainer/quantui.def +++ b/apptainer/quantui.def @@ -21,7 +21,7 @@ FROM: continuumio/miniconda3:latest %labels Maintainer "Jonathan Schultz" Purpose "Local teaching interface for quantum chemistry calculations" - Version "0.1.0" + Version "0.4.0" %environment export PATH="/opt/conda/bin:${PATH}" @@ -72,6 +72,11 @@ FROM: continuumio/miniconda3:latest python -c "import pyscf; print('PySCF OK')" python -c "import rdkit; print('RDKit OK')" python -c "import py3Dmol; print('py3Dmol OK')" + # Offline 3D: the vendored 3Dmol.js must be bundled and make_view must emit a + # CDN-free viewer that loads it from a local data: URI, or every 3D view + # blanks with no network (the whole point of the offline build). Fail the + # build here rather than ship blank viewers. + python -c "from quantui.viz_assets import _JS_PATH, _js_data_uri, make_view; assert _JS_PATH.exists() and _JS_PATH.stat().st_size > 100000, 'vendored 3Dmol.js missing/too small'; assert _js_data_uri().startswith('data:text/javascript;base64,'); v = make_view(width=80, height=80); v.addModel('1\nH\nH 0 0 0', 'xyz'); h = v._make_html(); assert 'jsdelivr' not in h and 'data:text/javascript;base64,' in h, 'viewer not loading vendored 3Dmol offline'; print('offline 3Dmol OK')" python -c "import ase; print('ASE OK')" python -c "from quantui import optimize_geometry; print('optimize_geometry OK')" python -c "from quantui import run_freq_calc, run_tddft_calc; print('freq/tddft OK')" diff --git a/docs/CLI.md b/docs/CLI.md index a835585..1f8fb10 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -66,7 +66,7 @@ quantui log tail -n 200 | grep -i error | tail -5 ``` 2026-05-25T13:55:22.421910+00:00 viz_route_decision task=molecule_preview pref=auto chosen=py3dmol reason=auto -> task primary (py3dmol) -2026-05-25T13:55:22.470028+00:00 startup QuantUI 0.2.0 started +2026-05-25T13:55:22.470028+00:00 startup QuantUI 0.3.0 started (viz backend pref=auto) 2026-05-25T14:08:14.102544+00:00 calc_done B3LYP/STO-3G on H2O elapsed_s=1.2 converged=True gpu_used=True gpu_name=NVIDIA GeForce RTX 4050 Laptop GPU ``` diff --git a/docs/index.html b/docs/index.html index 9dec9d0..29ee797 100644 --- a/docs/index.html +++ b/docs/index.html @@ -339,7 +339,7 @@