{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Photometric calibration: fitting a stellar spectrum"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The 2MASS photometry of PZ Tel A is fitted with a [IRTF spectrum](http://irtfweb.ifa.hawaii.edu/~spex/IRTF_Spectral_Library/References_files/G.html) of a G8V type star. With the best-fit scaling parameter, synthetic photometry is calculated for the VLT/SPHERE H2 filter."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Getting started"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The required modules are imported, *species* is initiated, and an object of `Database` is created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import urllib.request\n",
    "import species\n",
    "from IPython.display import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initiating species v0.1.1... [DONE]\n",
      "Creating species_config.ini... [DONE]\n",
      "Database: /Users/tomasstolker/applications/species/docs/tutorials/species_database.hdf5\n",
      "Data folder: /Users/tomasstolker/applications/species/docs/tutorials/data\n",
      "Working folder: /Users/tomasstolker/applications/species/docs/tutorials\n",
      "Creating species_database.hdf5... [DONE]\n",
      "Creating data folder... [DONE]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<species.core.setup.SpeciesInit at 0x12e51f710>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "species.SpeciesInit()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "database = species.Database()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The distance and certainty of PZ Tel are defined and a dictionary with the 2MASS magnitudes is created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "distance = (47.13, 0.13)  # [pc]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "magnitudes = {'2MASS/2MASS.J':(6.856, 0.021),\n",
    "              '2MASS/2MASS.H':(6.486, 0.049),\n",
    "              '2MASS/2MASS.Ks':(6.366, 0.024)}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also a list with the filter names is created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "filters = list(magnitudes.keys())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding an object and calibration spectrum"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The distance and magnitudes are of PZ Tel A are stored in the database as object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding filter: 2MASS/2MASS.J... [DONE]\n",
      "Downloading Vega spectrum (270 kB)... [DONE]\n",
      "Adding Vega spectrum... [DONE]\n",
      "Adding filter: 2MASS/2MASS.H... [DONE]\n",
      "Adding filter: 2MASS/2MASS.Ks... [DONE]\n",
      "Adding object: PZ Tel A... [DONE]\n"
     ]
    }
   ],
   "source": [
    "database.add_object(object_name='PZ Tel A',\n",
    "                    distance=distance,\n",
    "                    app_mag=magnitudes,\n",
    "                    spectrum=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A G8V type spectrum is downloaded from the IRTF website."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'data/G8V_HD75732.txt'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "urllib.request.urlretrieve('http://irtfweb.ifa.hawaii.edu/~spex/IRTF_Spectral_Library/Data/G8V_HD75732.txt',\n",
    "                           'data/G8V_HD75732.txt')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And stored as calibration data in de database."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding calibration spectrum: G8V_HD75732... [DONE]\n"
     ]
    }
   ],
   "source": [
    "database.add_calibration(filename='data/G8V_HD75732.txt',\n",
    "                         tag='G8V_HD75732')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fitting the stellar spectrum"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The stellar spectrum is fitted to the 2MASS fluxes with a scaling parameter. The boundaries for the uniform prior is provided as dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Getting object: PZ Tel A... [DONE]\n"
     ]
    }
   ],
   "source": [
    "fit = species.FitSpectrum(object_name='PZ Tel A',\n",
    "                          filters=None,\n",
    "                          spectrum='G8V_HD75732',\n",
    "                          bounds={'scaling':(0., 1e0)})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The posterior distribution are estimated with the MCMC ensemble sampler of [*emcee*](https://emcee.readthedocs.io/en/stable/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running MCMC...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 1000/1000 [00:06<00:00, 152.69it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mean acceptance fraction: 0.786\n",
      "Integrated autocorrelation time = [3706.75420287]\n"
     ]
    }
   ],
   "source": [
    "fit.run_mcmc(nwalkers=200,\n",
    "             nsteps=1000,\n",
    "             guess={'scaling':5e-1},\n",
    "             tag='pztel')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotting the results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's plot the evolution of the walkers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plotting walkers: walkers.png... [DONE]\n"
     ]
    }
   ],
   "source": [
    "species.plot_walkers(tag='pztel',\n",
    "                     nsteps=None,\n",
    "                     offset=(-0.2, -0.08),\n",
    "                     output='walkers.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 13628 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image('walkers.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And the posterior distribution of the scaling parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plotting posteriors: posterior.png... [DONE]\n"
     ]
    }
   ],
   "source": [
    "species.plot_posteriors(tag='pztel',\n",
    "                        burnin=500,\n",
    "                        offset=(-0.3, -0.10),\n",
    "                        title_fmt='.4f',\n",
    "                        output='posterior.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 10496 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image('posterior.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For plotting the spectrum, the data of PZ Tel A are stored in an `ObjectBox`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Getting object: PZ Tel A... [DONE]\n"
     ]
    }
   ],
   "source": [
    "objectbox = database.get_object(object_name='PZ Tel A',\n",
    "                                filters=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, 30 randomly selected samples from the posterior are used for creating comparison spectra."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Getting MCMC spectra: 100%|██████████| 30/30 [00:00<00:00, 1247.19it/s]\n"
     ]
    }
   ],
   "source": [
    "samples = database.get_mcmc_spectra(tag='pztel',\n",
    "                                    burnin=500,\n",
    "                                    random=30,\n",
    "                                    wavel_range=(0.1, 50.0),\n",
    "                                    spec_res=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And also the best-fit value is extracted as the median of the posterior distribution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "median = database.get_median_sample(tag='pztel',\n",
    "                                    burnin=500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's have a look at the value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'scaling': 0.11991330981254578}\n"
     ]
    }
   ],
   "source": [
    "print(median)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With this value, the best-fit spectrum is calculated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "readcalib = species.ReadCalibration(tag='G8V_HD75732',\n",
    "                                    filter_name=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "spectrum = readcalib.get_spectrum(model_param=median)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The best-fit value is also used for creating synthetic photometry in the 2MASS filters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Calculating synthetic photometry... [DONE]\n"
     ]
    }
   ],
   "source": [
    "synphot = species.multi_photometry(datatype='calibration',\n",
    "                                   spectrum='G8V_HD75732',\n",
    "                                   filters=filters,\n",
    "                                   parameters=median)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The difference between the data and the best-fit synthetic photometry is stored in a `ResidualsBox`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Calculating synthetic photometry... [DONE]\n",
      "Calculating residuals... [DONE]\n"
     ]
    }
   ],
   "source": [
    "residuals = species.get_residuals(datatype='calibration',\n",
    "                                  spectrum='G8V_HD75732',\n",
    "                                  parameters=median,\n",
    "                                  filters=filters,\n",
    "                                  objectbox=objectbox,\n",
    "                                  inc_phot=True,\n",
    "                                  inc_spec=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, all the boxes are provide as input to the `plot_spectrum` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plotting spectrum: spectrum.png... [DONE]\n"
     ]
    }
   ],
   "source": [
    "species.plot_spectrum(boxes=[samples, spectrum, objectbox, synphot],\n",
    "                      filters=filters,\n",
    "                      colors=['gray', 'black', ('black', None), 'black'],\n",
    "                      residuals=residuals,\n",
    "                      xlim=(1., 2.5),\n",
    "                      ylim=(-1.5e-12, 1.1e-11),\n",
    "                      scale=('linear', 'linear'),\n",
    "                      offset=(-0.3, -0.08),\n",
    "                      output='spectrum.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 52104 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image('spectrum.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Photometric calibration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The magnitude of PZ Tel B can now be computed for any other filter within the wavelength coverage of the IRTF spectrum. This example calculates the flux and magnitude for the VLT/SPHERE H2 filter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding filter: Paranal/SPHERE.IRDIS_D_H23_2... [DONE]\n"
     ]
    }
   ],
   "source": [
    "readcalib = species.ReadCalibration(tag='G8V_HD75732',\n",
    "                                    filter_name='Paranal/SPHERE.IRDIS_D_H23_2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Flux density [W m-2 micron-1] = 3.30e-12\n"
     ]
    }
   ],
   "source": [
    "flux = readcalib.get_flux(model_param=median)\n",
    "print(f'Flux density [W m-2 micron-1] = {flux:.2e}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Apparent magnitude [mag]] = 6.50\n",
      "Absolute magnitude [mag] = 3.13\n"
     ]
    }
   ],
   "source": [
    "app_mag, abs_mag = readcalib.get_magnitude(model_param=median, distance=distance[0])\n",
    "print(f'Apparent magnitude [mag]] = {app_mag:.2f}')\n",
    "print(f'Absolute magnitude [mag] = {abs_mag:.2f}')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
