-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathquantui.def
More file actions
141 lines (120 loc) · 5.02 KB
/
Copy pathquantui.def
File metadata and controls
141 lines (120 loc) · 5.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
Bootstrap: docker
FROM: condaforge/miniforge3:latest
%help
QuantUI — Educational Quantum Chemistry Interface
Lightweight local teaching interface for running PySCF calculations
without a cluster. Includes PySCF, ASE, py3Dmol, and Voilà.
Usage:
# Clean widget UI (students see no code — recommended for class)
apptainer run quantui.sif app
# JupyterLab (exploration / development mode)
apptainer run quantui.sif
Build:
# From the repo root:
apptainer build quantui.sif apptainer/quantui.def
%labels
Maintainer "Jonathan Schultz"
Purpose "Local teaching interface for quantum chemistry calculations"
Version "0.4.1"
%environment
export PATH="/opt/conda/bin:${PATH}"
export PYTHONPATH="/opt/quantui:${PYTHONPATH}"
# Disable user site-packages for reproducibility
export PYTHONNOUSERSITE=1
# Save calculation results to the user's home directory so they persist
# across kernel restarts. The home dir is bind-mounted by Apptainer.
export QUANTUI_RESULTS_DIR="${HOME}/.quantui/results"
%files
# Source path is relative to where you run `apptainer build` (repo root).
# Run the build command from the repo root, not from apptainer/.
. /opt/quantui
%post
export PATH="/opt/conda/bin:${PATH}"
echo "Installing dependencies via mamba (libmamba solver — the old classic conda solver hangs for hours on this pyscf + rdkit + jupyterlab spec)."
# conda-forge only, strict priority: avoids mixing in the base image's
# implicit 'defaults' channel, which both slows the solve and pulls from a
# channel with separate terms of service.
conda config --system --set channel_priority strict
mamba install -y --override-channels -c conda-forge \
jupyter \
jupyterlab \
ipywidgets \
notebook \
pyscf \
numpy \
scipy \
matplotlib \
plotly \
h5py \
rdkit
echo "Installing pip packages..."
pip install --no-cache-dir \
voila \
ase \
py3dmol \
requests
echo "Installing QuantUI..."
cd /opt/quantui
pip install --no-cache-dir -e .
echo "Verifying installation..."
python -c "import quantui; print('QuantUI OK')"
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')"
python -c "from quantui.app import QuantUIApp; print('QuantUIApp OK')"
echo "Cleaning up unnecessary files..."
# Version control and caches
rm -rf /opt/quantui/.git
rm -rf /opt/quantui/.mypy_cache
rm -rf /opt/quantui/.pytest_cache
rm -rf /opt/quantui/.ruff_cache
rm -rf /opt/quantui/.coverage
rm -rf /opt/quantui/coverage.xml
rm -rf /opt/quantui/htmlcov
find /opt/quantui -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find /opt/quantui -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
# Internal dev/AI files not intended for students
rm -f /opt/quantui/CLAUDE.md
rm -rf /opt/quantui/planning
rm -f /opt/quantui/feature-requests.md
rm -f /opt/quantui/bug-reports.md
rm -f /opt/quantui/launch-app.bat
rm -f /opt/quantui/launch-dev.bat
# Windows-only and CI artefacts
rm -rf /opt/quantui/.github
rm -f /opt/quantui/.pre-commit-config.yaml
echo "Configuring Jupyter Server..."
mkdir -p /etc/jupyter
cat > /etc/jupyter/jupyter_server_config.py << 'EOF'
# Disable XSRF cookie checks — prevents 403 errors on kernel shutdown in Voilà.
c.ServerApp.disable_check_xsrf = True
EOF
conda clean --all -y
pip cache purge
echo "Build complete!"
%runscript
MODE="${1:-lab}"
shift 2>/dev/null || true
if [ "$MODE" = "app" ]; then
exec voila /opt/quantui/notebooks/molecule_computations.ipynb \
--no-browser --port=8866 "${@}"
else
exec jupyter lab --ip=0.0.0.0 --no-browser --allow-root "${@}"
fi
%test
echo "Testing container..."
python -c "import quantui" || exit 1
python -c "import pyscf" || exit 1
python -c "import py3Dmol" || exit 1
python -c "import ase" || exit 1
python -c "from quantui import Molecule; print('Molecule OK')" || exit 1
python -c "from quantui.app import QuantUIApp; print('QuantUIApp OK')" || exit 1
echo "All tests passed!"