From 5060258077f1ae81ef6581af7b0b29f604d020ea Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Mon, 27 Mar 2023 10:15:31 -0400 Subject: [PATCH 1/6] added phase dependence to prop. effects --- sncosmo/models.py | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/sncosmo/models.py b/sncosmo/models.py index 97647aed..a583612f 100644 --- a/sncosmo/models.py +++ b/sncosmo/models.py @@ -1546,25 +1546,29 @@ def _flux(self, time, wave): """Array flux function.""" a = 1. / (1. + self._parameters[0]) - phase = (time - self._parameters[1]) * a + obsphase = (time - self._parameters[1]) + restphase = obsphase * a restwave = wave * a # Note that below we multiply by the scale factor to conserve # bolometric luminosity. - f = a * self._source._flux(phase, restwave) + f = a * self._source._flux(restphase, restwave) # Pass the flux through the PropagationEffects. for effect, frame, zindex in zip(self._effects, self._effect_frames, self._effect_zindicies): if frame == 'obs': effect_wave = wave + effect_phase = obsphase elif frame == 'rest': effect_wave = restwave + effect_phase = restphase else: # frame == 'free' effect_a = 1. / (1. + self._parameters[zindex]) effect_wave = wave * effect_a + effect_phase = obsphase * effect_a - f = effect.propagate(effect_wave, f) + f = effect.propagate(effect_phase,effect_wave, f) return f @@ -1948,15 +1952,24 @@ def minwave(self): def maxwave(self): return self._maxwave + def minphase(self): + return self._minphase + + def maxphase(self): + return self._maxphase + @abc.abstractmethod - def propagate(self, wave, flux): + def propagate(self,phase, wave, flux): pass def _headsummary(self): summary = """\ class : {0} - wavelength range: [{1:.6g}, {2:.6g}] Angstroms"""\ - .format(self.__class__.__name__, self._minwave, self._maxwave) + wavelength range: [{1:.6g}, {2:.6g}] Angstroms + phase range : [{3:.2g}, {4:.2g}]"""\ + .format(self.__class__.__name__, + self._minwave, self._maxwave, + self._minphase,self._maxphase) return dedent(summary) @@ -1966,11 +1979,13 @@ class CCM89Dust(PropagationEffect): param_names_latex = ['E(B-V)', 'R_V'] _minwave = 1000. _maxwave = 33333.33 + _minphase = np.nan + _maxphase = np.nan def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self, wave, flux): + def propagate(self,phase, wave, flux): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.ccm89(wave, ebv * r_v, r_v), flux) @@ -1982,11 +1997,13 @@ class OD94Dust(PropagationEffect): param_names_latex = ['E(B-V)', 'R_V'] _minwave = 909.09 _maxwave = 33333.33 + _minphase = np.nan + _maxphase = np.nan def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self, wave, flux): + def propagate(self,phase, wave, flux): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.odonnell94(wave, ebv * r_v, r_v), @@ -1997,6 +2014,8 @@ class F99Dust(PropagationEffect): """Fitzpatrick (1999) extinction model dust with fixed R_V.""" _minwave = 909.09 _maxwave = 60000. + _minphase = np.nan + _maxphase = np.nan def __init__(self, r_v=3.1): self._param_names = ['ebv'] @@ -2005,7 +2024,7 @@ def __init__(self, r_v=3.1): self._r_v = r_v self._f = extinction.Fitzpatrick99(r_v=r_v) - def propagate(self, wave, flux): + def propagate(self,phase, wave, flux): """Propagate the flux.""" ebv = self._parameters[0] return extinction.apply(self._f(wave, ebv * self._r_v), flux) From 56eb784110318abe88ec37f635291333b611b546 Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Mon, 27 Mar 2023 10:22:48 -0400 Subject: [PATCH 2/6] pep8 --- sncosmo/models.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sncosmo/models.py b/sncosmo/models.py index a583612f..69fdacfe 100644 --- a/sncosmo/models.py +++ b/sncosmo/models.py @@ -1568,7 +1568,7 @@ def _flux(self, time, wave): effect_wave = wave * effect_a effect_phase = obsphase * effect_a - f = effect.propagate(effect_phase,effect_wave, f) + f = effect.propagate(effect_phase, effect_wave, f) return f @@ -1959,7 +1959,7 @@ def maxphase(self): return self._maxphase @abc.abstractmethod - def propagate(self,phase, wave, flux): + def propagate(self, phase, wave, flux): pass def _headsummary(self): @@ -1967,9 +1967,9 @@ def _headsummary(self): class : {0} wavelength range: [{1:.6g}, {2:.6g}] Angstroms phase range : [{3:.2g}, {4:.2g}]"""\ - .format(self.__class__.__name__, + .format(self.__class__.__name__, self._minwave, self._maxwave, - self._minphase,self._maxphase) + self._minphase, self._maxphase) return dedent(summary) @@ -1985,7 +1985,7 @@ class CCM89Dust(PropagationEffect): def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self,phase, wave, flux): + def propagate(self, phase, wave, flux): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.ccm89(wave, ebv * r_v, r_v), flux) @@ -2003,7 +2003,7 @@ class OD94Dust(PropagationEffect): def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self,phase, wave, flux): + def propagate(self, phase, wave, flux): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.odonnell94(wave, ebv * r_v, r_v), @@ -2024,7 +2024,7 @@ def __init__(self, r_v=3.1): self._r_v = r_v self._f = extinction.Fitzpatrick99(r_v=r_v) - def propagate(self,phase, wave, flux): + def propagate(self, phase, wave, flux): """Propagate the flux.""" ebv = self._parameters[0] return extinction.apply(self._f(wave, ebv * self._r_v), flux) From c207f5462dc10da73468667231148061f9ccab34 Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Tue, 18 Apr 2023 15:18:17 -0400 Subject: [PATCH 3/6] phase dependence is optional in prop effects --- sncosmo/models.py | 15 ++++----- sncosmo/tests/test_models.py | 59 ++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/sncosmo/models.py b/sncosmo/models.py index 69fdacfe..1ad3bf8d 100644 --- a/sncosmo/models.py +++ b/sncosmo/models.py @@ -1567,9 +1567,10 @@ def _flux(self, time, wave): effect_a = 1. / (1. + self._parameters[zindex]) effect_wave = wave * effect_a effect_phase = obsphase * effect_a - - f = effect.propagate(effect_phase, effect_wave, f) - + try: + f = effect.propagate(effect_wave, f, phase=effect_phase) + except: + f = effect.propagate(effect_wave, f) return f def flux(self, time, wave): @@ -1959,7 +1960,7 @@ def maxphase(self): return self._maxphase @abc.abstractmethod - def propagate(self, phase, wave, flux): + def propagate(self, wave, flux, phase=None): pass def _headsummary(self): @@ -1985,7 +1986,7 @@ class CCM89Dust(PropagationEffect): def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self, phase, wave, flux): + def propagate(self, wave, flux, phase=None): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.ccm89(wave, ebv * r_v, r_v), flux) @@ -2003,7 +2004,7 @@ class OD94Dust(PropagationEffect): def __init__(self): self._parameters = np.array([0., 3.1]) - def propagate(self, phase, wave, flux): + def propagate(self, wave, flux, phase=None): """Propagate the flux.""" ebv, r_v = self._parameters return extinction.apply(extinction.odonnell94(wave, ebv * r_v, r_v), @@ -2024,7 +2025,7 @@ def __init__(self, r_v=3.1): self._r_v = r_v self._f = extinction.Fitzpatrick99(r_v=r_v) - def propagate(self, phase, wave, flux): + def propagate(self, wave, flux, phase=None): """Propagate the flux.""" ebv = self._parameters[0] return extinction.apply(self._f(wave, ebv * self._r_v), flux) diff --git a/sncosmo/tests/test_models.py b/sncosmo/tests/test_models.py index f6f037aa..d21717ad 100644 --- a/sncosmo/tests/test_models.py +++ b/sncosmo/tests/test_models.py @@ -2,6 +2,8 @@ from io import StringIO +import scipy + import numpy as np from numpy.testing import assert_allclose, assert_approx_equal @@ -18,9 +20,48 @@ def flatsource(): return sncosmo.TimeSeriesSource(phase, wave, flux) +class AchromaticMicrolensing(sncosmo.PropagationEffect): + """ + An achromatic microlensing object. Tests phase dependence. + """ + _param_names = [] + param_names_latex = [] + _minwave = np.nan + _maxwave = np.nan + _minphase = np.nan + _maxphase = np.nan + + def __init__(self, time, magnification): + """ + Parameters + ---------- + time: :class:`~list` or :class:`~numpy.array` + A time array for your microlensing + dmag: :class:`~list` or :class:`~numpy.array` + microlensing magnification + """ + self._parameters = np.array([]) + self.mu = scipy.interpolate.interp1d(time, + magnification, + bounds_error=False, + fill_value=1.) + self._minphase = np.min(time) + self._maxphase = np.max(time) + + def propagate(self, wave, flux, phase): + """ + Propagate the magnification onto the model's flux output. + """ + + mu = np.expand_dims(np.atleast_1d(self.mu(phase)), 1) + return flux * mu + + class StepEffect(sncosmo.PropagationEffect): - """Effect with transmission 0 below cutoff wavelength, 1 above. - Useful for testing behavior with redshift.""" + """ + Effect with transmission 0 below cutoff wavelength, 1 above. + Useful for testing behavior with redshift. + """ _param_names = ['stepwave'] param_names_latex = [r'\lambda_{s}'] @@ -312,3 +353,17 @@ def test_effect_frame_free(): wave = np.array([12000., 13000., 14000., 14999., 15000., 16000.]) assert_allclose(model.flux(0., wave), [0., 0., 0., 0., 0.5, 0.5]) + + +def test_effect_phase_dependent(): + """Test Model with PropagationEffect with phase dependence""" + + model = sncosmo.Model(source=flatsource()) + flux = model.flux(50., 5000.).flatten() + + model_micro = sncosmo.Model(source=flatsource(), + effects=[AchromaticMicrolensing([40., 60.], + [10., 10.])], + effect_frames=['rest'], + effect_names=['micro']) + assert_approx_equal(model_micro.flux(50., 5000.).flatten(), flux*10.) From fe38e15e80a24cd2b1d459040a998d6e9b9928a7 Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Wed, 19 Apr 2023 12:45:09 -0400 Subject: [PATCH 4/6] changed min/max phase parameter in prop effects --- sncosmo/models.py | 20 ++++++++++---------- sncosmo/tests/test_models.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sncosmo/models.py b/sncosmo/models.py index 1ad3bf8d..57bb93fa 100644 --- a/sncosmo/models.py +++ b/sncosmo/models.py @@ -1569,7 +1569,7 @@ def _flux(self, time, wave): effect_phase = obsphase * effect_a try: f = effect.propagate(effect_wave, f, phase=effect_phase) - except: + except TypeError: f = effect.propagate(effect_wave, f) return f @@ -1954,10 +1954,16 @@ def maxwave(self): return self._maxwave def minphase(self): - return self._minphase + try: + return self._minphase + except AttributeError: + return np.nan def maxphase(self): - return self._maxphase + try: + return self._minphase + except AttributeError: + return np.nan @abc.abstractmethod def propagate(self, wave, flux, phase=None): @@ -1970,7 +1976,7 @@ class : {0} phase range : [{3:.2g}, {4:.2g}]"""\ .format(self.__class__.__name__, self._minwave, self._maxwave, - self._minphase, self._maxphase) + self.minphase(), self.maxphase()) return dedent(summary) @@ -1980,8 +1986,6 @@ class CCM89Dust(PropagationEffect): param_names_latex = ['E(B-V)', 'R_V'] _minwave = 1000. _maxwave = 33333.33 - _minphase = np.nan - _maxphase = np.nan def __init__(self): self._parameters = np.array([0., 3.1]) @@ -1998,8 +2002,6 @@ class OD94Dust(PropagationEffect): param_names_latex = ['E(B-V)', 'R_V'] _minwave = 909.09 _maxwave = 33333.33 - _minphase = np.nan - _maxphase = np.nan def __init__(self): self._parameters = np.array([0., 3.1]) @@ -2015,8 +2017,6 @@ class F99Dust(PropagationEffect): """Fitzpatrick (1999) extinction model dust with fixed R_V.""" _minwave = 909.09 _maxwave = 60000. - _minphase = np.nan - _maxphase = np.nan def __init__(self, r_v=3.1): self._param_names = ['ebv'] diff --git a/sncosmo/tests/test_models.py b/sncosmo/tests/test_models.py index d21717ad..c6554b61 100644 --- a/sncosmo/tests/test_models.py +++ b/sncosmo/tests/test_models.py @@ -366,4 +366,4 @@ def test_effect_phase_dependent(): [10., 10.])], effect_frames=['rest'], effect_names=['micro']) - assert_approx_equal(model_micro.flux(50., 5000.).flatten(), flux*10.) + assert_approx_equal(model_micro.flux(50., 5000.).flatten(), flux*10.) \ No newline at end of file From 6389948e68e881a4b460df9142268bfb0ce67344 Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Wed, 19 Apr 2023 12:46:43 -0400 Subject: [PATCH 5/6] code style --- sncosmo/tests/test_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sncosmo/tests/test_models.py b/sncosmo/tests/test_models.py index c6554b61..d21717ad 100644 --- a/sncosmo/tests/test_models.py +++ b/sncosmo/tests/test_models.py @@ -366,4 +366,4 @@ def test_effect_phase_dependent(): [10., 10.])], effect_frames=['rest'], effect_names=['micro']) - assert_approx_equal(model_micro.flux(50., 5000.).flatten(), flux*10.) \ No newline at end of file + assert_approx_equal(model_micro.flux(50., 5000.).flatten(), flux*10.) From f545b1b71d1583d258262e80efddc27de46a7433 Mon Sep 17 00:00:00 2001 From: Justin Pierel Date: Wed, 19 Apr 2023 16:47:19 -0400 Subject: [PATCH 6/6] minor bug --- sncosmo/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sncosmo/models.py b/sncosmo/models.py index 57bb93fa..10cd4e62 100644 --- a/sncosmo/models.py +++ b/sncosmo/models.py @@ -1961,7 +1961,7 @@ def minphase(self): def maxphase(self): try: - return self._minphase + return self._maxphase except AttributeError: return np.nan