diff --git a/.gitattributes b/.gitattributes index cc963bc..da16616 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,7 @@ # Auto detect text files and perform LF normalization * text=auto -# Shell scripts must always use LF — CRLF breaks bash on Linux/WSL +# Shell scripts must always use LF — CRLF breaks bash on Linux/WSL/macOS *.sh text eol=lf +*.command text eol=lf apptainer/*.def text eol=lf diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 20d02e9..269a6e9 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -32,7 +32,14 @@ with transparent and extensible open tooling). ``` QuantUI/ ├── quantui/ ← Main Python package (imports as `quantui`) -│ ├── app.py ← QuantUIApp class — all widgets, callbacks, state +│ ├── app.py ← QuantUIApp — orchestration + run dispatch +│ ├── app_analysis.py ← Analysis-tab panel registry + _pop_* methods +│ ├── app_builders.py ← _build_* widget construction +│ ├── app_runflow.py ← _do_run + run/orchestration UI handlers +│ ├── app_visualization.py ← Trajectory / vib / IR / orbital / PES rendering +│ ├── app_history.py ← History tab loaders, replay context +│ ├── app_formatters.py ← Result-card and text formatters +│ ├── app_exports.py ← Export handlers (XYZ/MOL/PDB/script) │ ├── molecule.py ← Molecule dataclass + XYZ/SMILES parsing │ ├── session_calc.py ← In-session PySCF runner (run_in_session) │ ├── optimizer.py ← QM geometry optimization (ASE-BFGS + PySCF) @@ -46,6 +53,9 @@ QuantUI/ │ ├── calc_log.py ← Performance + event logging (JSONL) │ ├── pubchem.py ← PubChem molecule search │ ├── visualization_py3dmol.py ← 3D molecular viewer (py3Dmol / plotlyMol) +│ ├── viz_backend_router.py ← Capability-aware backend router (pure function) +│ ├── user_settings.py ← Persistent user preferences (~/.quantui/settings.json) +│ ├── vib_cache.py ← On-disk cache of rendered vib-mode HTML │ ├── ase_bridge.py ← ASE structure I/O + molecule library │ ├── preopt.py ← ASE force-field pre-optimisation (fast, no PySCF) │ ├── progress.py ← StepProgress widget @@ -61,7 +71,7 @@ QuantUI/ ├── notebooks/ │ ├── molecule_computations.ipynb ← Student-facing Voilà app (thin launcher) │ └── tutorials/ ← 01–05 step-by-step tutorial notebooks -├── tests/ ← pytest suite (~875 tests) +├── tests/ ← pytest suite (~1000 tests; 97 PySCF-gated skip on Windows) ├── .github/ │ └── copilot-instructions.md ← This file ├── apptainer/ @@ -70,10 +80,21 @@ QuantUI/ ├── local-setup/ ← Conda environment YAMLs ├── launch-app.bat ← Windows double-click launcher (Voilà app mode) ├── launch-dev.bat ← Windows double-click launcher (JupyterLab mode) +├── CHANGELOG.md ← Release history (Keep a Changelog format) ├── pyproject.toml ← Package config (name: quantui, imports as quantui) └── pytest.ini ← pytest configuration ``` +**Modular UI note.** `QuantUIApp` lives in `app.py`, but most of its logic is +implemented as module-level functions in `app_builders.py`, `app_analysis.py`, +`app_runflow.py`, `app_visualization.py`, `app_history.py`, `app_formatters.py`, +and `app_exports.py`. `app.py` keeps thin instance-method wrappers that pass +`self` through (e.g. `def _pop_energies(self, ctx): return _ana_pop_energies(self, ctx)`). +When working on UI changes, prefer editing the relevant companion module +rather than growing `app.py`. The conservative refactor close (DEC-014) +intentionally leaves `_do_run` and a small molecule/theme/pubchem callback +cluster in `app.py`. + --- ## Architecture @@ -208,6 +229,113 @@ to build the context from disk. --- +## Visualization Backend Router + +3D rendering is dispatched through a pure-function router in +`quantui/viz_backend_router.py`. **Do not call py3Dmol or plotlymol3d +directly from `app_visualization.py` — always go through the router.** + +### `VizTask` keys + +`MOLECULE_PREVIEW`, `STRUCTURE_VIEW_RESULTS`, `ANALYSIS_STRUCTURE_VIEW`, +`HISTORY_STRUCTURE_REPLAY`, `TRAJECTORY_FRAME`, `TRAJECTORY_EXPORT`, +`VIB_INTERACTIVE`, `VIB_EXPORT`, `ORBITAL_ISOSURFACE`. + +### Policy + +- Each task has a `(primary, fallback)` tuple. +- User preference (`VizPreference.AUTO | PY3DMOL | PLOTLYMOL`) is respected + for tasks that support both backends. +- Single-backend tasks **ignore preference** (e.g. `TRAJECTORY_FRAME` is + py3Dmol-only — Plotly causes flicker; `ORBITAL_ISOSURFACE` is py3Dmol-only). +- `BackendAvailability.from_environment()` probes imports at startup; the + router falls back gracefully when one backend is missing. + +### Usage + +```python +from quantui.viz_backend_router import VizTask, select_backend +decision = app._resolve_backend(VizTask.STRUCTURE_VIEW_RESULTS) +# decision.chosen is "py3dmol", "plotlymol", or None (no renderer) +# decision.reason carries a human-readable explanation +``` + +`Decision` is a frozen dataclass — never mutate it. + +### Calculate ↔ Analysis toggle sync + +The Calculate and Analysis tabs each have a "Default 3D backend" ToggleButton. +They are kept in sync via `_set_viz_preference(...)`, gated by +`_viz_sync_in_progress` to prevent observer echo loops. The preference is +persisted to `~/.quantui/settings.json` (`viz.default_backend`). + +--- + +## Lifecycle Telemetry + +Every render-dispatch site in `app_visualization.py` is wrapped in the +`_viz_render_event(app, task, backend, **extras)` context manager. It emits +three event types to `event_log.jsonl`: + +| Event | When | +| --- | --- | +| `viz_render_start` | Entry into the context | +| `viz_render_done` | Successful exit, with `elapsed_ms` | +| `viz_render_error` | Exception in the body, with `elapsed_ms` + `error` | + +**All four render dispatch sites are wrapped:** static structure view, +trajectory frame, vib mode, and the vib sync cache-hit fast path. Use this +helper for any new render call so telemetry stays uniform. + +--- + +## Persistent User Settings + +`quantui/user_settings.py` provides `UserSettings.load()` / +`UserSettings.save()`, persisted to `~/.quantui/settings.json` (override with +`QUANTUI_SETTINGS_PATH` for testing). + +Current schema (`_schema_version = 1`): + +| Section | Field | Default | Purpose | +| --- | --- | --- | --- | +| `viz` | `default_backend` | `"auto"` | One of `auto / py3dmol / plotlymol` | +| `viz` | `vib_framerate_fps` | `10` | Clamped `[1, 120]`; included in vib cache key | + +**Robustness rules:** atomic writes (`.tmp` + rename); missing file, malformed +JSON, unknown schema version, missing sections, or invalid values all fall +back to defaults with a single warning log — startup never crashes on bad +settings. Schema growth is additive; bump `_schema_version` only for +breaking changes. + +--- + +## Vib-Animation Disk Cache + +`quantui/vib_cache.py` stores rendered py3Dmol HTML for each vibrational mode +under `/vib_frames/`: + +``` +/ +└── vib_frames/ + ├── index.json ← manifest (schema v1) + ├── mode_001.html + └── ... +``` + +**Cache key:** `(result_dir, mode_number, n_frames, amplitude, renderer, fps)`. +Any parameter change → stale → cache miss → re-render. + +**Sync cache-hit fast path:** `_swap_vib_output()` atomically swaps in cached +HTML without a transient "Rendering…" placeholder, eliminating flash on +mode switches. + +**Staleness guard:** `_vib_render_token` is incremented on every render +request; background renders that finish after a newer token has been issued +bail out instead of overwriting newer output. + +--- + ## Analysis Tab — 8 Panels All 8 panels are **always in the DOM** (`layout.display=""`, `selected_index=None`). @@ -527,8 +655,8 @@ Test files in `tests/`: **PySCF-gated tests** use `@pytest.mark.skipif(not _PYSCF_AVAILABLE, ...)`. On Windows, these become skips — not failures. -**Baseline (WSL, 2026-05-01; `python -m pytest tests/ -q --no-cov`):** -860 passed, 15 skipped (875 collected). +**Baseline (Windows `quantui-win`, 2026-05-22; `python -m pytest tests/ -q --no-cov`):** +1004 passed, 97 skipped (the 97 skips are PySCF-gated Linux-only tests). --- @@ -553,6 +681,7 @@ Install all runtime + dev extras: `pip install -e ".[pyscf,ase,app,notebook,dev] | --- | --- | --- | | `QUANTUI_RESULTS_DIR` | `./results` | Where calculation results are saved | | `QUANTUI_LOG_DIR` | `~/.quantui/logs` | Where perf_log and event_log live | +| `QUANTUI_SETTINGS_PATH` | `~/.quantui/settings.json` | User-preferences file (`user_settings.py`); override for tests | --- diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2f2f8a7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,198 @@ +# Changelog + +All notable changes to QuantUI are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.2.0] - 2026-05-22 + +First substantial release after `v0.1.0`. The codebase moved from a single +monolithic `app.py` to a modular package, added six PySCF-backed calculation +types end-to-end, introduced a results-persistence layer with history replay, +and shipped a complete visualization stack (3D viewer with selectable backend, +trajectory animation, IR/UV-Vis/PES plots, orbital isosurfaces, vibrational +mode animation with caching). UI runs as a Voilà app suitable for classroom +deployment. + +### Added + +#### Calculations + +- **Geometry optimization** (`optimizer.py`) — ASE-BFGS driver around a custom + PySCF calculator; per-step trajectory persisted. +- **Vibrational frequency analysis** (`freq_calc.py`) — Hessian via + `pyscf.hessian`, ZPVE, thermochemistry (H/S/G at 298 K), IR intensities via + `pyscf.prop.infrared` or a numerical-derivative fallback for compatibility + across PySCF versions. +- **TD-DFT UV-Vis** (`tddft_calc.py`) — excitation energies, oscillator + strengths, wavelengths; full spectrum plot in the Analysis tab. +- **NMR shielding** (`nmr_calc.py`) — GIAO shielding via `pyscf.nmr` (core + preferred over `pyscf-properties` to dodge a known upstream bug); ¹H/¹³C + chemical shifts relative to TMS. +- **1D PES scan** (`pes_scan.py`) — bond / angle / dihedral; energy profile + + per-step geometry animation. +- **PCM implicit solvent** — Water, Ethanol, THF, DMSO, Acetonitrile via a + single checkbox in the Calculate tab. +- **MP2** post-HF method support. + +#### Analysis & visualization + +- **Analysis tab with 8 always-in-DOM panels** (Energies, Trajectory, + Vibrational, IR Spectrum, PES Scan, Isosurface, UV-Vis, NMR) wired through + a `_PANEL_REGISTRY` so live runs and history replay share one code path. +- **IR spectrum chart** (`ir_plot.py`) — stick plot + Lorentzian-broadened + curve; broadening toggle and FWHM slider. +- **UV-Vis spectrum plot** — Plotly chart with wavelength/energy axes. +- **Orbital visualization** (`orbital_visualization.py`) — energy-level + diagram (matplotlib → Plotly HTML) and cube-file isosurface viewer with + HOMO-1/HOMO/LUMO/LUMO+1 toggle. +- **Trajectory animation** — atomic Output-children swap to avoid + Voilà-deferred-display blank frames; py3Dmol-only render path with + prev/next arrow navigation. +- **Vibrational mode animation** — py3Dmol multi-frame XYZ renderer with + amplitude scaling, prev/next mode nav, and dropdown skipping near-zero + modes. +- **3D visualization backend router** (`viz_backend_router.py`) — pure + function that picks py3Dmol or plotlymol3d per `VizTask` based on user + preference and runtime availability; immutable `Decision` carries chosen + backend, fallback, and reason. +- **Lifecycle telemetry** — `_viz_render_event` context manager emits + `viz_render_start` / `viz_render_done` / `viz_render_error` JSONL events + with backend, task, `elapsed_ms`, and extras at every render dispatch. +- **Side-by-side Compare tab** — pick any two saved calculations and view a + diff table. + +#### Persistence & logging + +- **Results storage** (`results_storage.py`) — every run is saved to a + timestamped directory containing `result.json` (schema v2, additive-only), + `pyscf.log`, optional `trajectory.json` / `orbitals.npz` / `thumbnail.png`. +- **History tab** — browse and replay saved calculations after a kernel + restart; replay path is identical to live-run analysis activation. +- **Performance log** (`calc_log.py`) — `perf_log.jsonl` per converged run + + `event_log.jsonl` for startup/calc/error events; 7-day auto-prune. +- **Time estimator** — 4-strategy priority chain (N_basis-normalised → cross-method + electron-count) populates "Estimated time" before each run. +- **Benchmark suite** (`benchmarks.py`) — one-click calibration suite to + populate the time-estimator history with real machine data. +- **Issue tracker** (`issue_tracker.py`) — in-app bug-report UI writing to a + local `issues.db`. +- **Persistent user settings** (`user_settings.py`) — stored at + `~/.quantui/settings.json` (override via `QUANTUI_SETTINGS_PATH`). Schema + is section-based for additive growth, with atomic writes and graceful + fallback to defaults on corruption. +- **Vibrational-animation disk cache** (`vib_cache.py`) — per-result-dir + `vib_frames/` of pre-rendered py3Dmol HTML keyed by + `(mode, n_frames, amplitude, renderer, fps)`. Mode switches on repeat + visits and history replay are instant. +- **Vib FPS user preference** — `viz.vib_framerate_fps` exposed as an + IntSlider in the Status tab (clamped 1–120, default 10); included in the + vib cache key so changing FPS invalidates cleanly. + +#### UI + +- **Modular UI package** — `app.py` (orchestration) plus `app_analysis.py`, + `app_builders.py`, `app_exports.py`, `app_formatters.py`, `app_history.py`, + `app_runflow.py`, `app_visualization.py`. +- **Seven-tab layout** — Calculate, Results, Analysis, History, Compare, Log, + Status — with a floating Help overlay (not a tab). +- **Light / Dark theme selector** — dark by default on startup. +- **Status tab** — environment info, performance-history accordion (two-step + reset), default-3D-backend toggle, vib-FPS slider. +- **Files tab + activity indicator** for browsing saved results. +- **Plot export UI** — save IR, UV-Vis, PES, orbital diagram plots as HTML. +- **Scroll guard** for the run output area to keep long PySCF logs from + jumping the page. +- **Welcome header**, completion banner, structured log header/footer. +- **Compare-tab Copy-path button** (replaced a broken Open-folder action). +- **Result directory label + log accordion** showing inline `pyscf.log`. +- **Structure exports** — XYZ, MOL/SDF, PDB, plus a standalone runnable `.py` + script export. + +#### Tooling & dev + +- **Test suite grew from a handful to 1004 passed / 97 skipped** (Windows + `quantui-win` env baseline; the 97 skips are PySCF-gated Linux-only tests). +- New analysis-history end-to-end tests for every calc type + (`test_sp_analysis_history.py`, `test_geo_opt_analysis_history.py`, + `test_freq_analysis_history.py`, `test_tddft_analysis_history.py`, + `test_nmr_analysis_history.py`, `test_pes_scan_analysis_history.py`). +- `test_code_quality.py` enforces: + - No `include_plotlyjs="cdn"` anywhere (fails silently in offline Voilà). + - No bare `except: pass` blocks. +- `test_viz_backend_router.py` + `test_viz_backend_sync.py` — full + task × preference × availability matrix and Calculate/Analysis toggle sync. +- `test_vib_cache.py`, `test_vib_py3dmol_render.py`, + `test_viz_render_telemetry.py` — vib animation + telemetry coverage. +- `_layout(...)` helper sanitises `widgets.Layout` kwargs to eliminate a + 4808 → 13 traitlets warning regression. +- `_safe_cb` wrapper around every `.observe()` callback so exceptions surface + in the Log tab instead of disappearing into the Voilà kernel console. +- Kernel `io_loop` is cached at startup; thread-spawned callbacks are queued + onto the main thread to avoid `RuntimeError: no current event loop`. +- Native launchers: `launch-native.bat` (Windows / WSL) and + `launch-native.command` (macOS / Linux) — double-clickable, port `8867`, + stamp-based editable-install skip, browser auto-open. README documents + pinning each to the Start menu / Dock as a real app. +- Native JupyterLab launcher (`launch-native-jupyter.bat`) and Apptainer + launcher improvements. + +#### Docs + +- `.github/copilot-instructions.md` — canonical AI-assistant context (now + the single source of truth for any AI assistant working on this repo). +- `CLAUDE.md` — Claude-specific session/workflow context (git-ignored). +- Site favicons (ICO + SVG) for the GitHub Pages docs site. + +### Changed + +- **Visualization is py3Dmol-first.** `plotlymol3d` remains an optional + fallback for non-trajectory tasks; trajectory rendering is hard-wired to + py3Dmol to avoid Plotly/RequireJS flicker. +- **Plotly figures are rendered via `plotly.io.to_html(..., include_plotlyjs="require")`** + inside `widgets.HTML`, not `display(fig)`, so threaded renders work and + offline Voilà loads correctly. +- **`pyscf` is now an optional extra** (`pip install quantui[pyscf]`); the + package imports cleanly on Windows with PySCF unavailable. +- Repo renamed from `QuantUI-local` to `QuantUI`. + +### Fixed + +- **Trajectory accordion blank on first expand** — switched `traj_output` + from `Output` to `VBox` and use atomic children-swap so deferred + widget-display is no longer a blank-frame risk. +- **Vib mode races on rapid switching** — render-token guard (`_vib_render_token`) + causes stale background renders to bail rather than overwriting newer + output. +- **Camera state lost on mode switch** — JS hook caches the active + `$3Dmol.GLViewer` state across atomic HTML swaps; reset only on a + genuinely new frequency result. +- **PySCF API drift** — robust handling for v2 NMR / thermo API and the + `pyscf.prop.infrared` rename; both `Infrared.kernel()` and the older + IR API are supported. +- **Result-dir name collisions** — timestamps now include microseconds; same + formula + method + basis no longer overwrite each other. +- **IR x-axis** — corrected wavenumber axis on the IR Plotly figure. +- **Plotly figures invisible after accordion show** — figures are re-rendered + on accordion expand to handle RequireJS / display-deferral edge cases. + +### Removed + +- `visualization.py` (PlotlyMol fallback) — replaced by the router-backed + `visualization_py3dmol.py` path. +- All SLURM-era infrastructure already removed during the downstream port: + `job_manager.py`, `storage.py`, `slurm_errors.py`, SLURM config templates. + +## [0.1.0] - 2026 + +Initial public scaffolding of the QuantUI package: `quantui` package with +`molecule.py`, `pubchem.py`, `config.py`, `visualization_py3dmol.py`, +`calculator.py`, basic notebook launcher, Apptainer container definition, +MIT license, and project metadata. + +[Unreleased]: https://github.com/The-Schultz-Lab/QuantUI/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/The-Schultz-Lab/QuantUI/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/The-Schultz-Lab/QuantUI/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 634c7d0..5a6641c 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,15 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Python](https://img.shields.io/badge/python-3.9%20|%203.10%20|%203.11-blue)](https://www.python.org) -An interactive Jupyter interface for running quantum chemistry calculations -locally — no cluster account, no SLURM, no queueing. Students design -molecules, launch PySCF calculations in their own Python session, and -visualize results in minutes. +A powerful open-source frontend for DFT and post-HF quantum chemistry. +QuantUI puts [PySCF](https://pyscf.org) behind an interactive Jupyter/Voilà +UI so you can build molecules, run calculations locally, and visualize the +results — no cluster account, no SLURM, no queueing. -Built for classroom teaching at the -[Schultz Lab, North Carolina Central University](https://github.com/The-Schultz-Lab). +Developed by the +[Schultz Lab, North Carolina Central University](https://github.com/The-Schultz-Lab) +as an open alternative to closed-source GUI workflows. Equally suitable for +research and classroom use. --- @@ -19,9 +21,10 @@ Built for classroom teaching at the - **Molecule input** — paste XYZ coordinates, draw from a 20+ preset library, or search PubChem by name or SMILES -- **3D visualization** — interactive py3Dmol or PlotlyMol viewer with a live - backend toggle when both are installed; post-calculation structure rendered - automatically in the results panel +- **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) @@ -34,16 +37,21 @@ Built for classroom teaching at the HOMO, LUMO, LUMO+1), and a side-by-side comparison table for multiple calculations - **Geometry optimization** — BFGS optimizer with step-by-step trajectory - animation; vibrational frequency analysis with animated normal modes + animation; vibrational frequency analysis with animated normal modes, + user-tunable playback FPS, and a per-result-directory disk cache so mode + switches on repeat visits and history replay are instant - **Results persistence** — every calculation is saved automatically to a - timestamped directory; a built-in browser lets students reload past results + timestamped directory; a built-in browser lets you reload past results after a kernel restart; the full `pyscf.log` is shown inline - **Structure exports** — download XYZ, MOL/SDF, or PDB files alongside the saved results; script export for a standalone `.py` file +- **Plot export** — save IR, UV-Vis, PES, and orbital diagrams as standalone + HTML - **Timing calibration** — one-click benchmark suite populates the time estimator with real machine data so predictions are accurate from the first run -- **Voilà app mode** — serve the notebook as a polished widget-only UI (no code - visible) for classroom demos, with dark mode toggle and dedicated output log +- **Voilà app mode** — serve the notebook as a polished widget-only UI (no + code visible), with Light/Dark themes, a dedicated output log, and an + in-app bug-report form --- @@ -98,7 +106,7 @@ conda activate quantui # JupyterLab (full IDE — shows code) jupyter lab notebooks/molecule_computations.ipynb -# Voilà app mode (widget-only — for classroom demos) +# Voilà app mode (widget-only UI — code hidden) voila notebooks/molecule_computations.ipynb ``` @@ -107,6 +115,83 @@ Open the notebook, pick a molecule, choose a method and basis set, and click --- +## Launching QuantUI as an app + +For the smoothest day-to-day experience, QuantUI ships two double-clickable +launchers that activate the right conda environment, install the editable +package on first run (and only re-install when `pyproject.toml` actually +changes), clear any stale bytecode, start Voilà on port `8867`, and open the +app in your default browser. Edits to `quantui/*.py` are picked up live with +no rebuild. + +| Platform | File | Action | +| --- | --- | --- | +| Windows | [`launch-native.bat`](launch-native.bat) | Activates the `quantui` conda env inside WSL Ubuntu, runs Voilà, and opens `http://localhost:8867` | +| macOS / Linux | [`launch-native.command`](launch-native.command) | Activates the local `quantui` conda env directly (no WSL needed) and does the same | + +Both launchers reuse port `8867`, so you can keep the same browser tab pinned +across platforms. + +### Windows — pin to the Start menu + +1. Right-click [`launch-native.bat`](launch-native.bat) in File Explorer + → **Send to** → **Desktop (create shortcut)**. +2. Rename the shortcut to something friendly like `QuantUI`. +3. *(Optional)* Right-click the shortcut → **Properties** → **Change Icon...** + and point at `docs\logo.ico` for a proper app icon. +4. Move the shortcut into your Start-menu folder so it appears with normal + apps. Either: + - press `Win+R`, paste + `%APPDATA%\Microsoft\Windows\Start Menu\Programs`, and drop the + shortcut there *(per-user — recommended)*; or + - paste `%ProgramData%\Microsoft\Windows\Start Menu\Programs` for an + all-users install. +5. Open the Start menu, find **QuantUI**, right-click it, and choose + **Pin to Start** (or **Pin to taskbar**). + +You now launch QuantUI like any other Windows app — one click and Voilà opens +in your browser. + +### macOS — pin to the Dock / Launchpad + +**Quickest:** double-click [`launch-native.command`](launch-native.command) +from Finder. macOS will open Terminal, run the script, and pop the app open +in your browser. The first launch is gated by Gatekeeper: right-click the +file → **Open** → **Open** to clear it (one time only). + +**App-like experience (recommended):** wrap the launcher in a tiny Automator +application so it lives in Launchpad and pins to the Dock. + +1. Open **Automator** (Spotlight → "Automator") → **New Document** → + **Application**. +2. In the actions library on the left, find **Run Shell Script** and drag it + into the workflow pane on the right. +3. Set **Shell** to `/bin/bash` and **Pass input** to **as arguments**, then + replace the script body with the single line below (adjust the path if + your clone lives elsewhere): + + ```bash + "$HOME/path/to/QuantUI/launch-native.command" + ``` + +4. **File → Save** → name it `QuantUI` → save into `/Applications`. +5. *(Optional)* Set a custom icon: in Finder, open `docs/logo.svg` in + **Preview**, **Edit → Select All → Copy**, then in Finder select the + new `QuantUI.app`, **File → Get Info**, click the small icon in the + top-left of the Info window, and **Edit → Paste**. +6. Open Launchpad, find **QuantUI**, drag it into the Dock to pin it. + +You now have a real `.app` you can launch from Spotlight, Launchpad, or the +Dock — it just runs the `.command` script under the hood, so any +`quantui/*.py` edits take effect immediately on the next launch. + +> **Linux users:** the same `launch-native.command` script works from a +> terminal — `./launch-native.command`. To wire it into your desktop +> environment as a pinned app, create a `.desktop` entry pointing at the +> script. + +--- + ## Tutorials Five step-by-step notebooks in [`notebooks/tutorials/`](notebooks/tutorials/): @@ -179,31 +264,44 @@ pytest -m "not network" \ ```text quantui/ Main package - app.py QuantUIApp widget class (all tabs, UI logic) + app.py QuantUIApp — widget orchestration, run dispatch + app_analysis.py Analysis-tab panel registry + _pop_* methods + app_builders.py _build_* widget construction + app_runflow.py _do_run + run/orchestration UI handlers + app_visualization.py Trajectory / vib / IR / orbital / PES rendering + app_history.py History tab loaders, replay context + app_formatters.py Result-card and text formatters + app_exports.py Export handlers (XYZ/MOL/PDB/script) molecule.py Molecule input and validation session_calc.py In-session PySCF runner (RHF/UHF/DFT/MP2/PCM) - freq_calc.py Vibrational frequency + thermochemistry analysis - ir_plot.py IR spectrum chart (stick and Lorentzian broadened) + freq_calc.py Vibrational frequency + thermochemistry + ir_plot.py IR spectrum chart (stick / Lorentzian broadened) tddft_calc.py TD-DFT UV-Vis excited-state calculations - nmr_calc.py NMR shielding + ¹H/¹³C chemical shift prediction + nmr_calc.py NMR shielding + ¹H/¹³C chemical shifts pes_scan.py 1D potential energy surface scan optimizer.py QM geometry optimization with trajectory - visualization_py3dmol.py 3D viewer (py3Dmol + PlotlyMol backends) + visualization_py3dmol.py 3D viewer (py3Dmol-first; plotlymol fallback) + viz_backend_router.py Capability-aware backend router (pure function) + 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 comparison.py Side-by-side result tables - results_storage.py Timestamped result persistence - calc_log.py Performance logging and time estimation + results_storage.py Timestamped result persistence (schema v2) + calc_log.py Performance + event logging, time estimation + issue_tracker.py In-app bug-report DB 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 notebooks/ - molecule_computations.ipynb Main student-facing interface + molecule_computations.ipynb Main user-facing interface (3-cell launcher) tutorials/ Step-by-step guided notebooks (01–05) -tests/ pytest test suite (860+ tests) +tests/ pytest test suite (~1000 tests) apptainer/ Container definition for reproducible deployment local-setup/ Conda environment definition pyproject.toml Package metadata and tool config +CHANGELOG.md Release history (Keep a Changelog format) ``` --- diff --git a/docs/index.html b/docs/index.html index e95f87c..bf5f5dd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,10 +3,10 @@ - QuantUI — Quantum Chemistry in Jupyter - - - + QuantUI — An open-source frontend for DFT and post-HF quantum chemistry + + + @@ -141,6 +141,8 @@ .hero__meta { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; } .hero__stat { font-size: 0.8125rem; color: #64748b; font-weight: 500; } .hero__sep { color: #334155; } + .hero__link { color: #93c5fd; text-decoration: underline; } + .hero__link:hover { color: #bfdbfe; } .hero__visual { display: flex; justify-content: center; align-items: center; } @media (max-width: 768px) { .hero__inner { grid-template-columns: 1fr; } @@ -178,6 +180,7 @@ text-align: center; max-width: 540px; margin: 0 auto 3rem; line-height: 1.65; } + .section__subtitle--mid { margin-top: 3rem; } .section__note { font-size: 0.875rem; color: #94a3b8; text-align: center; margin-top: 1rem; @@ -244,6 +247,12 @@ border: 1px solid #e2e8f0; border-radius: 4px; padding: 0.15rem 0.45rem; color: #0f172a; } + .inline-code { + font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; + font-size: 0.8rem; background: #f1f5f9; + border: 1px solid #e2e8f0; border-radius: 4px; + padding: 0.1rem 0.35rem; color: #0f172a; + } .td-num { font-weight: 700; color: #94a3b8; font-size: 0.8125rem; white-space: nowrap; @@ -330,7 +339,7 @@