diff --git a/changelog/291.feature.rst b/changelog/291.feature.rst new file mode 100644 index 00000000..06932b28 --- /dev/null +++ b/changelog/291.feature.rst @@ -0,0 +1 @@ +The scalar parameters for ``ThermalEmission``, ``ThickTarget``, and ``ThinTarget`` in ``models.physical`` now use consistent custom scaled values and units instead of scaled values with non-scaled units. Parameters for the ``ThermalEmission`` and ``ThickTarget`` are given suitable parameter bounds. diff --git a/sunkit_spex/models/physical/albedo.py b/sunkit_spex/models/physical/albedo.py index 8fa6e758..87ded2f8 100644 --- a/sunkit_spex/models/physical/albedo.py +++ b/sunkit_spex/models/physical/albedo.py @@ -94,8 +94,8 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def evaluate(self, spectrum, theta, anisotropy): - if not isinstance(theta, Quantity): - theta = theta * u.deg + + theta <<= u.deg albedo_matrix = get_albedo_matrix(self.energy_edges, theta, anisotropy) diff --git a/sunkit_spex/models/physical/nonthermal.py b/sunkit_spex/models/physical/nonthermal.py index 1e95e29a..94234fe8 100644 --- a/sunkit_spex/models/physical/nonthermal.py +++ b/sunkit_spex/models/physical/nonthermal.py @@ -4,9 +4,11 @@ import astropy.units as u from astropy.modeling import FittableModel, Parameter +from astropy.modeling.functional_models import FLOAT_EPSILON from sunkit_spex.legacy import constants as const from sunkit_spex.legacy.integrate import gauss_legendre +from sunkit_spex.models.scaling import scaled_thick_eflux_units, scaled_thin_eflux_units const = const.Constants() @@ -29,6 +31,8 @@ __all__ = ["ThickTarget", "ThinTarget"] +FLOAT_EPSILON_FOR_POWER_LAW = 1 + FLOAT_EPSILON * 1e30 + class ThickTarget(FittableModel): r"""Calculates the thick-target bremsstrahlung radiation of a dual power-law electron distribution. @@ -73,22 +77,48 @@ class ThickTarget(FittableModel): n_inputs = 1 n_outputs = 1 - p = Parameter(name="p", default=2, description="Slope below break", fixed=False) + p = Parameter( + name="p", default=2, description="Slope below break", fixed=False, bounds=(FLOAT_EPSILON_FOR_POWER_LAW, None) + ) - break_energy = Parameter(name="break_energy", default=100, unit=u.keV, description="Break Energy", fixed=False) + break_energy = Parameter( + name="break_energy", + default=100, + unit=u.keV, + description="Break Energy", + fixed=True, + bounds=(FLOAT_EPSILON, None), + ) - q = Parameter(name="q", default=5, min=0.01, description="Slope above break", fixed=True) + q = Parameter( + name="q", default=5, description="Slope above break", fixed=True, bounds=(FLOAT_EPSILON_FOR_POWER_LAW, None) + ) low_e_cutoff = Parameter( - name="low_e_cutoff", default=7, unit=u.keV, description="Low energy electron cut off", fixed=False + name="low_e_cutoff", + default=7, + unit=u.keV, + description="Low energy electron cut off", + fixed=False, + bounds=(FLOAT_EPSILON, None), ) high_e_cutoff = Parameter( - name="high_e_cutoff", default=1500, unit=u.keV, description="High energy electron cut off", fixed=True + name="high_e_cutoff", + default=1500, + unit=u.keV, + description="High energy electron cut off", + fixed=True, + bounds=(FLOAT_EPSILON, None), ) total_eflux = Parameter( - name="total_eflux", default=1.5, unit=u.electron * u.s**-1, description="Total electron flux", fixed=True + name="total_eflux", + default=1.5, + unit=scaled_thick_eflux_units, + description="Total electron flux", + fixed=False, + bounds=(0, None), ) _input_units_allow_dimensionless = True @@ -106,6 +136,8 @@ def __init__( ): self.integrator = integrator + total_eflux <<= scaled_thick_eflux_units + super().__init__( p=p, break_energy=break_energy, @@ -119,29 +151,26 @@ def __init__( def evaluate(self, energy_edges, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux): energy_centers = energy_edges[:-1] + 0.5 * np.diff(energy_edges) - if ( - hasattr(break_energy, "unit") - or hasattr(energy_centers, "unit") - or hasattr(low_e_cutoff, "unit") - or hasattr(high_e_cutoff, "unit") - or hasattr(total_eflux, "unit") - ): - flux = thick_fn( + energy_centers <<= u.keV + break_energy <<= self.break_energy.unit + low_e_cutoff <<= self.low_e_cutoff.unit + high_e_cutoff <<= self.high_e_cutoff.unit + total_eflux <<= scaled_thick_eflux_units + + flux = ( + bremsstrahlung_thick_target( energy_centers.value, p, break_energy.value, q, low_e_cutoff.value, high_e_cutoff.value, - total_eflux.value, self.integrator, ) - else: - flux = thick_fn( - energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux, self.integrator - ) + * total_eflux.decompose().value + ) - return flux + return flux * self.return_units[self.outputs[0]] @property def input_units(self): @@ -157,7 +186,7 @@ def _parameter_units_for_data_units(self, inputs_unit, outputs_unit): "break_energy": u.keV, "low_e_cutoff": u.keV, "high_e_cutoff": u.keV, - "total_eflux": u.electron * u.s**-1, + "total_eflux": scaled_thick_eflux_units, } @@ -225,7 +254,11 @@ class ThinTarget(FittableModel): ) total_eflux = Parameter( - name="total_eflux", default=1.5, unit=u.s**-1 * u.cm**-2, description="Total electron flux", fixed=True + name="total_eflux", + default=1.5, + unit=scaled_thin_eflux_units, + description="Total electron flux", + fixed=True, ) _input_units_allow_dimensionless = True @@ -243,6 +276,8 @@ def __init__( ): self.integrator = integrator + total_eflux <<= scaled_thin_eflux_units + super().__init__( p=p, break_energy=break_energy, @@ -256,29 +291,26 @@ def __init__( def evaluate(self, energy_edges, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux): energy_centers = energy_edges[:-1] + 0.5 * np.diff(energy_edges) - if ( - hasattr(break_energy, "unit") - or hasattr(energy_centers, "unit") - or hasattr(low_e_cutoff, "unit") - or hasattr(high_e_cutoff, "unit") - or hasattr(total_eflux, "unit") - ): - flux = thin_fn( + energy_centers <<= u.keV + break_energy <<= self.break_energy.unit + low_e_cutoff <<= self.low_e_cutoff.unit + high_e_cutoff <<= self.high_e_cutoff.unit + total_eflux <<= scaled_thin_eflux_units + + flux = ( + bremsstrahlung_thin_target( energy_centers.value, p, break_energy.value, q, low_e_cutoff.value, high_e_cutoff.value, - total_eflux.value, - self.integrator, - ) - else: - flux = thin_fn( - energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux, self.integrator + integrator=self.integrator, ) + * total_eflux.to(u.electron * u.cm ** (-2) * u.s**-1).value + ) - return flux + return flux * self.return_units[self.outputs[0]] @property def input_units(self): @@ -294,132 +326,11 @@ def _parameter_units_for_data_units(self, inputs_unit, outputs_unit): "break_energy": u.keV, "low_e_cutoff": u.keV, "high_e_cutoff": u.keV, - "total_eflux": u.s**-1 * u.cm**-2, + "total_eflux": scaled_thin_eflux_units, # "total_eflux": u.electron * u.s**-1, } -def thick_fn(energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux, integrator): - """Calculates the thick-target bremsstrahlung radiation of a dual power-law electron distribution. - - [1] Brown, Solar Physics 18, 489 (1971) (https://link.springer.com/article/10.1007/BF00149070) - [2] https://hesperia.gsfc.nasa.gov/ssw/packages/xray/doc/brm_thick_doc.pdf - [3] https://hesperia.gsfc.nasa.gov/ssw/packages/xray/idl/brm2/brm2_thicktarget.pro - - Parameters - ---------- - - energy_edges : 1d array - Edges of energy bins in units of keV. - - total_eflux : int or float - Total integrated electron flux, in units of 10^35 e^- s^-1. - Need to take care here as the model returns units of cm-2 sec-1 as the scaling factor of 1e35 is hidden. - So actual units are 1.0d35 e^- s^-1. - - p : int or float - Power-law index of the electron distribution below the break. - - break_energy : int or float - Break energy of power law. - - q : int or float - Power-law index of the electron distribution above the break. - - low_e_cutoff : int or float - Low-energy cut-off of the electron distribution in units of keV. - - high_e_cutoff : int or float - High-energy cut-off of the electron distribution in units of keV. - - - Returns - ------- - A 1d array of thick-target bremsstrahlung radiation in units - of ph s^-1 keV^-1. - """ - - # hack = np.round([p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux], 15) - # p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux = hack[0], hack[1], hack[2], hack[3], hack[4], hack[5] - - # energies = np.mean(energies, axis=1) # since energy bins are given, use midpoints though - - # we want a single power law electron distribution, - # so set break_energy == high_e_cutoff at a high value. - # we don't care about q at E > break_energy. - # high_break = energies.max() * 10 - - output = bremsstrahlung_thick_target(energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, integrator) - - output[np.isnan(output)] = 0 - output[~np.isfinite(output)] = 0 - - # convert to 1e35 e-/s - return output * total_eflux * 1e35 - - -# def thin_fn(total_eflux, index, e_c, energies=None): -def thin_fn(energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux, integrator): - """Calculates the thin-target bremsstrahlung radiation of a dual power-law electron distribution. - - [1] Brown, Solar Physics 18, 489 (1971) (https://link.springer.com/article/10.1007/BF00149070) - [2] https://hesperia.gsfc.nasa.gov/ssw/packages/xray/doc/brm_thick_doc.pdf - [3] https://hesperia.gsfc.nasa.gov/ssw/packages/xray/idl/brm2/brm2_thicktarget.pro - - Parameters - ---------- - energy_edges : 1d array - Edges of energy bins in units of keV. - - total_eflux : int or float - normalization factor in units of 1.0d55 cm-2 sec-1, - i.e. plasma density * volume of source * integrated nonthermal electron flux density - Need to take care here as the model returns units of cm-2 sec-1 as the scaling factor of 1e55 is hidden. - So actual units are 1.0d55 cm-2 sec-1. - - p : int or float - Power-law index of the electron distribution below the break. - - break_energy : int or float - Break energy of power law. - - q : int or float - Power-law index of the electron distribution above the break. - - low_e_cutoff : int or float - Low-energy cut-off of the electron distribution in units of keV. - - high_e_cutoff : int or float - High-energy cut-off of the electron distribution in units of keV. - - - - Returns - ------- - A 1d array of thin-target bremsstrahlung radiation in units - of ph s^-1 keV^-1. - """ - - # hack = np.round([total_eflux, index, e_c], 15) - # total_eflux, index, e_c = hack[0], hack[1], hack[2] - - # energies = np.mean(energies, axis=1) # since energy bins are given, use midpoints though - # energies = energy_centers - # we want a single power law electron distribution, - # so set break_energy == high_e_cutoff at a high value. - # we don't care about q at E > break_energy. - # high_break = energies.max() * 10 - output = bremsstrahlung_thin_target( - energy_centers, p, break_energy, q, low_e_cutoff, high_e_cutoff, total_eflux, integrator - ) - - output[np.isnan(output)] = 0 - output[~np.isfinite(output)] = 0 - - # convert to 1e35 e-/s - return output * total_eflux * 1e55 - - class BrokenPowerLawElectronDistribution: """ A broken or double power law electron flux distribution and integral. diff --git a/sunkit_spex/models/physical/tests/test_nonthermal.py b/sunkit_spex/models/physical/tests/test_nonthermal.py index ac5419f8..01d65208 100644 --- a/sunkit_spex/models/physical/tests/test_nonthermal.py +++ b/sunkit_spex/models/physical/tests/test_nonthermal.py @@ -4,6 +4,7 @@ import astropy.units as u from sunkit_spex.models.physical import nonthermal +from sunkit_spex.models.scaling import scaled_thick_eflux_units, scaled_thin_eflux_units SSW_INTENSITY_UNIT = u.ph / u.cm**2 / u.s / u.keV @@ -144,3 +145,54 @@ def test_thin_target_against_ssw(ssw): output = model(energy_edges) expected_value = expected.to_value(output.unit) np.testing.assert_allclose(output.value, expected_value, rtol=0.035) + + +def test_thick_target_flux_scaling(): + """Test thick target flux units being scaled.""" + energy_edges = np.arange(2, 15, 0.1) << u.keV + for _flux in np.arange(1, 10, 0.5): + eflux = (_flux * 1e35) << (u.electron * u.s**-1) + s_eflux = _flux << scaled_thick_eflux_units + model = nonthermal.ThickTarget(total_eflux=eflux) + s_model = nonthermal.ThickTarget(total_eflux=s_eflux) + np.testing.assert_allclose(model(energy_edges).value, s_model(energy_edges).value) + np.testing.assert_allclose( + model.evaluate(energy_edges, *model.parameters).value, + s_model.evaluate(energy_edges, *s_model.parameters).value, + ) + + +def test_thin_target_flux_scaling(): + """Test thin target flux units being scaled.""" + energy_edges = np.arange(2, 15, 0.1) << u.keV + for _flux in np.arange(1, 10, 0.5): + eflux = (_flux * 1e55) << (u.electron * u.cm**-2 * u.s**-1) + s_eflux = _flux << scaled_thin_eflux_units + model = nonthermal.ThinTarget(total_eflux=eflux) + s_model = nonthermal.ThinTarget(total_eflux=s_eflux) + np.testing.assert_allclose(model(energy_edges).value, s_model(energy_edges).value) + np.testing.assert_allclose( + model.evaluate(energy_edges, *model.parameters).value, + s_model.evaluate(energy_edges, *s_model.parameters).value, + ) + + +def test_thick_target_parameter_check(): + """Test non-physical, erroneous values for parameters.""" + energy_edges = np.arange(2, 15, 0.1) << u.keV + model = nonthermal.ThickTarget() + + # produce a division by zero when calculating the internal n0 + p = 1 + with pytest.warns(RuntimeWarning): + model.evaluate(energy_edges, p, *model.parameters[1:]) + + # produce a division by zero when calculating the internal n0 + q = 1 + with pytest.warns(RuntimeWarning): + model.evaluate(energy_edges, *model.parameters[:2], q, *model.parameters[3:]) + + # produce a division by zero when calculating the internal n0 + ec = 0 + with pytest.warns(RuntimeWarning): + model.evaluate(energy_edges, *model.parameters[:3], ec, *model.parameters[4:]) diff --git a/sunkit_spex/models/physical/tests/test_thermal.py b/sunkit_spex/models/physical/tests/test_thermal.py index 89fb2c53..fe60728c 100644 --- a/sunkit_spex/models/physical/tests/test_thermal.py +++ b/sunkit_spex/models/physical/tests/test_thermal.py @@ -6,6 +6,7 @@ import astropy.units as u from sunkit_spex.models.physical import thermal +from sunkit_spex.models.scaling import scaled_em_units # Manually load file that was used to compile expected flux values. thermal.setup_continuum_parameters( @@ -50,7 +51,7 @@ def fvth_simple(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -111,7 +112,7 @@ def chianti_kev_cont_simple(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -172,7 +173,7 @@ def chianti_kev_lines_simple(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -234,7 +235,7 @@ def fvth_Fe2(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -297,7 +298,7 @@ def chianti_kev_cont_Fe2(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -360,7 +361,7 @@ def chianti_kev_lines_Fe2(): """ energy_edges = np.arange(3, 28.5, 0.5) * u.keV temperature = 6 * u.MK - emission_measure = 1e-5 / u.cm**3 + emission_measure = 1e44 / u.cm**3 abundance_type = DEFAULT_ABUNDANCE_TYPE observer_distance = (1 * u.AU).to(u.cm) # fmt: off @@ -513,3 +514,18 @@ def test_abundances_should_not_change(): after_models = thermal.DEFAULT_ABUNDANCES[thermal.DEFAULT_ABUNDANCE_TYPE].data assert np.allclose(after_models.data, orig.data) + + +def test_thermal_emission_measure_scaling(): + """Test thermal emission measure units being scaled.""" + energy_edges = np.arange(2, 15, 0.1) << u.keV + for _em in np.arange(1, 10, 0.5): + em = (_em * 1e49) << (u.cm**-3) + s_em = _em << scaled_em_units + model = thermal.ThermalEmission(emission_measure=em) + s_model = thermal.ThermalEmission(emission_measure=s_em) + np.testing.assert_allclose(model(energy_edges).value, s_model(energy_edges).value) + np.testing.assert_allclose( + model.evaluate(energy_edges, *model.parameters).value, + s_model.evaluate(energy_edges, *s_model.parameters).value, + ) diff --git a/sunkit_spex/models/physical/thermal.py b/sunkit_spex/models/physical/thermal.py index 73d09897..d54f9625 100644 --- a/sunkit_spex/models/physical/thermal.py +++ b/sunkit_spex/models/physical/thermal.py @@ -15,6 +15,7 @@ load_chianti_lines_lite, load_xray_abundances, ) +from sunkit_spex.models.scaling import scaled_em_units # The default elemental abundance values correspond to coronal values DEFAULT_ABUNDANCE_TYPE = "sun_coronal_ext" @@ -134,8 +135,6 @@ class ThermalEmission(FittableModel): temperature = Parameter( name="temperature", default=10, - min=1, - max=100, unit=u.MK, description="Temperature of the plasma", fixed=False, @@ -144,9 +143,10 @@ class ThermalEmission(FittableModel): emission_measure = Parameter( name="emission_measure", default=1, - unit=(u.cm ** (-3)), + unit=scaled_em_units, description="Emission measure of the observer", fixed=False, + bounds=(0, None), ) mg = Parameter(name="Mg", default=8.15, min=6.15, max=10.15, description="Mg relative abundance", fixed=True) @@ -185,6 +185,16 @@ def __init__( if abundance_type != DEFAULT_ABUNDANCE_TYPE: mg, al, si, s, ar, ca, fe = _initialize_abundances(DEFAULT_ABUNDANCES[abundance_type]) + emission_measure <<= scaled_em_units + self.temperature.bounds = ( + (np.min([CONTINUUM_GRID["temperature range K"][0], LINE_GRID["temperature range K"][0]]) << u.K).to( + temperature.unit + ), + (np.max([CONTINUUM_GRID["temperature range K"][1], LINE_GRID["temperature range K"][1]]) << u.K).to( + temperature.unit + ), + ) + self.line = LineEmission( temperature=temperature, emission_measure=emission_measure, @@ -237,6 +247,9 @@ def evaluate( ca, fe, ): + energy_edges <<= u.keV + temperature <<= self.temperature.unit + emission_measure <<= self.emission_measure.unit line_flux = self.line.evaluate( energy_edges, temperature, @@ -275,7 +288,7 @@ def return_units(self): return {self.outputs[0]: u.ph / u.keV * u.s**-1} def _parameter_units_for_data_units(self, inputs_unit, outputs_unit): - return {"temperature": u.MK, "emission_measure": (u.cm ** (-3))} + return {"temperature": u.MK, "emission_measure": scaled_em_units} class ContinuumEmission(FittableModel): @@ -329,7 +342,7 @@ class ContinuumEmission(FittableModel): emission_measure = Parameter( name="emission_measure", default=1, - unit=(u.cm ** (-3)), + unit=scaled_em_units, description="Emission measure of the observer", fixed=False, ) @@ -419,7 +432,7 @@ def return_units(self): return {self.outputs[0]: u.ph / u.keV * u.s**-1} def _parameter_units_for_data_units(self, inputs_unit, outputs_unit): - return {"temperature": u.MK, "emission_measure": (u.cm ** (-3))} + return {"temperature": u.MK, "emission_measure": scaled_em_units} class LineEmission(FittableModel): @@ -468,8 +481,8 @@ class LineEmission(FittableModel): emission_measure = Parameter( name="emission_measure", - default=1e50, - unit=(u.cm ** (-3)), + default=1, + unit=scaled_em_units, description="Emission measure of the observer", fixed=False, ) @@ -559,7 +572,7 @@ def return_units(self): return {self.outputs[0]: u.ph / u.keV * u.s**-1} def _parameter_units_for_data_units(self, inputs_unit, outputs_unit): - return {"temperature": u.MK, "emission_measure": (u.cm ** (-3))} + return {"temperature": u.MK, "emission_measure": scaled_em_units} def setup_continuum_parameters(filename=None): @@ -722,7 +735,7 @@ def continuum_emission( # Calculate flux. flux = _continuum_emission(energy_edges_keV, temperature_K, abundances) - flux *= emission_measure * 1e49 + flux *= emission_measure if temperature_K.isscalar and emission_measure.isscalar: flux = flux[0] @@ -767,7 +780,7 @@ def line_emission( flux = _line_emission(energy_edges_keV, temperature_K, abundances) - flux *= emission_measure * 1e49 + flux *= emission_measure if temperature_K.isscalar and emission_measure.isscalar: flux = flux[0] @@ -1223,7 +1236,7 @@ def _sanitize_inputs(energy_edges, temperature, emission_measure): # If they were not already Quantities, the parameters get the default units. energy_edges <<= u.keV temperature <<= u.K - emission_measure <<= u.cm**-3 + emission_measure <<= scaled_em_units energy_edges_keV = energy_edges.to(u.keV) diff --git a/sunkit_spex/models/scaling.py b/sunkit_spex/models/scaling.py index 549b92ff..e57ab61f 100644 --- a/sunkit_spex/models/scaling.py +++ b/sunkit_spex/models/scaling.py @@ -4,7 +4,21 @@ from astropy.modeling import FittableModel, Parameter from astropy.units import Quantity -__all__ = ["Constant", "InverseSquareFluxScaling"] +__all__ = [ + "Constant", + "InverseSquareFluxScaling", + "scaled_em_units", + "scaled_thick_eflux_units", + "scaled_thin_eflux_units", +] + + +scaled_thick_eflux_units = u.def_unit("scaled_thick_eflux_units", 1e35 * (u.electron * u.s**-1)) +scaled_thin_eflux_units = u.def_unit("scaled_thin_eflux_units", 1e55 * (u.electron * u.cm ** (-2) * u.s**-1)) +scaled_em_units = u.def_unit("scaled_em_units", 1e49 * (u.cm ** (-3))) +u.add_enabled_units( + [scaled_thick_eflux_units, scaled_thin_eflux_units, scaled_em_units] +) # lets astropy's methods find these units class InverseSquareFluxScaling(FittableModel): @@ -18,9 +32,6 @@ class InverseSquareFluxScaling(FittableModel): observer_distance: Distance of the observer from the source. - - - Examples ======== .. plot:: @@ -101,7 +112,6 @@ class Constant(FittableModel): constant : A constant value which populates the output array - Examples ======== .. plot::