diff --git a/.gitignore b/.gitignore index 8a89e0a..2d50de4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ env/ # Sphinx documentation docs/build/ docs/_build/ + +# Test coverage +.coverage diff --git a/.vscode/settings.json b/.vscode/settings.json index 022897c..a46abd7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,7 @@ "test_*.py" ], "python.testing.pytestEnabled": false, - "python.testing.unittestEnabled": true + "python.testing.unittestEnabled": true, + "esbonio.server.enabled": true, + "python.formatting.provider": "black" } \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2412b48..1c86aa2 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/superbol/FlxuCurve.py b/superbol/FlxuCurve.py new file mode 100644 index 0000000..f18dcfe --- /dev/null +++ b/superbol/FlxuCurve.py @@ -0,0 +1,44 @@ +import matplotlib.pyplot as plt + +from superbol import extinction, read_osc + +""" +TODO Need to create a class that contains the fluxes, magnitudes and etc. that are calculated from +an osc collection +This class should also contain a function that opens a graph to view the flux and its details +""" +class FluxCurve: + """constructor for file path, + constructor for photometry given + constructor for url given + """ + photometries = [] + luminosities = [] + times = [] + + def __init__(self, photometries): + self.photometries = photometries + self.luminosities + # fluxes = [] + # for photometry_dict in photometries: + # try: + # observed_magnitude = read_osc.get_observed_magnitude(photometry_dict) + # extinction_value = extinction.get_extinction_by_name(extinction_table, observed_magnitude.band) + # observed_magnitude.magnitude = extinction.correct_observed_magnitude(observed_magnitude, extinction_value) + # fluxes.append(observed_magnitude.convert_to_flux()) + # except: + # pass + + # distance = lum.Distance(3.0E7 * 3.086E18, 7.0E6 * 3.086E18) + # self.luminosities = lightcurve.calculate_lightcurve(fluxes, distance, lqbol.calculate_qbol_flux) + + + def draw_curve(self): + x=[1,3,5,7] + y=[2,4,6,1] + print('drawing curve') + plt.plot(x,y) + plt.show() + + def sum_fn(self): + print('yeah im working. what ab it') \ No newline at end of file diff --git a/superbol/blackbody.py b/superbol/blackbody.py index c8a7105..7bc626b 100644 --- a/superbol/blackbody.py +++ b/superbol/blackbody.py @@ -4,6 +4,7 @@ from astropy import constants as const from .planck import * + def bb_flux(wavelength, temperature, angular_radius): """Observed flux at `wavelength` from a blackbody of `temperature` and `angular_radius` in cgs units @@ -15,10 +16,15 @@ def bb_flux(wavelength, temperature, angular_radius): Returns: Astropy Quantity: blackbody flux in :math:`erg \\; s^{-1} cm^{-2} Anstrom^{-1}` """ - bb_flux = (np.pi * u.sr) * planck_function(wavelength, temperature) * (angular_radius)**2 + bb_flux = ( + (np.pi * u.sr) + * planck_function(wavelength, temperature) + * (angular_radius) ** 2 + ) return bb_flux + def bb_flux_nounits(wavelength, temperature, angular_radius): """Identical to bb_flux, but returns the value rather than the Astropy Quantity. @@ -26,76 +32,12 @@ def bb_flux_nounits(wavelength, temperature, angular_radius): """ return bb_flux(wavelength, temperature, angular_radius).value -def bb_total_flux(self): - """Integrate the planck function from :math:`\\lambda = 0` to - :math:`\\lambda = \\infty`, then convert result to observed flux. - The calculation is done using the Stefan-Boltxmann law, rather than - performing an actual integral using numerical integration. The - `angular_radius` is included to convert the result to an observed flux. - Args: - temperature (float): Temperature in Kelvin - angular_radius (float): Angular radius :math:`(\\theta = \\frac{R}{D})` - Returns: - float: The value of :math:`\\sigma \\frac{R^2}{D^2} T^4` - """ - bb_total_flux = (const.sigma_sb * self.angular_radius**2 - * self.temperature**4) - bb_total_flux = bb_total_flux.to(u.erg / (u.s * u.cm**2)) - return bb_total_flux.value -def bb_flux_integrated(wavelength, temperature, angular_radius): - """Integrate the planck function from :math:`\\lambda = 0` to :math:`\\lambda =` `wavelength`, then convert result to observed flux - - Args: - wavelength (float): Wavelength in Angstroms - temperature (float): Temperature in Kelvin - angular_radius (float): Angular radius :math:`(\\theta = \\frac{R}{D})` - - Returns: - float: Value of the integrated flux in :math:`erg \\; s^{-1} cm^{-2}` - """ - bb_flux_integrated = (np.pi * u.sr) * planck_integral(wavelength, temperature) * (angular_radius)**2 - - return bb_flux_integrated.value - -def dbb_flux_integrated_dT(wavelength, temperature, angular_radius): - """Take the derivative of the integrated planck function, then convert result to observed flux. This is used in error propagation calculations. - - Args: - wavelength (float): Wavelength in Angstroms - temperature (float): Temperature in Kelvin - angular_radius (float): Angular radius :math:`(\\theta = \\frac{R}{D})` - - Returns: - float: Derivative of the integrated blackbody flux at `wavelength` with respect to `temperature` - """ - dbb_flux_integrated_dT = (np.pi * u.sr) * d_planck_integral_dT(wavelength, temperature) * (angular_radius)**2 - - return dbb_flux_integrated_dT.value - -def dbb_total_flux_dT(temperature, angular_radius): - """Take the derivative of the total blackbody flux with respect to temperature - - The calculation takes a derivative of the Stefan-Boltzmann law with respect to temperature. The `angular_radius` is present to convert the result to an observed flux. - - Args: - temperature (float): Temperature in Kelvin - angular_radius (float): Angular radius :math:`(\\theta = \\frac{R}{D})` - - Returns: - float: The value of :math:`4 \\sigma \\frac{R^2}{D^2} T^3` - """ - temperature = u.Quantity(temperature, u.K) - bb_total_flux = 4.0 * const.sigma_sb * (angular_radius**2) * temperature**3 - bb_total_flux = bb_total_flux.to(u.erg / (u.s * u.cm**2 * u.K)) - return bb_total_flux.value - class BlackbodyFit(object): - def __init__(self): self.temperature = None self.angular_radius = None @@ -105,12 +47,12 @@ def __init__(self): def fit_to_SED(self, SED): """Fits the temperature and angular_radius of a blackbody to the SED - + The initial guesses for the `temperature` and `angular_radius` are :math:`T = 5000` K and :math:`\\theta = 1.0 \\times 10^{-10}`. These are typical for an extragalactic supernovae, but should be used with caution for any other objects. - + Args: SED (list): List of observed MonochromaticFlux objects. """ @@ -118,10 +60,15 @@ def fit_to_SED(self, SED): fluxes = [f.flux for f in SED] flux_uncertainties = [f.flux_uncertainty for f in SED] - popt, pcov = curve_fit(bb_flux_nounits, wavelengths, fluxes, - p0=[5000, 1.0e-10], sigma=flux_uncertainties, - absolute_sigma=True) - + popt, pcov = curve_fit( + bb_flux_nounits, + wavelengths, + fluxes, + p0=[5000, 1.0e-10], + sigma=flux_uncertainties, + absolute_sigma=True, + ) + self.SED = SED self.temperature = popt[0] self.angular_radius = popt[1] @@ -130,18 +77,22 @@ def fit_to_SED(self, SED): self.temperature_err = perr[0] self.angular_radius_err = perr[1] - def __call__(self, wavelength): """Flux of the blackbody at a given wavelength in angstroms - + Args: wavelength (float): Wavelength in Angstroms - + Returns: bb_flux (float): blackbody flux at given wavelength in cgs units""" if self.temperature == None: + # TODO No test written return None else: - bb_flux = (np.pi * u.sr * planck_function(wavelength, self.temperature) - * self.angular_radius**2) + bb_flux = ( + np.pi + * u.sr + * planck_function(wavelength, self.temperature) + * self.angular_radius**2 + ) return bb_flux.value diff --git a/superbol/lbc.py b/superbol/lbc.py index a961843..1b331d5 100644 --- a/superbol/lbc.py +++ b/superbol/lbc.py @@ -8,54 +8,74 @@ from superbol.lum import BolometricFlux dirname = os.path.dirname(__file__) -bc_color_fits = os.path.join(dirname, '../data/bc_color_fits.json') +bc_color_fits = os.path.join(dirname, "../data/bc_color_fits.json") + def calculate_bc_flux_h01(obs_group): """Turn a group of observations into an average BC flux - - Args: + + Args: obs_group: observed photometry - Returns: + Returns: BC Bolemetric flux - """ + """ obs_group.sort(key=lambda x: x.band.effective_wavelength) - if 'V' in [x.band.name for x in obs_group]: + if "V" in [x.band.name for x in obs_group]: fbc = [] for obs_pair in itertools.combinations(obs_group, 2): try: - bc = compute_bolometric_correction('H01', obs_pair[0], obs_pair[1]) - mbol = apply_bolometric_correction(bc, next(obs for obs in obs_group if obs.band.name == 'V')) + bc = compute_bolometric_correction("H01", obs_pair[0], obs_pair[1]) + mbol = apply_bolometric_correction( + bc, next(obs for obs in obs_group if obs.band.name == "V") + ) + # TODO Is this a hard coded value or a constant zeropoint = -10.88802466 Fbol = convert_mbol_to_Fbol(mbol, zeropoint) fbc.append(Fbol) except InvalidColor: + # TODO No test written pass except InvalidBCMethod: + # TODO No test written pass except InvalidFilterCombination: + # TODO No test written pass - return BCBolometricFlux(np.mean([x.value for x in fbc]), np.mean([x.uncertainty for x in fbc]), np.mean([x.time for x in fbc])) + return BCBolometricFlux( + np.mean([x.value for x in fbc]), + np.mean([x.uncertainty for x in fbc]), + np.mean([x.time for x in fbc]), + ) + +# TODO No test written def calculate_bc_flux_bh09(obs_group): """Turn a group of observations into an average BC flux""" obs_group.sort(key=lambda x: x.band.effective_wavelength) - if 'V' in [x.band.name for x in obs_group]: + if "V" in [x.band.name for x in obs_group]: fbc = [] for obs_pair in itertools.combinations(obs_group, 2): try: - bc = compute_bolometric_correction('BH09', obs_pair[0], obs_pair[1]) - mbol = apply_bolometric_correction(bc, next(obs for obs in obs_group if obs.band.name == 'V')) + bc = compute_bolometric_correction("BH09", obs_pair[0], obs_pair[1]) + mbol = apply_bolometric_correction( + bc, next(obs for obs in obs_group if obs.band.name == "V") + ) zeropoint = -11.64 Fbol = convert_mbol_to_Fbol(mbol, zeropoint) fbc.append(Fbol) except InvalidColor: pass except InvalidBCMethod: + # TODO No test written pass except InvalidFilterCombination: pass - return BCBolometricFlux(np.mean([x.value for x in fbc]), np.mean([x.uncertainty for x in fbc]), np.mean([x.time for x in fbc])) + return BCBolometricFlux( + np.mean([x.value for x in fbc]), + np.mean([x.uncertainty for x in fbc]), + np.mean([x.time for x in fbc]), + ) def compute_bolometric_correction(method_name, obs1, obs2): @@ -69,44 +89,58 @@ def compute_bolometric_correction(method_name, obs1, obs2): if range_min <= color <= range_max: bc = compute_polynomial(color, coefficients) poly_deriv = compute_polynomial_derivative(color, coefficients) - uncertainty = np.sqrt(rms**2 + (poly_deriv * color_err)**2) + uncertainty = np.sqrt(rms**2 + (poly_deriv * color_err) ** 2) return BolometricCorrection(bc, uncertainty) else: - raise InvalidColor("Cannot calculate bolometric correction, given " + - "{0}-{1} color outside the allowable range for " + - "the {2} method.".format(obs1.band.name, - obs2.band.name, - method_name)) + # TODO No test written + raise InvalidColor( + "Cannot calculate bolometric correction, given " + + "{0}-{1} color outside the allowable range for " + + "the {2} method.".format(obs1.band.name, obs2.band.name, method_name) + ) + def retrieve_bc_method_data(method_name, path=bc_color_fits): - with open(path, 'r') as bc_color_data_file: + with open(path, "r") as bc_color_data_file: file_content = json.load(bc_color_data_file) try: return file_content[method_name] except KeyError: - raise InvalidBCMethod(f"Bolometric correction method {method_name} not found") + raise InvalidBCMethod( + f"Bolometric correction method {method_name} not found" + ) + def get_bc_method_coefficients(method_data, band1, band2): try: - return method_data[band1.name + '-' + band2.name]['coefficients'] + return method_data[band1.name + "-" + band2.name]["coefficients"] except KeyError: - raise InvalidFilterCombination(f"{band1.name} - {band2.name} not an allowable color for this method") + raise InvalidFilterCombination( + f"{band1.name} - {band2.name} not an allowable color for this method" + ) + def get_bc_method_range(method_data, band1, band2): - range_min = method_data[band1.name + '-' + band2.name]['range_min'] - range_max = method_data[band1.name + '-' + band2.name]['range_max'] + range_min = method_data[band1.name + "-" + band2.name]["range_min"] + range_max = method_data[band1.name + "-" + band2.name]["range_max"] return range_min, range_max + def get_bc_method_rms(method_data, band1, band2): - return method_data[band1.name + '-' + band2.name]['rms'] + return method_data[band1.name + "-" + band2.name]["rms"] + +# TODO Method not used in integration but still has a unit test def get_bc_method_zeropoint(method_data): - return method_data['properties']['ZP'] + return method_data["properties"]["ZP"] + def apply_bolometric_correction(bc, observed_magnitude): """Apply the bolometric correction to the observed magnitude""" mbol_value = bc.value + observed_magnitude.magnitude - mbol_uncertainty = math.sqrt(bc.uncertainty**2 + observed_magnitude.uncertainty**2) + mbol_uncertainty = math.sqrt( + bc.uncertainty**2 + observed_magnitude.uncertainty**2 + ) mbol_time = observed_magnitude.time return BolometricMagnitude(mbol_value, mbol_uncertainty, mbol_time) @@ -114,37 +148,40 @@ def apply_bolometric_correction(bc, observed_magnitude): class InvalidColor(Exception): pass + class InvalidBCMethod(Exception): pass + class InvalidFilterCombination(Exception): pass -class BolometricMagnitude(object): +class BolometricMagnitude(object): def __init__(self, value, uncertainty, time): self.value = value self.uncertainty = uncertainty self.time = time -class BCBolometricFlux(BolometricFlux): +class BCBolometricFlux(BolometricFlux): def __init__(self, value, uncertainty, time): super().__init__(value, uncertainty) self.time = time - + def to_lbol(self, distance): + # TODO No test written lbol = super().to_lbol(distance) lbol.time = self.time return lbol class BolometricCorrection(object): - def __init__(self, value, uncertainty): self.value = value self.uncertainty = uncertainty + def compute_polynomial(color, coefficients): """Compute the bc-color polynomial""" result = 0.0 @@ -152,6 +189,7 @@ def compute_polynomial(color, coefficients): result += coefficient * color**n return result + def compute_polynomial_derivative(color, coefficients): """Compute the derivative of the bc-color polynomial""" result = 0.0 @@ -159,10 +197,11 @@ def compute_polynomial_derivative(color, coefficients): result = coefficients[1] else: for n, coefficient in enumerate(coefficients): - result += n * coefficient * color**(n-1) + result += n * coefficient * color ** (n - 1) return result + def convert_mbol_to_Fbol(mbol, zeropoint): - Fbol = 10**((-mbol.value + zeropoint)/2.5) - Fbol_uncertainty = np.abs(math.log(10)/2.5 * Fbol * mbol.uncertainty) + Fbol = 10 ** ((-mbol.value + zeropoint) / 2.5) + Fbol_uncertainty = np.abs(math.log(10) / 2.5 * Fbol * mbol.uncertainty) return BCBolometricFlux(Fbol, Fbol_uncertainty, mbol.time) diff --git a/superbol/lightcurve.py b/superbol/lightcurve.py index 1b6e62d..f504fee 100644 --- a/superbol/lightcurve.py +++ b/superbol/lightcurve.py @@ -4,6 +4,7 @@ from superbol import photometry # TODO Doc these +# TODO No tests written for fns in this file def calculate_lightcurve(fluxes, distance, flux_calculator): grouped_fluxes = sed.group_fluxes(fluxes, math.floor) SEDs = [sed.get_SED(flux_group) diff --git a/superbol/lqbol.py b/superbol/lqbol.py index 9bedfe6..d0e7c31 100644 --- a/superbol/lqbol.py +++ b/superbol/lqbol.py @@ -70,6 +70,7 @@ def uncertainty_calculator_trapezoidal(fluxes): return math.sqrt(radicand) +# TODO No test written def calculate_qbol_flux(flux_group): """Turn a group of fluxes into a quasi-bolometric flux""" return get_quasi_bolometric_flux(TrapezoidalIntegralCalculator(), diff --git a/superbol/mag2flux.py b/superbol/mag2flux.py index 5407ee7..3b80353 100644 --- a/superbol/mag2flux.py +++ b/superbol/mag2flux.py @@ -2,13 +2,13 @@ # TODO Doc these class ObservedMagnitude(object): - def __init__(self, magnitude, uncertainty, band, time): self.magnitude = magnitude self.uncertainty = uncertainty self.band = band self.time = time + # TODO No test written def __str__(self): return str(self.__dict__) @@ -18,35 +18,37 @@ def __eq__(self, other): def convert_to_flux(self): return MagnitudeToFluxConverter().convert(self) + class Band(object): - def __init__(self, name, alt_name, effective_wavelength, flux_conversion_factor): self.name = name self.alt_name = alt_name self.effective_wavelength = effective_wavelength self.flux_conversion_factor = flux_conversion_factor + # TODO No test written def __eq__(self, other): return self.__dict__ == other.__dict__ -class MonochromaticFlux(object): +class MonochromaticFlux(object): def __init__(self, flux, flux_uncertainty, wavelength, time): self.flux = flux self.flux_uncertainty = flux_uncertainty self.wavelength = wavelength self.time = time + # TODO No test written def __str__(self): return str(self.__dict__) def __eq__(self, other): return self.__dict__ == other.__dict__ -class MagnitudeToFluxConverter(object): +class MagnitudeToFluxConverter(object): def _calculate_flux(self, magnitude, flux_conversion_factor): - return flux_conversion_factor * 10**(-0.4 * magnitude) + return flux_conversion_factor * 10 ** (-0.4 * magnitude) def _calculate_flux_uncertainty(self, flux, magnitude_uncertainty): return flux * 0.4 * math.log(10) * magnitude_uncertainty diff --git a/superbol/photometry.py b/superbol/photometry.py index 59227ef..608781e 100644 --- a/superbol/photometry.py +++ b/superbol/photometry.py @@ -109,6 +109,7 @@ def get_interpolated_magnitudes(lightcurve, observed_times): interpolated_magnitude_value, interpolated_magnitude_uncertainty, previous_observed_magnitude.band, unobserved_time) interpolated_magnitudes.append(interpolated_magnitude) except MissingMagnitudeOutOfBounds: + # TODO No test written pass return interpolated_magnitudes diff --git a/superbol/planck.py b/superbol/planck.py index d02349e..86e81b5 100644 --- a/superbol/planck.py +++ b/superbol/planck.py @@ -68,42 +68,3 @@ def planck_integral(wavelength, temperature): B_integral = (C1 * temperature**4 / C2**4) * series / u.sr return B_integral.to(u.erg / (u.s * u.cm**2 * u.sr)) - - -def d_planck_integral_dT(wavelength, temperature): - """Derivative of the integrated Planck function from :math:`\\lambda = 0` to - :math:`\\lambda =` `wavelength` using the infinite series approximation of the - integral. This is used in the error propagation calculation. - - TODO So uh, i dont' think this function's being tested, and I'm not sure what the first - steps would be to test it. I changed series to zero and the tests all still passed - - Args: - wavelength (float): Upper bound for the wavelength in Angstrom. - temperature (float): Temperature in Kelvin. - - Returns: - Astropy Quantity: Derivative of the integral of the planck function - with respect to T in :math:`erg \\; s^{-1} cm^{-2} sterad^{-1} K^{-1}` - """ - wavelength = u.Quantity(wavelength, unit=u.Angstrom) - temperature = u.Quantity(temperature, unit=u.K) - - C1 = 2.0 * const.h.cgs * const.c.cgs**2 - C2 = const.h.cgs * const.c.cgs / const.k_B.cgs - - x = C2 / (wavelength.to(u.cm) * temperature) - iterations = min(int(2 + 20/x.value), 512) - - series = 0.0 - for i in range(1, iterations): - term1 = C1 / (temperature * wavelength**4) - term2 = 4*C1 / (i * C2 * wavelength**3) - term3 = 12 * C1 * temperature / (i**2 * C2**2 * wavelength**2) - term4 = 24*C1*temperature**2 / (i**3 * C2**3 * wavelength) - term5 = 24 * C1 * temperature**3 / (i**4 * C2**4) - series += (term1 + term2 + term3 + term4 + term5) * np.exp(-i*x) - - dB_integral_dT = series / u.sr - - return dB_integral_dT.to(u.erg / (u.s * u.cm**2 * u.K * u.sr)) diff --git a/superbol/read_sne.py b/superbol/read_sne.py index 5cebc6e..bd476d0 100644 --- a/superbol/read_sne.py +++ b/superbol/read_sne.py @@ -3,5 +3,8 @@ from superbol import lightcurve, lqbol, lum, read_osc +def get_supernova_lum_dist(name): + return requests.get(f'https://api.astrocats.space/{name}/lumdist').json()[name]["lumdist"] + def get_supernova_photometry(name): return requests.get(f'https://api.astrocats.space/{name}/photometry/').json()[name]["photometry"] diff --git a/superbol/sed.py b/superbol/sed.py index a26dfd4..366a857 100644 --- a/superbol/sed.py +++ b/superbol/sed.py @@ -115,6 +115,7 @@ def get_interpolated_fluxes(lightcurve, observed_times): interpolated_flux_value, interpolated_flux_uncertainty, previous_flux.wavelength, unobserved_time) interpolated_fluxes.append(interpolated_flux) except MissingFluxOutOfBounds: + # TODO No test written pass return interpolated_fluxes @@ -135,6 +136,7 @@ def get_previous_flux(monochromatic_lightcurve, unobserved_time): if delta > 0: earlier_fluxes.append(flux) if earlier_fluxes == []: + # TODO No test written raise MissingFluxOutOfBounds return max(earlier_fluxes, key=lambda flux: flux.time) @@ -143,11 +145,13 @@ def get_next_flux(monochromatic_lightcurve, unobserved_time): later_fluxes = [ flux for flux in monochromatic_lightcurve if unobserved_time - flux.time < 0] if later_fluxes == []: + # TODO No test written raise MissingFluxOutOfBounds return min(later_fluxes, key=lambda flux: flux.time) # TODO Code review +# TODO Has unit test, but not used in integration tests def get_gap_size(times, unobserved_time): positive_deltas = [ time - unobserved_time for time in times if time - unobserved_time > 0] @@ -162,6 +166,7 @@ def get_unobserved_times(lightcurve, observed_times): observed_time for observed_time in observed_times if observed_time not in times] +# TODO Code review def get_observed_wavelengths(SEDs): wavelengths = [] for SED in SEDs: @@ -169,6 +174,7 @@ def get_observed_wavelengths(SEDs): return sorted(list(set(wavelengths))) +# TODO Code review def get_observed_times(SEDs): times = [] for SED in SEDs: diff --git a/tests/integration/test_00cb_synthetic_magnitudes.py b/tests/integration/test_00cb_synthetic_magnitudes.py index c3b7895..66d578f 100644 --- a/tests/integration/test_00cb_synthetic_magnitudes.py +++ b/tests/integration/test_00cb_synthetic_magnitudes.py @@ -15,8 +15,8 @@ from superbol import extinction dirname = os.path.dirname(__file__) -sn2000cb_extinction = os.path.join(dirname, '../../data/sn2000cb_extinction.dat') -extinction_table = Table.read(sn2000cb_extinction, format = 'ascii') +sn2000cb_extinction = os.path.join(dirname, "../../data/sn2000cb_extinction.dat") +extinction_table = Table.read(sn2000cb_extinction, format="ascii") sn00cb_synphot_data = """{ "SN2000cb":{ @@ -474,51 +474,70 @@ class TestQuasiBolometricLightcurve(unittest.TestCase): - def setUp(self): with patch("builtins.open", mock_open(read_data=sn00cb_synphot_data)): - self.sn00cb_osc_photometry = read_osc.retrieve_osc_photometry('SN2000cb') + self.sn00cb_osc_photometry = read_osc.retrieve_osc_photometry("SN2000cb") fluxes = [] for photometry_dict in self.sn00cb_osc_photometry: + # TODO Why is there a try catch here? try: observed_magnitude = read_osc.get_observed_magnitude(photometry_dict) fluxes.append(observed_magnitude.convert_to_flux()) except: pass - - distance = lum.Distance(3.0E7 * 3.086E18, 7.0E6 * 3.086E18) - self.lc_00cb = lightcurve.calculate_lightcurve(fluxes, distance, lqbol.calculate_qbol_flux) + + distance = lum.Distance(3.0e7 * 3.086e18, 7.0e6 * 3.086e18) + self.lc_00cb = lightcurve.calculate_lightcurve( + fluxes, distance, lqbol.calculate_qbol_flux + ) def test_qbol_lightcurve(self): print("") for luminosity in self.lc_00cb: - print("{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format(luminosity.time, luminosity.value, luminosity.uncertainty)) + print( + "{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format( + luminosity.time, luminosity.value, luminosity.uncertainty + ) + ) -class TestBolometricCorrectionLightcurve(unittest.TestCase): +class TestBolometricCorrectionLightcurve(unittest.TestCase): def setUp(self): with patch("builtins.open", mock_open(read_data=sn00cb_synphot_data)): - sn00cb_osc_photometry = read_osc.retrieve_osc_photometry('SN2000cb') + sn00cb_osc_photometry = read_osc.retrieve_osc_photometry("SN2000cb") observed_magnitudes = [] for photometry_dict in sn00cb_osc_photometry: + # TODO Why is there a try catch here? try: magnitude = read_osc.get_observed_magnitude(photometry_dict) observed_magnitudes.append(magnitude) except: pass - distance = lum.Distance(3.0E7 * 3.086E18, 7.0E6 * 3.086E18) - self.lc_00cb_bh09 = lightcurve.calculate_bc_lightcurve(observed_magnitudes, distance, lbc.calculate_bc_flux_bh09) - self.lc_00cb_h01 = lightcurve.calculate_bc_lightcurve(observed_magnitudes, distance, lbc.calculate_bc_flux_h01) + distance = lum.Distance(3.0e7 * 3.086e18, 7.0e6 * 3.086e18) + self.lc_00cb_bh09 = lightcurve.calculate_bc_lightcurve( + observed_magnitudes, distance, lbc.calculate_bc_flux_bh09 + ) + self.lc_00cb_h01 = lightcurve.calculate_bc_lightcurve( + observed_magnitudes, distance, lbc.calculate_bc_flux_h01 + ) def test_no_negatives_in_bh09_lightcurve(self): print("") for luminosity in self.lc_00cb_bh09: - print("{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format(luminosity.time, luminosity.value, luminosity.uncertainty)) + print( + "{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format( + luminosity.time, luminosity.value, luminosity.uncertainty + ) + ) self.assertTrue([luminosity.value > 0.0 for luminosity in self.lc_00cb_bh09]) def test_no_negatives_in_h01_lightcurve(self): print("") for luminosity in self.lc_00cb_h01: - print("{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format(luminosity.time, luminosity.value, luminosity.uncertainty)) + print( + "{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format( + luminosity.time, luminosity.value, luminosity.uncertainty + ) + ) self.assertTrue([luminosity.value > 0.0 for luminosity in self.lc_00cb_h01]) diff --git a/tests/unit/test_read_sne.py b/tests/unit/test_read_sne.py new file mode 100644 index 0000000..44a38eb --- /dev/null +++ b/tests/unit/test_read_sne.py @@ -0,0 +1,33 @@ +import json +import os +import unittest +import numpy as np +from .context import superbol +import requests +from superbol import read_sne +from httmock import urlmatch, all_requests, HTTMock, response + +SUPERNOVA_NAME = 'SN2000cb' +DIRNAME = os.path.dirname(__file__) +SUPERNOVA_FILE_PATH = os.path.join( + DIRNAME, f'../../data/{SUPERNOVA_NAME}.json') + + +@all_requests +def google_mock(url, request): + with open(SUPERNOVA_FILE_PATH, 'r') as f: + content = json.load(f) + return response(200, content, None, None, 5, request) + +class TestReadSne(unittest.TestCase): + def test_get_photometry(self): + with open(SUPERNOVA_FILE_PATH) as f, HTTMock(google_mock): + req_array = np.array(read_sne.get_supernova_photometry(SUPERNOVA_NAME)) + file_array = np.array(json.load(f)[SUPERNOVA_NAME]['photometry']) + assert np.array_equal(req_array, file_array) + + def test_get_distance(self): + with open(SUPERNOVA_FILE_PATH) as f, HTTMock(google_mock): + req_array = np.array(read_sne.get_supernova_lum_dist(SUPERNOVA_NAME)) + file_array = np.array(json.load(f)[SUPERNOVA_NAME]['lumdist']) + assert np.array_equal(req_array, file_array) diff --git a/tests/unit/test_sed.py b/tests/unit/test_sed.py index e42b044..67c4847 100644 --- a/tests/unit/test_sed.py +++ b/tests/unit/test_sed.py @@ -6,33 +6,28 @@ from superbol import sed from superbol import mag2flux -class TestGroupFluxes(unittest.TestCase): +class TestGroupFluxes(unittest.TestCase): def setUp(self): - self.flux10 = mag2flux.MonochromaticFlux(flux = 0, - flux_uncertainty = 0, - wavelength = 0, - time = 1) - - self.flux11 = mag2flux.MonochromaticFlux(flux = 0, - flux_uncertainty = 0, - wavelength= 0, - time = 1.1) - - self.flux12 = mag2flux.MonochromaticFlux(flux = 0, - flux_uncertainty = 0, - wavelength= 0, - time = 1.3) - - self.flux21 = mag2flux.MonochromaticFlux(flux = 0, - flux_uncertainty = 0, - wavelength= 0, - time = 2.1) - - self.flux27 = mag2flux.MonochromaticFlux(flux = 0, - flux_uncertainty = 0, - wavelength= 0, - time = 2.7) + self.flux10 = mag2flux.MonochromaticFlux( + flux=0, flux_uncertainty=0, wavelength=0, time=1 + ) + + self.flux11 = mag2flux.MonochromaticFlux( + flux=0, flux_uncertainty=0, wavelength=0, time=1.1 + ) + + self.flux12 = mag2flux.MonochromaticFlux( + flux=0, flux_uncertainty=0, wavelength=0, time=1.3 + ) + + self.flux21 = mag2flux.MonochromaticFlux( + flux=0, flux_uncertainty=0, wavelength=0, time=2.1 + ) + + self.flux27 = mag2flux.MonochromaticFlux( + flux=0, flux_uncertainty=0, wavelength=0, time=2.7 + ) def test_group_fluxes_floor_same_day(self): fluxes = [self.flux10, self.flux11, self.flux12] @@ -42,57 +37,48 @@ def test_group_fluxes_floor_same_day(self): def test_group_fluxes_floor_different_days(self): fluxes = [self.flux10, self.flux11, self.flux12, self.flux21, self.flux27] - expected = [[self.flux10, self.flux11, self.flux12], - [self.flux21, self.flux27]] + expected = [[self.flux10, self.flux11, self.flux12], [self.flux21, self.flux27]] result = sed.group_fluxes(fluxes) self.assertEqual(expected, result) -class TestCombineFluxes(unittest.TestCase): +class TestCombineFluxes(unittest.TestCase): def setUp(self): - self.flux1 = mag2flux.MonochromaticFlux(flux = 100, - flux_uncertainty = 10, - wavelength = 1, - time = 0) - self.flux2 = mag2flux.MonochromaticFlux(flux = 200, - flux_uncertainty = 10, - wavelength= 1, - time = 0) - self.flux3 = mag2flux.MonochromaticFlux(flux = 150, - flux_uncertainty = 8, - wavelength= 2, - time = 0) - self.flux4 = mag2flux.MonochromaticFlux(flux = 50, - flux_uncertainty = 8, - wavelength= 3, - time = 0) - self.flux5 = mag2flux.MonochromaticFlux(flux = 60, - flux_uncertainty = 8, - wavelength= 3, - time = 0) + self.flux1 = mag2flux.MonochromaticFlux( + flux=100, flux_uncertainty=10, wavelength=1, time=0 + ) + self.flux2 = mag2flux.MonochromaticFlux( + flux=200, flux_uncertainty=10, wavelength=1, time=0 + ) + self.flux3 = mag2flux.MonochromaticFlux( + flux=150, flux_uncertainty=8, wavelength=2, time=0 + ) + self.flux4 = mag2flux.MonochromaticFlux( + flux=50, flux_uncertainty=8, wavelength=3, time=0 + ) + self.flux5 = mag2flux.MonochromaticFlux( + flux=60, flux_uncertainty=8, wavelength=3, time=0 + ) self.fluxes = [self.flux1, self.flux2, self.flux3, self.flux4, self.flux5] self.repeated_fluxes1 = [self.flux1, self.flux2] self.repeated_fluxes3 = [self.flux4, self.flux5] def test_combine_fluxes_equal_uncertainties(self): result = sed.combine_fluxes(self.repeated_fluxes1) - expected = mag2flux.MonochromaticFlux(flux = 150, - flux_uncertainty = np.sqrt(200)/2., - wavelength = 1, - time = 0) + expected = mag2flux.MonochromaticFlux( + flux=150, flux_uncertainty=np.sqrt(200) / 2.0, wavelength=1, time=0 + ) self.assertEqual(expected, result) def test_combine_fluxes_unequal_uncertainties(self): fluxes = [self.flux1, self.flux3] result = sed.combine_fluxes(fluxes) - expected = mag2flux.MonochromaticFlux(flux = 130.488, - flux_uncertainty = 6.247, - wavelength = 1, - time = 0) + expected = mag2flux.MonochromaticFlux( + flux=130.488, flux_uncertainty=6.247, wavelength=1, time=0 + ) self.assertAlmostEqual(expected.flux, result.flux, 3) self.assertAlmostEqual(expected.flux_uncertainty, result.flux_uncertainty, 3) - def test_yield_fluxes_at_each_observed_wavelength(self): result_generator = sed.yield_fluxes_at_each_observed_wavelength(self.fluxes) expected1 = self.repeated_fluxes1 @@ -105,13 +91,18 @@ def test_yield_fluxes_at_each_observed_wavelength(self): def test_get_SED(self): result = sed.get_SED(self.fluxes) - expected = [mag2flux.MonochromaticFlux(150, np.sqrt(200)/2., 1, 0), self.flux3, - mag2flux.MonochromaticFlux(55.0, np.sqrt(128)/2., 3, 0)] + expected = [ + mag2flux.MonochromaticFlux(150, np.sqrt(200) / 2.0, 1, 0), + self.flux3, + mag2flux.MonochromaticFlux(55.0, np.sqrt(128) / 2.0, 3, 0), + ] # Ugly for i, flux in enumerate(result): self.assertAlmostEqual(result[i].flux, expected[i].flux) - self.assertAlmostEqual(result[i].flux_uncertainty, expected[i].flux_uncertainty) + self.assertAlmostEqual( + result[i].flux_uncertainty, expected[i].flux_uncertainty + ) def test_weighted_average(self): expected = 10.4 @@ -135,8 +126,8 @@ def test_get_weights_zero_uncertainty(self): uncertainties = [0.5, 1.0, 0.0] sed.get_weights(uncertainties) -class TestInterpolateSED(unittest.TestCase): +class TestInterpolateSED(unittest.TestCase): def setUp(self): self.flux01 = mag2flux.MonochromaticFlux(100, 2, 1, 0) self.flux02 = mag2flux.MonochromaticFlux(200, 2, 2, 0) @@ -157,9 +148,13 @@ def test_simple_interpolation(self): sed.interpolate_missing_fluxes([self.SED0, self.SED1, self.SED2]) previous_flux = self.flux02 next_flux = self.flux22 - weight1 = (2-1)/(2-0) - weight2 = (1-0)/(2-0) - uncertainty = math.sqrt(weight1**2 * previous_flux.flux_uncertainty**2 + weight2**2 + next_flux.flux_uncertainty**2) + weight1 = (2 - 1) / (2 - 0) + weight2 = (1 - 0) / (2 - 0) + uncertainty = math.sqrt( + weight1**2 * previous_flux.flux_uncertainty**2 + + weight2**2 + + next_flux.flux_uncertainty**2 + ) interpolated_flux = mag2flux.MonochromaticFlux(200, uncertainty, 2, 1) self.assertTrue(interpolated_flux in self.SED1) @@ -167,10 +162,14 @@ def test_get_interpolated_fluxes(self): lightcurve = [self.flux02, self.flux22, self.flux32] previous_flux = self.flux02 next_flux = self.flux22 - weight1 = (2-1)/(2-0) - weight2 = (1-0)/(2-0) - uncertainty = math.sqrt(weight1**2 * previous_flux.flux_uncertainty**2 + weight2**2 + next_flux.flux_uncertainty**2) - expected = [mag2flux.MonochromaticFlux(200.0, uncertainty , 2, 1)] + weight1 = (2 - 1) / (2 - 0) + weight2 = (1 - 0) / (2 - 0) + uncertainty = math.sqrt( + weight1**2 * previous_flux.flux_uncertainty**2 + + weight2**2 + + next_flux.flux_uncertainty**2 + ) + expected = [mag2flux.MonochromaticFlux(200.0, uncertainty, 2, 1)] result = sed.get_interpolated_fluxes(lightcurve, [1]) self.assertEqual(expected, result) @@ -192,13 +191,14 @@ def test_get_next_flux(self): next_flux = sed.get_next_flux(monochromatic_lc, unobserved_time) self.assertEqual(self.flux22, next_flux) - def test_get_gap_size(self): + # TODO Test not running bc it has the same name as the one above + def test_get_gap_size_1(self): times = [0, 1, 3, 6] unobserved_time = 2 max_delta = sed.get_gap_size(times, unobserved_time) self.assertEqual(2, max_delta) - def test_get_gap_size(self): + def test_get_gap_size_2(self): times = [0, 1, 3, 6] unobserved_time = 4 max_delta = sed.get_gap_size(times, unobserved_time) @@ -219,18 +219,26 @@ def test_get_interpolated_flux_uncertainty(self): previous_flux = self.flux02 next_flux = self.flux22 unobserved_time = 1 - weight1 = (2-1)/(2-0) - weight2 = (1-0)/(2-0) - expected = math.sqrt(weight1**2 * previous_flux.flux_uncertainty**2 + weight2**2 + next_flux.flux_uncertainty**2) - result = sed.get_interpolated_flux_uncertainty(previous_flux, next_flux, unobserved_time) + weight1 = (2 - 1) / (2 - 0) + weight2 = (1 - 0) / (2 - 0) + expected = math.sqrt( + weight1**2 * previous_flux.flux_uncertainty**2 + + weight2**2 + + next_flux.flux_uncertainty**2 + ) + result = sed.get_interpolated_flux_uncertainty( + previous_flux, next_flux, unobserved_time + ) self.assertEqual(expected, result) def test_get_unobserved_times(self): lightcurve = [self.flux02, self.flux22, self.flux32] - observed_times = sed.get_observed_times([self.SED0, self.SED1, self.SED2, self.SED3]) + observed_times = sed.get_observed_times( + [self.SED0, self.SED1, self.SED2, self.SED3] + ) unobserved_times = sed.get_unobserved_times(lightcurve, observed_times) self.assertEqual([1], unobserved_times) - + def test_get_observed_wavelengths(self): expected = [1, 2, 3] result = sed.get_observed_wavelengths([self.SED0, self.SED1, self.SED2]) @@ -245,4 +253,3 @@ def test_get_monochromatic_lightcurve(self): expected = [self.flux01, self.flux11, self.flux21] result = sed.get_monochromatic_lightcurve([self.SED0, self.SED1, self.SED2], 1) self.assertEqual(expected, result) - diff --git a/tests/unit/test_space_sne_connection.py b/tests/unit/test_space_sne_connection.py deleted file mode 100644 index b0dc99f..0000000 --- a/tests/unit/test_space_sne_connection.py +++ /dev/null @@ -1,28 +0,0 @@ -import unittest -import requests - -from superbol import lightcurve, lqbol, lum, read_osc, read_sne - -class TestQuasiBolometricLightcurve(unittest.TestCase): - - def setUp(self): - - self.sn00cb_osc_photometry = read_sne.get_supernova_photometry('SN2000cb') - fluxes = [] - for photometry_dict in self.sn00cb_osc_photometry: - try: - observed_magnitude = read_osc.get_observed_magnitude( - photometry_dict) - fluxes.append(observed_magnitude.convert_to_flux()) - except: - pass - - distance = lum.Distance(3.0E7 * 3.086E18, 7.0E6 * 3.086E18) - self.lc_00cb = lightcurve.calculate_lightcurve( - fluxes, distance, lqbol.calculate_qbol_flux) - - def test_qbol_lightcurve(self): - print("") - for luminosity in self.lc_00cb: - print("{0:4.2E}, {1:4.2E} +/- {2:4.2E}".format(luminosity.time, - luminosity.value, luminosity.uncertainty))