|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "ea95a75c-ab66-4cd5-bcc3-2daa8f7bc358", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# XAS Notebook\n", |
| 9 | + "\n", |
| 10 | + "The XAS Notebook autoprocessor will run automatically on every scan performed that contains the [NXxas](https://manual.nexusformat.org/classes/applications/NXxas.html#nxxas) sub-entry.\n", |
| 11 | + "\n", |
| 12 | + "A simple analysis and plot of the data is provided.\n", |
| 13 | + "\n", |
| 14 | + "Note: [mmg_toolbox](https://github.com/DanPorter/mmg_toolbox) is in active development and likely to change in the future, therefore please don't rely to heavily on the functions at this point. You can see how everything works at the repository. If you have any comments, please do get in touch!" |
| 15 | + ] |
| 16 | + }, |
| 17 | + { |
| 18 | + "cell_type": "code", |
| 19 | + "execution_count": null, |
| 20 | + "id": "42f203e1", |
| 21 | + "metadata": { |
| 22 | + "tags": [ |
| 23 | + "parameters" |
| 24 | + ] |
| 25 | + }, |
| 26 | + "outputs": [], |
| 27 | + "source": [ |
| 28 | + "# Processor requirements\n", |
| 29 | + "inpath = \"\"" |
| 30 | + ] |
| 31 | + }, |
| 32 | + { |
| 33 | + "cell_type": "code", |
| 34 | + "execution_count": null, |
| 35 | + "id": "ef4acc26-df0a-43d2-9c90-3dd908def7a0", |
| 36 | + "metadata": {}, |
| 37 | + "outputs": [], |
| 38 | + "source": [ |
| 39 | + "import sys, os\n", |
| 40 | + "import numpy as np\n", |
| 41 | + "import matplotlib.pyplot as plt\n", |
| 42 | + "\n", |
| 43 | + "import hdfmap\n", |
| 44 | + "print(hdfmap.module_info())\n", |
| 45 | + "\n", |
| 46 | + "# Set environment variables\n", |
| 47 | + "os.environ[\"MPLCONFIGDIR\"] = \"/tmp/.config/matplotlib\"\n", |
| 48 | + "\n", |
| 49 | + "# Ensure the directories exist\n", |
| 50 | + "os.makedirs(os.environ[\"MPLCONFIGDIR\"], exist_ok=True)\n", |
| 51 | + "\n", |
| 52 | + "from mmg_toolbox.env_functions import get_scan_number, replace_scan_number\n", |
| 53 | + "from mmg_toolbox.spectra_scan import SpectraScan, find_pol_pairs, is_nxxas\n" |
| 54 | + ] |
| 55 | + }, |
| 56 | + { |
| 57 | + "cell_type": "code", |
| 58 | + "execution_count": null, |
| 59 | + "id": "591f3860-45f7-4545-9a8c-d58e27d9782e", |
| 60 | + "metadata": {}, |
| 61 | + "outputs": [], |
| 62 | + "source": [ |
| 63 | + "# Load data from NeXus file using HdfMap\n", |
| 64 | + "\n", |
| 65 | + "nxs_map = hdfmap.create_nexus_map(inpath)\n", |
| 66 | + "\n", |
| 67 | + "with nxs_map.load_hdf() as nxs:\n", |
| 68 | + " def rd(expr, default=''):\n", |
| 69 | + " return nxs_map.format_hdf(nxs, expr, default=default)\n", |
| 70 | + "\n", |
| 71 | + " # currently accounts for i06-1 and i10-1 metadata\n", |
| 72 | + " metadata = {\n", |
| 73 | + " \"scan\": rd('{filename}'),\n", |
| 74 | + " \"cmd\": rd('{(cmd|user_command|scan_command)}'),\n", |
| 75 | + " \"title\": rd('{title}', os.path.basename(inpath)),\n", |
| 76 | + " \"endstation\": rd('{end_station}', 'unknown'),\n", |
| 77 | + " \"sample\": rd('{sample_name}', ''),\n", |
| 78 | + " \"energy\": rd('{np.mean((fastEnergy|pgm_energy|energye|energyh)):.2f} eV'),\n", |
| 79 | + " \"pol\": rd('{polarisation?(\"lh\")}'),\n", |
| 80 | + " \"height\": rd('{(em_y|hfm_y|scm_y?(0)):.2f}', 0),\n", |
| 81 | + " \"pitch\": rd('{(em_pitch|hfm_pitch|m7_pitch?(0)):.2f}', 0),\n", |
| 82 | + " \"temperature\": rd('{(T_sample|sample_temperature|lakeshore336_cryostat|lakeshore336_sample|itc3_device_sensor_temp?(300)):.2f} K'),\n", |
| 83 | + " \"field\": rd('{(field_z|sample_field|magnet_field|ips_demand_field?(0)):.2f} T'),\n", |
| 84 | + " }\n", |
| 85 | + "\n", |
| 86 | + " print(nxs_map.eval(nxs, '_(fastEnergy|pgm_energy|energye|energyh)'))\n", |
| 87 | + " print(nxs_map.eval(nxs, '_(C2|ca62sr|mcs16_data|mcse16_data|mcsh16_data)'))\n", |
| 88 | + " print(nxs_map.eval(nxs, '_(C1|ca61sr|mcs17_data|mcse17_data|mcsh17_data)'))\n", |
| 89 | + " print(nxs_map.eval(nxs, '_(C3|ca63sr|mcs18_data|mcse18_data|mcsh18_data|mcsd18_data)'))\n", |
| 90 | + "\n", |
| 91 | + " energy = nxs_map.eval(nxs, '(fastEnergy|pgm_energy|energye|energyh)')\n", |
| 92 | + " monitor = nxs_map.eval(nxs, '(C2|ca62sr|mcs16_data|mcse16_data|mcsh16_data)', default=1.0)\n", |
| 93 | + " tey = nxs_map.eval(nxs, '(C1|ca61sr|mcs17_data|mcse17_data|mcsh17_data)', default=np.ones(nxs_map.scannables_shape())) / monitor\n", |
| 94 | + " tfy = nxs_map.eval(nxs, '(C3|ca63sr|mcs18_data|mcse18_data|mcsh18_data|mcsd18_data)', default=np.ones(nxs_map.scannables_shape())) / monitor\n", |
| 95 | + "\n", |
| 96 | + "print('\\n'.join(f\"{n:12}: {d}\" for n, d in metadata.items()))\n", |
| 97 | + "\n", |
| 98 | + "title = \"{endstation} {sample} {scan}\\nE = {energy}, pol = {pol}, T = {temperature}, B = {field}\".format(**metadata)" |
| 99 | + ] |
| 100 | + }, |
| 101 | + { |
| 102 | + "cell_type": "code", |
| 103 | + "execution_count": null, |
| 104 | + "id": "d8849732", |
| 105 | + "metadata": {}, |
| 106 | + "outputs": [], |
| 107 | + "source": [ |
| 108 | + "# Load data from NeXus file from NXxas sub-entry\n", |
| 109 | + "\"\"\"\n", |
| 110 | + "import h5py \n", |
| 111 | + "with h5py.File(inpath, 'r') as nxs:\n", |
| 112 | + " # first entry\n", |
| 113 | + " entry = next(group for path, group in nxs.items() if group.attrs.get('NX_class', b'') == b'NXentry')\n", |
| 114 | + " nxxas = next(group for path, group in entry.items() if group.attrs.get('NX_class', b'') == b'NXsubentry' and group.get('definition').asstr()[()] == 'NXxas')\n", |
| 115 | + " print(f\"NXxas path: \\n{nxxas.name}\")\n", |
| 116 | + " print(f\" {'\\n '.join(nxxas.keys())}\")\n", |
| 117 | + "\n", |
| 118 | + " monitor = nxxas['monitor']['data'][()] if 'data' in nxxas['monitor'] else 1.0\n", |
| 119 | + " data = nxxas['data'] # or 'tey', 'tfy_ft'\n", |
| 120 | + " mode = data['mode'][()]\n", |
| 121 | + " energy = data['energy'][()]\n", |
| 122 | + " absorbed_beam = data['absorbed_beam'][()] / monitor\n", |
| 123 | + " tey = nxxas['tey']['absorbed_beam'][()] / monitor\n", |
| 124 | + " tfy = nxxas['tfy']['absorbed_beam'][()] / monitor\n", |
| 125 | + "\"\"\"\n" |
| 126 | + ] |
| 127 | + }, |
| 128 | + { |
| 129 | + "cell_type": "code", |
| 130 | + "execution_count": null, |
| 131 | + "id": "28b6a641-8f85-4c76-ae2a-ed2e6f588dce", |
| 132 | + "metadata": {}, |
| 133 | + "outputs": [], |
| 134 | + "source": [ |
| 135 | + "fig, ax = plt.subplots(1, 2, figsize=(12, 4))\n", |
| 136 | + "fig.suptitle(title)\n", |
| 137 | + "\n", |
| 138 | + "ax[0].plot(energy, tey, '-', label=f\"{metadata['pol']} TEY\")\n", |
| 139 | + "ax[1].plot(energy, tfy, '-', label=f\"{metadata['pol']} TFY\")\n", |
| 140 | + "\n", |
| 141 | + "ax[0].set_xlabel('Energy [eV]')\n", |
| 142 | + "ax[0].set_ylabel('signal / monitor')\n", |
| 143 | + "ax[0].legend()\n", |
| 144 | + "\n", |
| 145 | + "ax[1].set_xlabel('Energy [eV]')\n", |
| 146 | + "ax[1].set_ylabel('signal / monitor')\n", |
| 147 | + "ax[1].legend()" |
| 148 | + ] |
| 149 | + }, |
| 150 | + { |
| 151 | + "cell_type": "markdown", |
| 152 | + "id": "6a75d026-7605-4745-ab45-c17bb254bb8c", |
| 153 | + "metadata": {}, |
| 154 | + "source": [ |
| 155 | + "# Search for previous NXxas scans\n", |
| 156 | + "If the previous scan was also a spectra scan, plot this and take the difference" |
| 157 | + ] |
| 158 | + }, |
| 159 | + { |
| 160 | + "cell_type": "code", |
| 161 | + "execution_count": null, |
| 162 | + "id": "8f052bf9-4e7d-4fb6-8d26-d744268a0844", |
| 163 | + "metadata": {}, |
| 164 | + "outputs": [], |
| 165 | + "source": [ |
| 166 | + "# Build list of scans\n", |
| 167 | + "scan_number = get_scan_number(inpath)\n", |
| 168 | + "scans = []\n", |
| 169 | + "while len(scans) < 9:\n", |
| 170 | + " filename = replace_scan_number(inpath, scan_number)\n", |
| 171 | + " scan_number -= 1\n", |
| 172 | + " if is_nxxas(filename):\n", |
| 173 | + " scans.append(SpectraScan(filename)) # Load scan data\n", |
| 174 | + " else:\n", |
| 175 | + " break\n", |
| 176 | + "\n", |
| 177 | + "for scan in scans:\n", |
| 178 | + " print(scan, '\\n')\n", |
| 179 | + "\n", |
| 180 | + "# Get polarisations\n", |
| 181 | + "pols = {scan.pol for scan in scans}\n", |
| 182 | + "print(f\"Polarisations: {pols}\")" |
| 183 | + ] |
| 184 | + }, |
| 185 | + { |
| 186 | + "cell_type": "code", |
| 187 | + "execution_count": null, |
| 188 | + "id": "3942b136-9d23-4065-b35a-2d39a4c50887", |
| 189 | + "metadata": {}, |
| 190 | + "outputs": [], |
| 191 | + "source": [ |
| 192 | + "# Plot raw spectra\n", |
| 193 | + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[12, 6], dpi=100)\n", |
| 194 | + "for scan in scans:\n", |
| 195 | + " scan.tey.plot(ax1)\n", |
| 196 | + " scan.tfy.plot(ax2)\n", |
| 197 | + "\n", |
| 198 | + "ax1.set_xlabel('E [eV]')\n", |
| 199 | + "ax1.set_ylabel('TEY / monitor')\n", |
| 200 | + "ax2.set_xlabel('E [eV]')\n", |
| 201 | + "ax2.set_ylabel('TFY / monitor')\n", |
| 202 | + "ax1.legend()\n", |
| 203 | + "ax2.legend()" |
| 204 | + ] |
| 205 | + }, |
| 206 | + { |
| 207 | + "cell_type": "code", |
| 208 | + "execution_count": null, |
| 209 | + "id": "380001c6-950d-468f-92e0-aec5099f910d", |
| 210 | + "metadata": {}, |
| 211 | + "outputs": [], |
| 212 | + "source": [] |
| 213 | + }, |
| 214 | + { |
| 215 | + "cell_type": "code", |
| 216 | + "execution_count": null, |
| 217 | + "id": "7a13e382-a30e-4b19-86c0-34e1604c7112", |
| 218 | + "metadata": {}, |
| 219 | + "outputs": [], |
| 220 | + "source": [ |
| 221 | + "# Subtract background and normalise\n", |
| 222 | + "# background options: flat, norm, linear, curve, exp\n", |
| 223 | + "# normalisation option: .norm_to_jump(), .norm_to_peak()\n", |
| 224 | + "rem_bkg = [s.remove_background('flat').norm_to_jump() for s in scans]\n", |
| 225 | + "\n", |
| 226 | + "# Plot background subtracted, normalised spectra\n", |
| 227 | + "for scan in rem_bkg:\n", |
| 228 | + " # print(scan, '\\n')\n", |
| 229 | + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[12, 6], dpi=100)\n", |
| 230 | + " scan.tey.plot(ax1)\n", |
| 231 | + " scan.tey.plot_bkg(ax1)\n", |
| 232 | + " scan.tfy.plot(ax2)\n", |
| 233 | + " scan.tfy.plot_bkg(ax2)\n", |
| 234 | + "\n", |
| 235 | + " ax1.set_xlabel('E [eV]')\n", |
| 236 | + " ax1.set_ylabel('TEY / monitor')\n", |
| 237 | + " ax2.set_xlabel('E [eV]')\n", |
| 238 | + " ax2.set_ylabel('TFY / monitor')\n", |
| 239 | + " ax1.legend()\n", |
| 240 | + " ax2.legend()" |
| 241 | + ] |
| 242 | + }, |
| 243 | + { |
| 244 | + "cell_type": "code", |
| 245 | + "execution_count": null, |
| 246 | + "id": "5d66604e-7dd5-4675-912f-88ccd5d5ee3e", |
| 247 | + "metadata": {}, |
| 248 | + "outputs": [], |
| 249 | + "source": [ |
| 250 | + "# Find polarisation pairs within the scans\n", |
| 251 | + "if len(scans) > 1 and len(pols) > 1:\n", |
| 252 | + " pairs = find_pol_pairs(*rem_bkg)\n", |
| 253 | + " \n", |
| 254 | + " for pair in pairs:\n", |
| 255 | + " print(pair)\n", |
| 256 | + " \n", |
| 257 | + " # pair.create_figure()\n", |
| 258 | + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[12, 6], dpi=100)\n", |
| 259 | + " fig.suptitle(pair.description)\n", |
| 260 | + " \n", |
| 261 | + " pair.spectra1.tey.plot_parents(ax1) # background subtracted spectra\n", |
| 262 | + " pair.spectra2.tey.plot_parents(ax1)\n", |
| 263 | + " pair.tey.plot(ax1) # XMCD/XMLD\n", |
| 264 | + " \n", |
| 265 | + " pair.spectra1.tfy.plot_parents(ax2)\n", |
| 266 | + " pair.spectra2.tfy.plot_parents(ax2)\n", |
| 267 | + " pair.tfy.plot(ax2)\n", |
| 268 | + " \n", |
| 269 | + " ax1.set_xlabel('E [eV]')\n", |
| 270 | + " ax1.set_ylabel('TEY / monitor')\n", |
| 271 | + " ax2.set_xlabel('E [eV]')\n", |
| 272 | + " ax2.set_ylabel('TFY / monitor')\n", |
| 273 | + " ax1.legend()\n", |
| 274 | + " ax2.legend()" |
| 275 | + ] |
| 276 | + }, |
| 277 | + { |
| 278 | + "cell_type": "code", |
| 279 | + "execution_count": null, |
| 280 | + "id": "8869991d-3b3a-4e36-ba22-afd75ad296c4", |
| 281 | + "metadata": {}, |
| 282 | + "outputs": [], |
| 283 | + "source": [ |
| 284 | + "# Average each polarisation of all scans\n", |
| 285 | + "if len(scans) > 1 and len(pols) > 1:\n", |
| 286 | + " pol1 = [pair.spectra1 for pair in pairs]\n", |
| 287 | + " pol2 = [pair.spectra2 for pair in pairs]\n", |
| 288 | + " av_pol1 = sum(pol1[1:], pol1[0])\n", |
| 289 | + " av_pol2 = sum(pol2[1:], pol2[0])\n", |
| 290 | + " diff = av_pol1 - av_pol2\n", |
| 291 | + " print(diff)\n", |
| 292 | + " \n", |
| 293 | + " # diff.create_figure()\n", |
| 294 | + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[12, 6], dpi=100)\n", |
| 295 | + " fig.suptitle(diff.description)\n", |
| 296 | + " \n", |
| 297 | + " diff.spectra1.tey.plot_parents(ax1)\n", |
| 298 | + " diff.spectra2.tey.plot_parents(ax1)\n", |
| 299 | + " diff.tey.plot(ax1)\n", |
| 300 | + " \n", |
| 301 | + " diff.spectra1.tfy.plot_parents(ax2)\n", |
| 302 | + " diff.spectra2.tfy.plot_parents(ax2)\n", |
| 303 | + " diff.tfy.plot(ax2)\n", |
| 304 | + " \n", |
| 305 | + " ax1.set_xlabel('E [eV]')\n", |
| 306 | + " ax1.set_ylabel('TEY / monitor')\n", |
| 307 | + " ax2.set_xlabel('E [eV]')\n", |
| 308 | + " ax2.set_ylabel('TFY / monitor')\n", |
| 309 | + " ax1.legend()\n", |
| 310 | + " ax2.legend()" |
| 311 | + ] |
| 312 | + }, |
| 313 | + { |
| 314 | + "cell_type": "code", |
| 315 | + "execution_count": null, |
| 316 | + "id": "7e39fae3-b0ed-4aaf-be8c-a872d250bf5c", |
| 317 | + "metadata": {}, |
| 318 | + "outputs": [], |
| 319 | + "source": [] |
| 320 | + } |
| 321 | + ], |
| 322 | + "metadata": { |
| 323 | + "kernelspec": { |
| 324 | + "display_name": "Python 3", |
| 325 | + "language": "python", |
| 326 | + "name": "python3" |
| 327 | + }, |
| 328 | + "language_info": { |
| 329 | + "codemirror_mode": { |
| 330 | + "name": "ipython", |
| 331 | + "version": 3 |
| 332 | + }, |
| 333 | + "file_extension": ".py", |
| 334 | + "mimetype": "text/x-python", |
| 335 | + "name": "python", |
| 336 | + "nbconvert_exporter": "python", |
| 337 | + "pygments_lexer": "ipython3", |
| 338 | + "version": "3.12.9" |
| 339 | + } |
| 340 | + }, |
| 341 | + "nbformat": 4, |
| 342 | + "nbformat_minor": 5 |
| 343 | +} |
0 commit comments