<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 The LightCurve class
Background
What kind of physical data are we representing and what do these quantities mean?
Astrophysical variable sources including transients like supernovae are sources that are (roughly) fixed in position but change appreciably at human time scales, such that their measurements at different points of time in a survey are expected to be different. The key science of such sources has to do with interpreting such data.
In a photometric or imaging survey, the raw data associated with such measurements is in the form of a time series of images, along with metadata. This is often extracted into a catalog summarizing the inferred brightness of the source in the filter band and the uncertainties of the inferred. The uncertainties in this process are dominated by the sky noise which is Poisson distributed to a good approximation. Hence, the format of this recorded data is usually of the form
timestamp, flux, flux uncertainty, zero point, magnitude system
Note that the flux is really the band flux obtained in a filter band
The zero point, and magnitude system are methods of specifying the units of the reported flux, and flux uncertainty. flux may be reported so that the following equation with bandflux and std_bandflux in the same physical units holds. The std_bandflux depends on the transmissions and the magnitude system used.
bandmag 
Step1:  Instantiation
The class is instantiated using a constructor that has a mandatory input of a dataframe. and optional inputs. The dataframe must contain the light curve information, and the minimum set of columns required are
Step2:  This was a SNCosmo example dataset, loaded into pandas.DataFrame. Note that the column representing temporal information is time. Now, we will use this to instantiate our class.
Step3:  We get the representation in our convention by accessing the attribute lightCurve, which is a dataFrame with columns of the standard name. It could have more columns, but the minimal columns have to be there. If we supplied a dataFrame without having the minimal number of columns, it will raise a valueError, as described later. From the lightCurve attribute, we note that time has changed to our standard name mjd
Step4:  What would have happened if an essential column was missing? to check let us do the following
Step5:  This raises a ValueError pointing out that the column band was missing. However, it correctly recognizes that while
mjd was missing, it had the aliased column time instead and did not report it missing.
Light Curves in SNCosmo Format
SNCosmo has a data format using astropy.table.Table. Since, we use SNCosmo to plot, or fit light curves, it is essential that we can regenerate the SNCosmo format data easily. We do this by the following method
Step6:  We can now plot the data using the usual SNCosmo plotting method, showing the data in g, r, and z bands.
Step7:  SNANA simulations
Step8:  Let us look at what the array in the fits file looks like
Step9:  Fitting
Step10:  To infer the light curve model parameters, we need a model. We will use the SALT model from SNCosmo
Step11:  We will not try to infer the redshift first
Step12:  We have two main methods of trying to infer the model parameters
Step13:  Scratch
<ASSISTANT_TASK:>
Python Code:
import sncosmo
import analyzeSN as ans
import numpy as np
from analyzeSN import LightCurve
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
Explanation: The LightCurve class
Background
What kind of physical data are we representing and what do these quantities mean?
Astrophysical variable sources including transients like supernovae are sources that are (roughly) fixed in position but change appreciably at human time scales, such that their measurements at different points of time in a survey are expected to be different. The key science of such sources has to do with interpreting such data.
In a photometric or imaging survey, the raw data associated with such measurements is in the form of a time series of images, along with metadata. This is often extracted into a catalog summarizing the inferred brightness of the source in the filter band and the uncertainties of the inferred. The uncertainties in this process are dominated by the sky noise which is Poisson distributed to a good approximation. Hence, the format of this recorded data is usually of the form
timestamp, flux, flux uncertainty, zero point, magnitude system
Note that the flux is really the band flux obtained in a filter band
The zero point, and magnitude system are methods of specifying the units of the reported flux, and flux uncertainty. flux may be reported so that the following equation with bandflux and std_bandflux in the same physical units holds. The std_bandflux depends on the transmissions and the magnitude system used.
bandmag := -2.5 log10(bandflux / std_bandflux) = -2.5 log10(flux) + zero point
so that a zero point of zero, implies that flux is bandflux in units of std_bandflux
Desired Functionality
the LightCurve class is meant to be a standard internal representation of this kind of catalog data in our software. This means that 
- given a different format/model of data, we will first convert it into an instance of this class.
- All our calculations will be defined on instances of this class
- We should have write methods to convert the instances of this class to useful formats for serialization.
Structure
End of explanation
ex_data = sncosmo.load_example_data().to_pandas()
ex_data.head()
Explanation: Instantiation
The class is instantiated using a constructor that has a mandatory input of a dataframe. and optional inputs. The dataframe must contain the light curve information, and the minimum set of columns required are:
mjd, band, flux, flux_err, zp, zpsys or recognized aliases. Here, we load some data and demonstrate this
End of explanation
lc = LightCurve(ex_data)
Explanation: This was a SNCosmo example dataset, loaded into pandas.DataFrame. Note that the column representing temporal information is time. Now, we will use this to instantiate our class.
End of explanation
lc.lightCurve.head()
Explanation: We get the representation in our convention by accessing the attribute lightCurve, which is a dataFrame with columns of the standard name. It could have more columns, but the minimal columns have to be there. If we supplied a dataFrame without having the minimal number of columns, it will raise a valueError, as described later. From the lightCurve attribute, we note that time has changed to our standard name mjd
End of explanation
lc_tmp = ex_data.copy()
del lc_tmp['band']
lc_tmp.head()
lc_bad = LightCurve(lc_tmp)
Explanation: What would have happened if an essential column was missing? to check let us do the following:
   - We create a dataframe like the above, but remove the essential column band
   - We attempt to create an instance of the LightCurve class
End of explanation
SNCosmoLC = lc.snCosmoLC()
SNCosmoLC
Explanation: This raises a ValueError pointing out that the column band was missing. However, it correctly recognizes that while
mjd was missing, it had the aliased column time instead and did not report it missing.
Light Curves in SNCosmo Format
SNCosmo has a data format using astropy.table.Table. Since, we use SNCosmo to plot, or fit light curves, it is essential that we can regenerate the SNCosmo format data easily. We do this by the following method
End of explanation
sncosmo.plot_lc(SNCosmoLC)
Explanation: We can now plot the data using the usual SNCosmo plotting method, showing the data in g, r, and z bands.
End of explanation
from analyzeSN import SNANASims
from astropy.table import Table
megacamBandNames = 'ugriz'
megacamRegisteredNames = tuple('mega_' + band for band in megacamBandNames)
snana_eg = SNANASims.fromSNANAfileroot(snanafileroot='snana_fits',
                                       location='../analyzeSN/example_data/',
                                       coerce_inds2int=False,
                                       SNANABandNames=megacamBandNames,
                                       registeredBandNames=megacamRegisteredNames)
Table.read(snana_eg.photFile)[45:50]
Explanation: SNANA simulations
End of explanation
snana_eg.bandNames
snana_eg.newbandNames
lcInstance = snana_eg.get_SNANA_photometry(snid='03D1aw')
lcInstance.lightCurve[['mjd', 'band', 'flux', 'fluxerr', 'zp', 'zpsys']]
lcInstance.bandNameDict
snana_eg.headData['REDSHIFT_FINAL']
Explanation: Let us look at what the array in the fits file looks like: 
- It has fields that are not of the standard name (FLUXCAL)
- It has things like "XXX" in he fields
End of explanation
import sncosmo
Explanation: Fitting
End of explanation
dust = sncosmo.CCM89Dust()
model = sncosmo.Model(source='salt2', effects=[dust],
                     effect_names=['host', 'mw'], effect_frames=['rest', 'obs'])
Explanation: To infer the light curve model parameters, we need a model. We will use the SALT model from SNCosmo
End of explanation
model.set(z=0.5817)
Explanation: We will not try to infer the redshift first
End of explanation
resfit = sncosmo.fit_lc(lcInstance.snCosmoLC(), model, vparam_names=['t0', 'x0', 'x1', 'c'], modelcov=False)
res = sncosmo.mcmc_lc(lcInstance.snCosmoLC(), model, vparam_names=['t0', 'x0', 'x1', 'c'], modelcov=False)
from analyzeSN import ResChar
reschar = ResChar.fromSNCosmoRes(res)
reschar.salt_samples()['t0'].mean()
reschar.salt_samples()['c'].mean()
resfit[0].parameters[2]
resfit[0].parameters[2]
reschar.salt_samples()['c'].std()
fig, ax  = plt.subplots(1, 4)
reschar.salt_samples()['c'].hist(bins=np.arange(-0.6, 0.6, 0.03), lw=2., histtype='step', normed=1, ax=ax[0])
reschar.salt_samples()['x1'].hist(bins=np.arange(-4., 4., 0.2), lw=2., histtype='step', normed=1, ax=ax[1])
reschar.salt_samples()['t0'].hist(bins=10, lw=2., histtype='step', normed=1, ax=ax[2])
reschar.salt_samples()['mu'].hist(bins=10, lw=2., histtype='step', normed=1, ax=ax[3])
sns.distplot(reschar.salt_samples()['t0'], rug=False, color='r', hist_kws=dict(histtype='step', lw=2., alpha=1., color='k'))
resfit[0].errors['c']
Explanation: We have two main methods of trying to infer the model parameters: the first one is a maximum likelihood estimate
End of explanation
10**(-0.4 * 0.27)
-2.5 * np.log10(f) 
10.0**(0.27 / 2.5 )
Explanation: Scratch
End of explanation
<END_TASK>