File size: 5,633 Bytes
64c992d 90b47cf 64c992d | 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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | {
"cells": [
{
"cell_type": "markdown",
"id": "706410fd",
"metadata": {},
"source": [
"# Figure 5B: MagNET-Zero vs DFT shieldings on the DFT8K benchmark\n",
"\n",
"Reproduces Figure 5B: MagNET-Zero gas-phase shielding predictions vs DFT on the DFT8K benchmark (~7,000\n",
"organics, untrained). Protons vs WP04/pcSseg-2, carbons vs wB97X-D/pcSseg-2; residual = DFT minus\n",
"MagNET."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7e0a3b95",
"metadata": {},
"outputs": [],
"source": [
"import os, sys\n",
"\n",
"# make the in-repo modules importable (not pip-installed)\n",
"REPO = os.path.abspath(\"../..\")\n",
"for _p in (\"data/dft8k\", \"analysis/code\", \"analysis/code/shared\"):\n",
" sys.path.insert(0, os.path.join(REPO, _p))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c9838352",
"metadata": {},
"outputs": [],
"source": [
"import dft8k_residuals\n",
"import paths\n",
"import fig5b_plots"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2231e1e",
"metadata": {},
"outputs": [],
"source": [
"DFT8K_HDF5 = paths.dataset_file(\"dft8k\", root=REPO)\n",
"\n",
"def figure_path(name):\n",
" os.makedirs(\"figures\", exist_ok=True)\n",
" return os.path.join(\"figures\", name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7d02a23",
"metadata": {},
"outputs": [],
"source": [
"shieldings = dft8k_residuals.load_shieldings(DFT8K_HDF5)\n",
"print(\"atoms in DFT8K:\", len(shieldings[\"atomic_numbers\"]))"
]
},
{
"cell_type": "markdown",
"id": "867ed2b4",
"metadata": {},
"source": [
"## Residual statistics"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "02ca1b09",
"metadata": {},
"outputs": [],
"source": [
"for nucleus in [\"H\", \"C\"]:\n",
" errors = dft8k_residuals.residuals(shieldings, nucleus)\n",
" stats = dft8k_residuals.residual_stats(errors)\n",
" print(f\"{nucleus}: n={stats['n']:,} RMSE={stats['rmse']:.4f} ppm MAE={stats['mae']:.4f} ppm \"\n",
" f\"95% abs={stats['abs_p95']:.4f} ppm fraction < 0.1 ppm={stats['frac_below']:.3f}\")"
]
},
{
"cell_type": "markdown",
"id": "02d95406",
"metadata": {},
"source": [
"## Residual histograms"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bf9148b3",
"metadata": {},
"outputs": [],
"source": [
"for nucleus in [\"H\", \"C\"]:\n",
" errors = dft8k_residuals.residuals(shieldings, nucleus)\n",
" stats = dft8k_residuals.residual_stats(errors)\n",
" print(f\"{nucleus}: RMSE={stats['rmse']:.3f} ppm frac within 0.1 ppm={stats['frac_below']:.3f}\")\n",
" if nucleus == \"H\":\n",
" fig5b_plots.plot_dft8k_residual_histogram(errors, figure_path(\"fig5b_residuals_1H.png\"),\n",
" bin_width=0.0025, xlim=0.23, grey_box=0.1, x_tick=0.05)\n",
" else: # 13C: wider window, no +/-0.1 box since that threshold is 1H-specific\n",
" fig5b_plots.plot_dft8k_residual_histogram(errors, None,\n",
" bin_width=0.05, xlim=5.0, grey_box=None, x_tick=1.0)"
]
},
{
"cell_type": "markdown",
"id": "5eab006a",
"metadata": {},
"source": [
"## Extreme-residual callouts\n",
"\n",
"The largest positive and negative ¹H residuals over the full set. The published negative callout (a\n",
"sulfonium zwitterion, -1.040 ppm) is not the true global minimum -- see the printed note."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1f2315b",
"metadata": {},
"outputs": [],
"source": [
"extreme_max = dft8k_residuals.find_extreme_residual(DFT8K_HDF5, \"H\", sign=\"max\")\n",
"print(\"largest positive 1H residual:\", extreme_max)\n",
"fig5b_plots.show_dft8k_molecule(extreme_max[\"smiles\"])\n",
"\n",
"zwitterion = dft8k_residuals.molecule_by_id(DFT8K_HDF5, \"H\", molecule_id=88779)\n",
"print(\"published sulfonium-zwitterion callout (id 88779):\", zwitterion)\n",
"fig5b_plots.show_dft8k_molecule(zwitterion[\"smiles\"])"
]
},
{
"cell_type": "markdown",
"id": "5f4276e7",
"metadata": {},
"source": "## Functional-group error breakdown\n\nMean absolute residual for six functional groups (Carbonyls, Amines, Sulfonyl, Pyridines, Furans,\nNitroso), via RDKit SMARTS matching over every molecule's SMILES."
},
{
"cell_type": "code",
"execution_count": null,
"id": "f95f9d58",
"metadata": {},
"outputs": [],
"source": [
"for nucleus in [\"H\", \"C\"]:\n",
" group_errors = dft8k_residuals.functional_group_errors(DFT8K_HDF5, nucleus)\n",
" print(f\"--- {nucleus} ---\")\n",
" for name, v in group_errors.items():\n",
" print(f\"{name:12s} mean|error|={v['mean_abs_error']:.4f} ppm n_molecules={v['n_molecules']:,}\")\n",
" save = figure_path(\"fig5b_functional_groups_1H.png\") if nucleus == \"H\" else None\n",
" fig5b_plots.plot_dft8k_functional_group_errors(group_errors, nucleus, save)"
]
}
],
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
} |