Applying a Model to light curves

Applying a Model to light curves#

This notebook will go through reformatting an Otter JSON file to the JSON file format expected by MOSFiT (https://mosfit.readthedocs.io/en/latest/)

First, go to that link above and install mosfit if you haven’t already!

Setup#

[1]:
# imports
import otter
import mosfit
import numpy as np
import pandas as pd
import os
import glob
import json
from collections import OrderedDict

import matplotlib.pyplot as plt

from astropy import units as u
[2]:
# connect to the dataset
db = otter.Otter()
Attempting to login to https://otter.idies.jhu.edu/api with the following credentials:
username: user-guest
password: test
[3]:
# Select the mosfit TDE model since we will later be modeling a TDE
model = mosfit.model.Model(model='tde')

Converting the OTTER dataset to MOSFiT format#

The below function will do this conversion for us!

[4]:
def otter_to_mosfit(db, names, outdir="", verbose=True, **query_kwargs):

    outpaths = []
    for name in names:
        phot = db.get_phot(
            obs_type="uvoir",
            names=name,
            flux_unit="uJy",
            drop_no_host_subtract = True,
            drop_unclear_host_subtract = True,
            **query_kwargs
        )

        meta = db.get_meta(names=name)[0]

        col_map = {
            "filter_name" : "band",
            "converted_flux" : "f_nu",
            "converted_flux_err" : "e_flux_density",
            "converted_flux_units": "u_flux",
            "converted_date" : "time"
        }
        phot = phot.rename(columns=col_map)

        phot = phot.drop(columns = [
            "converted_freq",
            "converted_flux_unit",
            "converted_date_unit",
            "converted_freq_unit",
            "obs_type",
            "human_readable_refs"
        ])


        phot.time = phot.time.astype(float)
        phot["instrument"] = None
        phot["redshift"] = float(meta.get_redshift())
        phot["name"] = name

        phot["band"] = [b.split(".")[0].strip() for b in phot.band]

        # only take data from 25 days before to 2 years after discovery
        discovery = meta.get_discovery_date().mjd
        phot = phot[(phot.time > discovery-25) * (phot.time < discovery+2*365)]
        if not len(phot):
            if not verbose: continue
            print(f"Skipping {name} because no good photometry!")
            continue

        # filter out infrared data that MOSFiT can't handle
        phot = phot[phot.converted_wave < 1_000]

        # handle upperlimits
        # this includes binning the data if needed
        phot.upperlimit = phot.apply(lambda row : row.f_nu < 3*row.e_flux_density if pd.isna(row.upperlimit) else row.upperlimit, axis=1)

        # convert it to the astrocat json format
        outpath = os.path.join(outdir, f"{name}.csv")
        phot.to_csv(outpath, index=False, sep='\t')
        outpaths.append(outpath)


        if not verbose: continue
        fig, ax = plt.subplots()
        ax.set_ylabel("Flux [uJy]")
        ax.set_xlabel("MJD")
        ax.set_yscale("log")
        ax.set_title(f"Fitting Data for {name}")
        for band, grp in phot.groupby('band'):
            uplims = grp[grp.upperlimit]
            dets = grp[~grp.upperlimit]

            ax.errorbar(dets.time, dets.f_nu, yerr=dets.e_flux_density, marker='o', linestyle='none', color=mosfit.plotting.bandcolorf(band), label=band)
            ax.plot(uplims.time, uplims.f_nu, marker='v', linestyle='none', color=mosfit.plotting.bandcolorf(band), alpha=0.2)
        ax.legend()
        fig.savefig(f"{name}-mosfit-input-plot.png")


    printer = mosfit.printer.Printer()
    converter = mosfit.converter.Converter(printer)
    outjsons = converter.generate_event_list(outpaths)

    for j in outjsons:
        os.rename(j, os.path.join(outdir, j))

    return outjsons

Now we can call this function to convert the otter datafile of AT2021sdu to the mosfit format

[5]:
query_kwargs = dict(
    return_type = "pandas"
)

phot_files = otter_to_mosfit(db, names = ["AT2021sdu"], outdir=".", **query_kwargs)
phot_files
Unable to apply the source mapping because '2023ApJ...955L...6Y'
2021sdu has at least one photometry point where it is unclear if a host subtraction was performed. This can be especially detrimental for UV data. Please consider filtering out UV/Optical/IR or radio rows where the corr_host column is null/None/NaN.

The ASCII converter in MOSFiT converts flat ASCII tables to the Open Catalog's JSON schema. Inputs
are preferably provided by the user in the fixed-width CDS format, but if not, the converter works
best if the data:
1. Uses consistent delimeters throughout (i.e. just tabs, just spaces, etc.).
2. Has a single header column specifying column contents.
3. Specifies the instrument and photometric system used for each observation.
4. Contains a single event per file (not multiple events per file or multiple files per event).

Please note that conversions are inherently imperfect and that you should always scan the output
JSON file for errors.

Converting input file `./AT2021sdu.csv` to JSON format...


What are the units of the flux density column, e.g. "µJy" or "millijansky" (if left blank, "µJy"
will be assumed):
Would you like to merge this data with previously converted data in this directory? ([y]/n)  n
[5]:
['AT2021sdu.json']
../_images/examples_modeling_7_4.png

And you should now be able to run MOSFiT like you normally would from the terminal on this file!

[ ]: