diff --git a/notebooks/pfiFocus.ipynb b/notebooks/pfiFocus.ipynb
new file mode 100644
index 0000000..ab32bf9
--- /dev/null
+++ b/notebooks/pfiFocus.ipynb
@@ -0,0 +1,341 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "bd9c763a-4b6b-450b-b25c-a9cdd51eb013",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import os\n",
+ "import re\n",
+ "import numpy as np\n",
+ "\n",
+ "%matplotlib ipympl\n",
+ "import matplotlib.pyplot as plt\n",
+ "plt.rcParams['figure.figsize'] = (9, 7)\n",
+ "\n",
+ "from IPython.display import display, HTML\n",
+ "display(HTML(\"\"))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "478976d9-d5a4-4d7e-ab55-6a056602e07a",
+ "metadata": {},
+ "source": [
+ "# Imports, code"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "cb7f88b3-b6ae-46b6-a0f5-3666574fb513",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'pfs.drp.stella.utils.pfiFocus'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "Input \u001b[0;32mIn [2]\u001b[0m, in \u001b[0;36m| \u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mlsst\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdaf\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpersistence\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mdafPersist\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpfs\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdatamodel\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpfsConfig\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m TargetType\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpfs\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdrp\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstella\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpfiFocus\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m estimateFiberFluxes, plotVariantOffsets, plotRadialProfiles, plotRms, rmsFromCenteredFibers\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28;01mFalse\u001b[39;00m:\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpfs\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdrp\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstella\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m DataId\n",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pfs.drp.stella.utils.pfiFocus'"
+ ]
+ }
+ ],
+ "source": [
+ "import lsst.daf.persistence as dafPersist\n",
+ "from pfs.datamodel.pfsConfig import TargetType\n",
+ "from pfs.drp.stella.utils.pfiFocus import estimateFiberFluxes, plotVariantOffsets, plotRadialProfiles, plotRms, rmsFromCenteredFibers\n",
+ "\n",
+ "if False:\n",
+ " from pfs.drp.stella.utils import DataId\n",
+ "else:\n",
+ " DataId = dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7dd9420-0637-4dcf-ba30-fd6db937a6ca",
+ "metadata": {},
+ "source": [
+ "# Butler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f5e0ae63-1aa1-4455-869b-0817895e1765",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def butlerName(_butler=None):\n",
+ " if _butler is None:\n",
+ " _butler = butler\n",
+ " root = _butler._repos.inputs()[0]._repoArgs.root\n",
+ " root = re.sub(r\"^.*/rerun/\", \"\", root)\n",
+ " \n",
+ " return root\n",
+ "\n",
+ "butlers = {}\n",
+ "\n",
+ "repo = \"/work/drp\" \n",
+ "\n",
+ "reruns = [\n",
+ " \"rhl/tmp\",\n",
+ " \"rhl/focus\",\n",
+ "]\n",
+ "for rerun in reruns:\n",
+ " kwargs = {}\n",
+ " if rerun.startswith('/'):\n",
+ " dataDir = rerun\n",
+ " else:\n",
+ " dataDir = os.path.join(repo, \"rerun\", rerun)\n",
+ "\n",
+ " if rerun in [\"rhl/focus\"]:\n",
+ " kwargs.update(calibRoot=\"/work/drp/CALIB-kiyoyabe-20240311\")\n",
+ "\n",
+ " if not os.path.exists(dataDir):\n",
+ " continue\n",
+ "\n",
+ " butlers[rerun] = dafPersist.Butler(dataDir, **kwargs)\n",
+ "\n",
+ "if os.path.exists(\"/work/drp\"):\n",
+ " kwargs = {}\n",
+ " repoRoot = \"/work/drp\"\n",
+ "\n",
+ " calibName = \"CALIB-20220630\"\n",
+ " kwargs.update(calibRoot=os.path.join(repoRoot, calibName))\n",
+ " rerun = f'drpActor/{calibName}'\n",
+ "\n",
+ " butlers[\"drp\"] = dafPersist.Butler(os.path.join(repoRoot, 'rerun', rerun), **kwargs)\n",
+ "\n",
+ "butler = butlers[list(butlers)[0]] # default"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5ab45b91-d08d-42bd-b06a-0565ccc9b798",
+ "metadata": {},
+ "source": [
+ "# Process data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a23d5ce4-b7c1-455b-b9f2-4f072713a928",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if False:\n",
+ " visits = sorted([108315] + list(range(108317, 108339+1)))\n",
+ "else:\n",
+ " visits = sorted([108507] + list(range(108509, 108525 + 1))) # \n",
+ "\n",
+ "filterName = \"g_gaia\"\n",
+ "pfsConfig = butler.get(\"pfsConfig\", visit=visits[1]).select(targetType=~TargetType.ENGINEERING)\n",
+ "nJy = pfsConfig.getPhotometry(filterName)\n",
+ "mag = 8.90 - 2.5*np.log10(nJy*1e-9)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "72fcc78b-12a0-4c3f-9e65-32636f898e00",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Distribution of fluxes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0376a640-2029-47df-8075-d2ef7fcad1ab",
+ "metadata": {},
+ "source": [
+ "## Read data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2ad359e1-f2f9-4bf9-95a9-4fc5e3fe9a34",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "fig = 'tmp'; plt.close(fig); fig = plt.figure(fig)\n",
+ "\n",
+ "plt.hist(mag, bins=21)\n",
+ "plt.xlabel(f\"{filterName}\")\n",
+ "plt.ylabel(\"N\")\n",
+ "plt.title(f\"{pfsConfig.designName}\");"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ae91517a-d3ff-4137-8ec9-f4609e957250",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if False:\n",
+ " from importlib import reload\n",
+ " import pfs.drp.stella.utils.pfiFocus\n",
+ " estimateFiberFluxes = reload(pfs.drp.stella.utils.pfiFocus).estimateFiberFluxes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "04306f34-eedf-4d55-8801-827b5e185fb1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " cache\n",
+ "except NameError:\n",
+ " cache = {}\n",
+ "\n",
+ "import warnings\n",
+ "with warnings.catch_warnings():\n",
+ " warnings.simplefilter('error', UserWarning)\n",
+ " pass\n",
+ "\n",
+ "cache = estimateFiberFluxes(butler, visits, windows=[\"b\", \"r\", \"b1\", \"b2\", \"r1\", \"r2\"],\n",
+ " missingCamera=lambda arm, s: (arm == 'b' and s in [3]) or (arm == 'n' and s in [1, 4]),\n",
+ " cache=cache)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff36db6f-eb0a-465a-9a59-6c58e0d55931",
+ "metadata": {},
+ "source": [
+ "## Visualize offsets"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cd13b91c-ff67-4e74-9e03-b9ebcb7447c4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = 1; plt.close(fig); fig = plt.figure(fig)\n",
+ "\n",
+ "plotVariantOffsets(cache, title=f\"{pfsConfig.designName}\", figure=fig)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1053cb80-9b39-43a6-933f-f1dab91f53c7",
+ "metadata": {},
+ "source": [
+ "## Make radial profile plots"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a41fd3aa-005e-4693-a99c-bffc9126865a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = 2; plt.close(fig); fig = plt.figure(fig)\n",
+ "\n",
+ "magMin = 15\n",
+ "magMax = 17\n",
+ "\n",
+ "windows=[\"b\", \"r\"] if False else ['b1', 'b2', 'r1', 'r2']\n",
+ "\n",
+ "\n",
+ "with np.testing.suppress_warnings() as suppress:\n",
+ " suppress.filter(RuntimeWarning, \"RuntimeWarning: Mean of empty slice\")\n",
+ "\n",
+ " rms, meanCenteredFlux = plotRadialProfiles(windows=windows,\n",
+ " nbin=10, rmax=200, mag=mag, filterName=filterName, magMin=magMin, magMax=magMax, cache=cache,\n",
+ " normPercentile=100, title=\"\", figure=fig)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "de1626ff-7288-4d2a-b387-fdef9a83f347",
+ "metadata": {},
+ "source": [
+ "## RMS as a function of focus"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3d143210-db9e-491d-a846-af97488e1aa2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = 3; plt.close(fig); fig = plt.figure(fig)\n",
+ "\n",
+ "plotRms(rms, byQuadrant=True, title=\"\", cache=cache, figure=fig)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9c73bc57-ff0f-4958-b4ee-c27c0d66c055",
+ "metadata": {},
+ "source": [
+ "## Focus sweep using immobile cobras, unaffected by variant"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d2ee66a3-ab16-45fc-b0aa-92342b3f03fa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = 4; plt.close(fig); fig = plt.figure(fig)\n",
+ "\n",
+ "#windows = ['b1', 'b2', 'r1', 'r2']\n",
+ "rmsFromCenteredFibers(meanCenteredFlux, byQuadrant=True, cache=cache, title=\"\", figure=fig)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "PFS",
+ "language": "python",
+ "name": "pfs_pipe2d"
+ },
+ "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.8.13"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
|