{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f3a7f3e8-3f77-465f-b1b9-f12d525ac942",
   "metadata": {},
   "source": [
    "# Gamma from 1D ASCII data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fc12ef5-71d3-4099-9064-615d256dd0e6",
   "metadata": {},
   "source": [
    "PyMedPhys can also be used to calculate gamma index for one dimensional dose data. Presented here is an example which reads in two .csv files (reference and evaluation dose distributions) as input for the purpose of directly calculating the gamma index of the reference dose distribution. In this example, the reference dose distribution is from film measurement and the evaluation dose distribution is from Monte Carlo simulation. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b706261f-d5ac-4a3a-818a-a29ff6042e0c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import csv\n",
    "import pymedphys\n",
    "import urllib.request"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7419b52-b038-4fda-84a3-db23ad3f3638",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Getting the demo .csv files\n",
    "\n",
    "Let's download the reference and evaluation dose data in .csv files for the purpose of demonstrating gamma analysis for 1D dose data. Users, please note that, there are not explict links of these two .csv files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ff7f83e-6eb5-47e9-b891-2f550eba4111",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'https://github.com/pymedphys/data/raw/200a79623e5c8b226e039e45a606512129a9df97/dose_film_1D_z0mm.csv'\n",
    "save_filepath = 'dose_film_1D_z0mm.csv'\n",
    "\n",
    "urllib.request.urlretrieve(url, save_filepath)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "881ef381-5a6d-4704-9b1a-8b6abcf888b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'https://github.com/pymedphys/data/raw/200a79623e5c8b226e039e45a606512129a9df97/dose_MC_1D_z0mm.csv'\n",
    "save_filepath = 'dose_MC_1D_z0mm.csv'\n",
    "\n",
    "urllib.request.urlretrieve(url, save_filepath)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e1dd980-ad6b-4842-8b1d-9be1dfae9042",
   "metadata": {},
   "source": [
    "## Calculate gamma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8420b22a-4a3f-4fad-a6cd-68e8b97cf36a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "reference = np.genfromtxt('dose_film_1D_z0mm.csv',delimiter=',',skip_header=1)\n",
    "evaluation = np.genfromtxt('dose_MC_1D_z0mm.csv',delimiter=',',skip_header=1)\n",
    "\n",
    "axis_reference = reference[:, 0] #1st column is x in mm\n",
    "dose_reference = reference[:, 1] #2nd column is dose in Gy/MU\n",
    "\n",
    "axis_evaluation = evaluation[:, 0]\n",
    "dose_evaluation = evaluation[:, 1]\n",
    "gamma_options = {\n",
    "    'dose_percent_threshold': 1,\n",
    "    'distance_mm_threshold': 1,\n",
    "    'lower_percent_dose_cutoff': 10,\n",
    "    'interp_fraction': 10,  # Should be 10 or more for more accurate results\n",
    "    'max_gamma': 2,\n",
    "    'random_subset': None,\n",
    "    'local_gamma': False, # False indicates global gamma is calculated\n",
    "    'ram_available': 2 ** 29  # 1/2 GB\n",
    "}\n",
    "#for global dose normalization, the maximum reference dose is used\n",
    "#but in TG218, it said usually the prescribed dose or the maximum dose in a plan (evaluation) is used\n",
    "gamma = pymedphys.gamma(\n",
    "    axis_reference, dose_reference,\n",
    "    axis_evaluation, dose_evaluation,\n",
    "    **gamma_options)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd11776a-fc43-4083-9858-3613060c1b54",
   "metadata": {},
   "source": [
    "## Plot the histogram of gamma index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "666f06bb-261f-43b0-bbc3-68aea891d750",
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_gamma = gamma[~np.isnan(gamma)]\n",
    "print('# of reference points with a valid gamma {0}'.format( len(valid_gamma)) )\n",
    "num_bins = (\n",
    "    gamma_options['interp_fraction'] * gamma_options['max_gamma'])\n",
    "bins = np.linspace(0, gamma_options['max_gamma'], num_bins + 1)\n",
    "\n",
    "if gamma_options['local_gamma']:\n",
    "    gamma_norm_condition = 'Local gamma'\n",
    "else:\n",
    "    gamma_norm_condition = 'Global gamma'\n",
    "\n",
    "pass_ratio = np.sum(valid_gamma <= 1) / len(valid_gamma)\n",
    "    \n",
    "figure_1 = plt.figure(1, figsize=(8, 6), dpi=300, facecolor='w', edgecolor='k')\n",
    "figure_1.suptitle(f\"Dose cut: {gamma_options['lower_percent_dose_cutoff']}% | {gamma_norm_condition} ({gamma_options['dose_percent_threshold']}%/{gamma_options['distance_mm_threshold']}mm) | Pass Rate(\\u03B3<=1): {pass_ratio*100:.2f}% \\n ref pts: {len(dose_reference)} | valid \\u03B3 pts: {len(valid_gamma)}\")\n",
    "\n",
    "plt.hist(valid_gamma, bins, density=True) #y value is probability density in each bin\n",
    "#plt.hist(valid_gamma, bins, density=False) #y value is counts in each bin\n",
    "plt.xlim([0, gamma_options['max_gamma']])\n",
    "plt.xlabel('gamma index of reference point') #FG\n",
    "plt.ylabel('probability density')\n",
    "#plt.ylabel('counts')\n",
    "plt.vlines(x=[1], ymin=0, ymax=1, colors='purple', ls='--', lw=2, label='target')\n",
    "plt.savefig('1D_{0}_histogram.png'.format(gamma_norm_condition), dpi=300) #plt.savefig() must be before plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "817813f1-e678-49f6-95dc-ad656342b669",
   "metadata": {},
   "source": [
    "## Display gamma together with dose points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3049bf24-cc83-43d4-8da8-fd54dfab586e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#show gamma index together with dose points\n",
    "max_ref_dose = np.max(dose_reference) #max reference dose\n",
    "max_eva_dose = np.max(dose_evaluation) #max evaluation dose\n",
    "lower_dose_cutoff = gamma_options['lower_percent_dose_cutoff']/100*max_ref_dose\n",
    "\n",
    "figure_2 = plt.figure(2, figsize=(8, 6), dpi=120, facecolor='w', edgecolor='k')\n",
    "figure_2.suptitle('Reference and evaluation dose curves, and {0} index of reference dose points'.format(gamma_norm_condition),fontsize=12)\n",
    "\n",
    "ax_1 = figure_2.add_subplot(111)\n",
    "ax_1.tick_params(direction='in')\n",
    "ax_1.tick_params(axis='x', bottom='on', top='on')  \n",
    "ax_1.tick_params(labeltop='on')\n",
    "ax_1.minorticks_on()\n",
    "ax_1.set_xlabel('x(mm)')\n",
    "ax_1.set_ylabel('dose(Gy/MU)')\n",
    "ax_1.set_ylim([0, max(max_ref_dose,max_eva_dose) * 1.1])\n",
    "\n",
    "\n",
    "ax_2 = ax_1.twinx()\n",
    "ax_2.minorticks_on()\n",
    "ax_2.set_ylabel('gamma index')\n",
    "ax_2.set_ylim([0, gamma_options['max_gamma'] * 2.0 ])\n",
    "\n",
    "curve_0 = ax_1.plot(axis_reference, dose_reference,'k-',label='reference dose')\n",
    "curve_1 = ax_1.plot(axis_evaluation, dose_evaluation,'bo', mfc='none', markersize=5, label='evaluation dose')\n",
    "curve_2 = ax_2.plot(axis_reference, gamma, 'r*', label=f\"gamma ({gamma_options['dose_percent_threshold']}%/{gamma_options['distance_mm_threshold']}mm)\")\n",
    "curves = curve_0 + curve_1 + curve_2\n",
    "\n",
    "labels = [l.get_label() for l in curves] \n",
    "ax_1.legend(curves, labels, loc='best') \n",
    "ax_1.grid(True)\n",
    "\n",
    "# save figure first and show it\n",
    "figureName = '1D dose_reference_evaluation_{0} index.png'.format(gamma_norm_condition)\n",
    "plt.savefig(figureName) #plt.savefig() must be before plt.show()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "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.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
