def __setattr__(self, attr, value): # TODO: Support a means of specifying default values for coefficients # Check for self._ndim first--if it hasn't been defined then the # instance hasn't been initialized yet and self.param_names probably # won't work. # This has to vaguely duplicate the functionality of # Parameter.__set__. # TODO: I wonder if there might be a way around that though... if attr[0] != '_' and self.param_names and attr in self.param_names: param = Parameter(attr, default=0.0, model=self) # This is a little hackish, but we can actually reuse the # Parameter.__set__ method here param.__set__(self, value) else: super(BSplineModel, self).__setattr__(attr, value)
class LunarLambert(DiskFunctionModel): """Lunar-Lambert model, or McEwen model class""" inputs = ('i', 'e') outputs = ('d',) L = Parameter(default=0.1, description='Partition parameter') @staticmethod def evaluate(i, e, L): return (1-L) * LommelSeeliger.evaluate(i, e) + L * Lambert.evaluate(i)
class Lorimer2006(Fittable1DModel): """ Radial distribution of the suface density of pulsars in the galaxy - Lorimer 2006. .. math :: f(r) = A \\left( \\frac{r}{r_{\\odot}} \\right) ^ B \\exp \\left[ -C \\left( \\frac{r - r_{\\odot}}{r_{\\odot}} \\right) \\right] Reference: http://adsabs.harvard.edu/abs/2006MNRAS.372..777L (Formula (10)) Parameters ---------- amplitude : float See model formula B : float See model formula C : float See model formula See Also -------- CaseBattacharya1998, Paczynski1990, YusifovKucuk2004, Lorimer2006, YusifovKucuk2004B, FaucherKaspi2006 """ amplitude = Parameter() B = Parameter() C = Parameter() evolved = True def __init__(self, amplitude=1, B=1.9, C=5.0, **kwargs): super(Lorimer2006, self).__init__(amplitude=amplitude, B=B, C=C, **kwargs) @staticmethod def evaluate(r, amplitude, B, C): """One dimensional Lorimer 2006 model function""" term1 = (r / D_SUN_TO_GALACTIC_CENTER.value)**B term2 = np.exp(-C * (r - D_SUN_TO_GALACTIC_CENTER.value) / D_SUN_TO_GALACTIC_CENTER.value) return amplitude * term1 * term2
class Beta(Fittable1DModel): s0 = Parameter(default = 1e-2, min = 1e-12) beta = Parameter(default = 0.7, min = 1e-12) rc = Parameter(default = 0.1, min = 1e-12) const = Parameter(default = 1e-3, min=1e-12) @staticmethod def evaluate(x, s0, beta, rc, const): result = s0 * (1. + (x/rc)**2) ** (0.5 - 3*beta) + const return result @staticmethod def fit_deriv(x, s0, beta, rc, const): d_s0 = (1. + (x/rc)**2) ** (0.5 - 3*beta) d_beta = -3 * s0 * np.log(1. + (x/rc)**2) * \ (1. + (x/rc)**2) ** (0.5 - 3*beta) d_rc = -2 * s0 * x**2 * (0.5 - 3*beta) / rc**3 \ * (1. + (x/rc)**2) ** (-0.5 - 3*beta) return [d_s0, d_beta, d_rc, np.ones_like(x)]
class YusifovKucuk2004(Fittable1DModel): """Radial distribution of the surface density of pulsars in the galaxy - Yusifov & Kucuk 2004. .. math :: f(r) = A \\left ( \\frac{r + r_1}{r_{\\odot} + r_1} \\right )^a \\exp \\left [-b \\left( \\frac{r - r_{\\odot}}{r_{\\odot} + r_1} \\right ) \\right ] Used by Faucher-Guigere and Kaspi. Density at ``r = 0`` is nonzero. Reference: http://adsabs.harvard.edu/abs/2004A%26A...422..545Y (Formula (15)) Parameters ---------- amplitude : float See model formula a : float See model formula b : float See model formula r_1 : float See model formula See Also -------- CaseBattacharya1998, Paczynski1990, Lorimer2006, YusifovKucuk2004B, FaucherKaspi2006, Exponential """ amplitude = Parameter() a = Parameter() b = Parameter() r_1 = Parameter() evolved = True def __init__(self, amplitude=1, a=1.64, b=4.01, r_1=0.55, **kwargs): super(YusifovKucuk2004, self).__init__(amplitude=amplitude, a=a, b=b, r_1=r_1, **kwargs) @staticmethod def evaluate(r, amplitude, a, b, r_1): """One dimensional Yusifov & Kucuk 2004 model function""" term1 = ((r + r_1) / (D_SUN_TO_GALACTIC_CENTER.value + r_1)) ** a term2 = np.exp(-b * (r - D_SUN_TO_GALACTIC_CENTER.value) / (D_SUN_TO_GALACTIC_CENTER.value + r_1)) return amplitude * term1 * term2
class CaseBattacharya1998(Fittable1DModel): """Radial distribution of the surface density of supernova remnants in the galaxy - Case & Battacharya 1998. .. math :: f(r) = A \\left( \\frac{r}{r_{\\odot}} \\right) ^ \\alpha \\exp \\left[ -\\beta \\left( \\frac{ r - r_{\\odot}}{r_{\\odot}} \\right) \\right] Reference: http://adsabs.harvard.edu//abs/1998ApJ...504..761C (Formula (14)) Parameters ---------- amplitude : float See model formula alpha : float See model formula beta : float See model formula See Also -------- Paczynski1990, YusifovKucuk2004, Lorimer2006, YusifovKucuk2004B, FaucherKaspi2006, Exponential """ amplitude = Parameter() alpha = Parameter() beta = Parameter() evolved = True def __init__(self, amplitude=1., alpha=2, beta=3.53, **kwargs): super(CaseBattacharya1998, self).__init__(amplitude=amplitude, alpha=alpha, beta=beta, **kwargs) @staticmethod def evaluate(r, amplitude, alpha, beta): """Evaluate model.""" term1 = (r / D_SUN_TO_GALACTIC_CENTER.value)**alpha term2 = np.exp(-beta * (r - D_SUN_TO_GALACTIC_CENTER.value) / D_SUN_TO_GALACTIC_CENTER.value) return amplitude * term1 * term2
class FaucherKaspi2006VelocityBimodal(Fittable1DModel): """Bimodal pulsar velocity distribution - Faucher & Kaspi (2006). .. math :: f(v) = A\\sqrt{\\frac{2}{\\pi}} v^2 \\left[\\frac{w}{\\sigma_1^3} \\exp \\left(-\\frac{v^2}{2\\sigma_1^2} \\right) + \\frac{1-w}{\\sigma_2^3} \\exp \\left(-\\frac{v^2}{2\\sigma_2^2} \\right) \\right] Reference: http://adsabs.harvard.edu/abs/2006ApJ...643..332F (Formula (7)) Parameters ---------- amplitude : float Value of the integral sigma1 : float See model formula sigma2 : float See model formula w : float See model formula """ amplitude = Parameter() sigma_1 = Parameter() sigma_2 = Parameter() w = Parameter() def __init__(self, amplitude=1, sigma_1=160, sigma_2=780, w=0.9, **kwargs): super(FaucherKaspi2006VelocityBimodal, self).__init__(amplitude=amplitude, sigma_1=sigma_1, sigma_2=sigma_1, w=w, **kwargs) @staticmethod def evaluate(v, amplitude, sigma_1, sigma_2, w): """One dimensional Faucher-Guigere & Kaspi 2006 velocity model function.""" A = amplitude * np.sqrt(2 / np.pi) * v**2 term1 = (w / sigma_1**3) * np.exp(-v**2 / (2 * sigma_1**2)) term2 = (1 - w) / sigma_2**3 * np.exp(-v**2 / (2 * sigma_2**2)) return A * (term1 + term2)
class YusifovKucuk2004B(Fittable1DModel): """Radial distribution of the surface density of OB stars in the galaxy - Yusifov & Kucuk 2004. .. math :: f(r) = A \\left( \\frac{r}{r_{\\odot}} \\right) ^ a \\exp \\left[ -b \\left( \\frac{r}{r_{\\odot}} \\right) \\right] Derived empirically from OB-stars distribution. Reference: http://adsabs.harvard.edu/abs/2004A%26A...422..545Y (Formula (17)) Parameters ---------- amplitude : float See model formula a : float See model formula b : float See model formula See Also -------- CaseBattacharya1998, Paczynski1990, YusifovKucuk2004, Lorimer2006, FaucherKaspi2006, Exponential """ amplitude = Parameter() a = Parameter() b = Parameter() evolved = False def __init__(self, amplitude=1, a=4, b=6.8, **kwargs): super(YusifovKucuk2004B, self).__init__(amplitude=amplitude, a=a, b=b, **kwargs) @staticmethod def evaluate(r, amplitude, a, b): """Evaluate model.""" return amplitude * (r / D_SUN_TO_GALACTIC_CENTER.value)**a * np.exp( -b * (r / D_SUN_TO_GALACTIC_CENTER.value))
class GaussianLine(Fittable1DModel): """ A model for line emission using a Gaussian """ amplitude = Parameter(min=0) fwhm = Parameter(min=0) x_0 = Parameter(min=0) def evaluate(self, x, amplitude, fwhm, x_0): sig = fwhm/2.3548 return amplitude * np.exp(-(x - x_0)**2/(2*sig**2)) def luminosity(self, ldist): lam = np.arange(-1000, 1000, 0.001) nu = 3e14/(lam) f = self(lam) f_int = -np.trapz(f, nu) / 10**23 b = 4*np.pi*(ldist*10**6*3.086e18)**2 return f_int*b
class LinearExp(FittableModel): inputs = ('t', ) outputs = ('flux', ) amplitude = Parameter() rise_time = Parameter() decay_tau = Parameter() t0 = Parameter(default=0.) @staticmethod def evaluate(t, amplitude, rise_time, decay_tau, t0): if np.ndim(t) == 0: t = np.asarray(t, dtype=np.float).reshape((1, )) t_offset = t - t0 vals = np.zeros_like(t_offset, dtype=np.float) rise_idx = np.logical_and(t_offset >= -rise_time, t_offset <= 0) fall_idx = t_offset > 0 vals[rise_idx] = (1 + t_offset[rise_idx] / rise_time) vals[fall_idx] = np.exp(-t_offset[fall_idx] / decay_tau) return amplitude * vals
class BlackBody1D(Fittable1DModel): """ Current astropy BlackBody1D does not play well with Lorentz1D and Gauss1D maybe, need to check again, possibly a units issue """ amplitude = Parameter() temperature = Parameter() @staticmethod def evaluate(x, amplitude, temperature): """ """ return ( amplitude * ((9.7 / x) ** 2) * 3.97289e13 / x ** 3 / (np.exp(1.4387752e4 / x / temperature) - 1.0) )
class LinearPhaseFunc(DiskIntegratedModelClass): """Linear phase function model Examples -------- >>> # Define a linear phase function model with absolute magnitude >>> # H = 5 and slope = 0.04 mag/deg = 2.29 mag/rad >>> from sbpy.photometry import LinearPhaseFunc >>> >>> linear_phasefunc = LinearPhaseFunc(5, 2.29, radius=300) >>> pha = np.linspace(0, 180, 200) >>> mag = linear_phasefunc.mag(np.deg2rad(pha)) >>> ref = linear_phasefunc.ref(np.deg2rad(pha)) >>> geoalb = linear_phasefunc.geoalb >>> phaseint = linear_phasefunc.phaseint >>> bondalb = linear_phasefunc.bondalb >>> print('Geometric albedo is {0:.3}'.format(geoalb)) Geometric albedo is 0.0501 >>> print('Bond albedo is {0:.3}'.format(bondalb)) Bond albedo is 0.0184 >>> print('Phase integral is {0:.3}'.format(phaseint)) Phase integral is 0.368 """ _unit = 'mag' H = Parameter(description='Absolute magnitude') S = Parameter(description='Linear slope (mag/rad)') @staticmethod def evaluate(a, H, S): return H + S * a @staticmethod def fit_deriv(a, H, S): if hasattr(a, '__iter__'): ddh = np.ones_like(a) else: ddh = 1. dds = a return [ddh, dds]
class GaussHermite1D(Fittable1DModel): """ Gauss-Hermite Series up to the fourth order. Parameters ---------- amplitude : float Integrated flux of the profile. mean : float Coordinate of the profile center. stddev : float Sigma h3 : float Coefficient of the third order element. h4 : float Coefficient of the fourth order element. Description ----------- Taken from Riffel, R. A. 2010 and van der Marel & Franx 1993. """ inputs = ('x', ) outputs = ('y', ) amplitude = Parameter(default=1) mean = Parameter(default=0) stddev = Parameter(default=1) h3 = Parameter(default=0) h4 = Parameter(default=0) @staticmethod def evaluate(x, amplitude, mean, stddev, h3, h4): w = (x - mean) / stddev alphag = np.exp(-w**2. / 2.) / np.sqrt(2. * np.pi) hh3 = h3 * np.sqrt(2.) / np.sqrt(6.) * (2. * w**3 - 3. * w) hh4 = h4 / np.sqrt(24.) * (4. * w**4 - 12. * w**2 + 3.) return amplitude * alphag / stddev * (1. + hh3 + hh4)
class EINASTO2(Fittable1DModel): '''Einasto dark matter halo model Inputs: r: array_like Radius in Kpc. Must be non negative. rho_e2: float or int. rho_e2 in Msol/pc3. r_e2: float or int. r_e2 in Kpc. mu: float or int. no units Outputs v: array_like velocity in km/s. ''' inputs = ('r', ) outputs = ('v', ) rho_e2 = Parameter(bounds=(1e-8, 1e3)) r_e2 = Parameter(bounds=(1e-8, 300)) mu = Parameter(bounds=(0, 20)) fit_deriv = None @staticmethod def evaluate(r, rho_e2, r_e2, mu): '''Einasto dark matter model function ''' r = r * u.kpc rho_e2 = rho_e2 * u.M_sun / (u.pc**3) rho_e2 = rho_e2.to(u.M_sun / (u.kpc**3)) r_e2 = r_e2 * u.kpc # rayon de densite rho2 dn = 2.0 * mu xx = dn * np.power(r / r_e2, 1.0 / mu) igma = gammainc(3 * mu, xx.value) * gamma(3 * mu) v = np.sqrt(G * 4 * np.pi * np.power(r_e2, 3) * rho_e2 * np.power(2.0, -3.0 * mu) * np.power(mu, 1.0 - 3 * mu) * np.exp(dn) * igma / r) v = v.to(u.km / u.s) v = v.value return (v)
class FaucherKaspi2006(Fittable1DModel): """Radial distribution of the birth surface density of pulsars in the galaxy - Faucher-Giguere & Kaspi 2006. .. math :: f(r) = A \\frac{1}{\\sqrt{2 \pi} \sigma} \\exp \\left(- \\frac{(r - r_0)^2}{2 \sigma ^ 2}\\right) Reference: http://adsabs.harvard.edu/abs/2006ApJ...643..332F (Appendix B) Parameters ---------- amplitude : float See model formula r_0 : float See model formula sigma : float See model formula See Also -------- CaseBattacharya1998, Paczynski1990, YusifovKucuk2004, Lorimer2006, YusifovKucuk2004B, Exponential """ amplitude = Parameter() r_0 = Parameter() sigma = Parameter() evolved = False def __init__(self, amplitude=1, r_0=7.04, sigma=1.83, **kwargs): super(FaucherKaspi2006, self).__init__(amplitude=amplitude, r_0=r_0, sigma=sigma, **kwargs) @staticmethod def evaluate(r, amplitude, r_0, sigma): """Evaluate model.""" term1 = 1. / np.sqrt(2 * pi * sigma) term2 = np.exp(-(r - r_0)**2 / (2 * sigma**2)) return amplitude * term1 * term2
class RSquared(FittableModel): inputs = ('epoch', 'luminosity', ) outputs = ('epoch', 'luminosity_density',) #Distance in Mpc distance = Parameter() def evaluate(self, epoch, luminosity, distance): luminosity_density = (luminosity / (4 * np.pi * (distance * mpc_to_cm)**2)) return epoch, luminosity_density
class TwoDScale(Model): n_inputs = 2 n_outputs = 2 scale = Parameter() separable = False def evaluate(self, x, y, scale=1 * u.deg): return u.Quantity([x, y]) * scale @property def inverse(self): return TwoDScale(1 / self.scale)
class Parsec(StarKitModel): mh = Parameter() mass = Parameter() age = Parameter() inputs = () outputs = ('teff', 'logg', 'lum') def __init__(self, parsec_store, mh=0.0, mass=1.0, age=5e9): super(Parsec, self).__init__(mh, mass, age) try: self.parsec_store = pd.HDFStore(parsec_store) except TypeError: self.parsec_store = parsec_store self.evolution_data = [ self.parsec_store[key] for key in self.parsec_store.keys() ] self.parsec_store.close() self.mh_mass = np.empty((len(self.evolution_data), 2)) for i, ev_data in enumerate(self.evolution_data): mh = ev_data['MH'][0] mass = ev_data['MASS'][0] self.mh_mass[i] = mh, mass self.mh_mass_kd_tree = KDTree(self.mh_mass) def evaluate(self, mh, mass, age): distance, idx = self.mh_mass_kd_tree.query( np.array([mh, mass]).squeeze()) ev_data = self.evolution_data[idx] age_ev_data = ev_data['AGE'].values out_ev_data = ev_data[['TEFF', 'LOG_G', 'LOG_L']].values teff, logg, log_l = interpolate.interp1d(age_ev_data, out_ev_data.T, bounds_error=False)( np.squeeze(age)) return teff, logg, 10**log_l
class ModSigmoidExp(FittableModel): """ Sigmoidal rise / exponential decay modulated by a quadratic polynomial. Typically applied as a supernova optical-lightcurve model, applicable to all SNe types. Following Karpenka et al 2012; Eq 1. ( http://adsabs.harvard.edu/abs/2013MNRAS.429.1278K ) """ inputs = ('t', ) outputs = ('flux', ) a = Parameter() b = Parameter() t1_minus_t0 = Parameter() rise_tau = Parameter() decay_tau = Parameter() t0 = Parameter(default=0.) @staticmethod def evaluate(t, a, b, t1_minus_t0, rise_tau, decay_tau, t0): t_offset = t - t0 t_minus_t1 = t_offset - t1_minus_t0 b_fac = 1 + b * t_minus_t1 * t_minus_t1 #NB imported 'truediv' behaviour, so OK even if t0, decay both integers. exp_num = np.exp(-t_offset / decay_tau) exp_denom = 1 + np.exp(-t_offset / rise_tau) return a * b_fac * exp_num / exp_denom
class ModGauss1D(Fittable1DModel): r""" Modified Gaussian """ n_inputs = 1 n_outputs = 1 scale = Parameter(default=1.0) x_o = Parameter(default=3.0, min=0.0) gamma_o = Parameter(default=1.0, min=0.0) asym = Parameter(default=0.0) @staticmethod def evaluate(x, scale, x_o, gamma_o, asym): """ Parameters ---------- x : float input wavelengths scale : float central amplitude x_o : float central wavelength gamma_o : float full-width-half-maximum of profile asym : float asymmetry where a value of 0 results in a standard Drude profile """ # gamma replaces FWHM, so stddev=gamma/(2sqrt(2ln2)) gamma = 2.0 * gamma_o / (1.0 + np.exp(asym * (x - x_o))) y = scale * np.exp( -((x - x_o) ** 2) / (2 * (gamma / (2 * np.sqrt(2 * np.log(2)))) ** 2) ) return y
class GaussExp(FittableModel): inputs = ('t', ) outputs = ('flux', ) amplitude = Parameter() rise_tau = Parameter() decay_tau = Parameter() t0 = Parameter(default=0.) @staticmethod def evaluate(t, amplitude, rise_tau, decay_tau, t0): if np.ndim(t) == 0: t = np.asarray(t, dtype=np.float).reshape((1, )) t_offset = t - t0 vals = np.zeros_like(t_offset, dtype=np.float) #NB vals outside offset_min/max limits taken care of by LightcurveBase rise_idx = t_offset <= 0. fall_idx = t_offset > 0. vals[rise_idx] = np.exp(-1. * t_offset[rise_idx] * t_offset[rise_idx] / (2. * rise_tau * rise_tau)) vals[fall_idx] = np.exp(-t_offset[fall_idx] / decay_tau) return amplitude * vals
class NegativeQuadratic(FittableModel): """ Very simple example, used for testing purposes. """ inputs = ('t', ) outputs = ('flux', ) amplitude = Parameter() t0 = Parameter(default=0.0) @staticmethod def evaluate(t, amplitude, t0): if np.ndim(t) == 0: t = np.asarray(t, dtype=np.float).reshape((1, )) t_offset = t - t0 root = np.sqrt(amplitude) t_valid = (t_offset > -root) & (t_offset < root) # print "t_offset", t_offset # print "T_valid", t_valid vals = np.zeros_like(t_offset) vals[t_valid] = amplitude - t_offset[t_valid]**2 return vals
def _load_parameters(self): """Function to load parameters from the sub-model""" if self._parameters is not None: # do nothing return self._parameters_ = {} self._param_names = [] for param_name, param_val in zip(self._model.param_names, self._model.parameters): param = Parameter(param_name, default=param_val) self.__dict__[param_name] = param self._parameters_[param_name] = param self._param_names.append(param_name) param_name = 'psf_pa' param = Parameter(param_name, default=0) self.__dict__[param_name] = param self._parameters_[param_name] = param self._param_names.append(param_name) self._param_names = tuple(self._param_names)
class Gaussian1D(Fittable1DModelPlugin): amplitude = Parameter("amplitude") mean = Parameter("mean") stddev = Parameter("stddev") @staticmethod def evaluate(x, amplitude, mean, stddev): """ Gaussian1D model function. """ return amplitude * np.exp(-0.5 * (x - mean)**2 / stddev**2) @staticmethod def fit_deriv(x, amplitude, mean, stddev): """ Gaussian1D model function derivatives. """ d_amplitude = np.exp(-0.5 / stddev**2 * (x - mean)**2) d_mean = amplitude * d_amplitude * (x - mean) / stddev**2 d_stddev = amplitude * d_amplitude * (x - mean)**2 / stddev**3 return [d_amplitude, d_mean, d_stddev]
class VanDerLaan(FittableModel): """ """ inputs = ('t', ) outputs = ('flux', ) # maximum_flux amplitude = Parameter() energy_index = Parameter() # maximum_time t0 = Parameter(default=0.) @staticmethod def evaluate(t, amplitude, energy_index, t0): maximum_flux = amplitude maximum_time = t0 vals = np.zeros_like(t, dtype=np.float) index = t >= 0. # parameters that are derived from inputs and physics parameters distance = 3.09e19 # place holder distance of 1 kiloparsec initial_tau_0_guess = 10. tau_m = fsolve(tau_0_solve, initial_tau_0_guess, energy_index) size_at_peak_flux = ((maximum_flux * distance * distance / np.pi) * (1. / (1. - np.exp(-tau_m))))**0.5 expansion_speed = size_at_peak_flux / maximum_time # assume that the cloud expands linearly relative_size = 1. + ((expansion_speed / size_at_peak_flux) * (t - maximum_time)) numerator = 1. - np.exp( -tau_m * relative_size**(-2. * energy_index - 3.)) denominator = 1. - np.exp(-tau_m) vals[index] = (relative_size**3.) * numerator / denominator return maximum_flux * vals
class gaussian(Fittable1DModel): '''A two-faced gaussian based on the version in stsdas.contrib.specfit Effectively, this gaussian has two different sigmas on each side of the mean. For values less than the mean, the sigma is as specified. For values greater than the mean, the new sigma = skew * specified sigma Units for fwhm are km/s norm represents total flux (presumably in arbitrary units) mean is called the centroid, but that seems misleading. It is the maximum of the dual faced gaussian. The units of mean and x should be consistent. ''' norm = Parameter(default=1) mean = Parameter(default=0) fwhm = Parameter(default=1) skew = Parameter(default=1) @staticmethod def evaluate(x, norm, mean, fwhm, skew): return bipolar_gaussian(x, norm, mean, fwhm, skew)
class Shift2D(FittableModel): """2D translation""" if ASTROPY_LT_40: inputs = ('x', 'y') outputs = ('x', 'y') else: n_inputs = 2 n_outputs = 2 x_offset = Parameter(default=0.0) y_offset = Parameter(default=0.0) @property def inverse(self): inv = self.copy() inv.x_offset = -self.x_offset inv.y_offset = -self.y_offset return inv @staticmethod def evaluate(x, y, x_offset, y_offset): return x + x_offset, y + y_offset
class sl(Fittable1DModel): """ Model for starlight calculation """ star_temp = 5000. Star_tau = Parameter(description="star_tau_T5000", default=5e-12, min=0.0) @staticmethod def evaluate(in_x, Star_tau): y = Star_tau * blackbody(in_x, sl.star_temp) return y
class Drude(Fittable1DModel): """ Drude profile to use for dust features in IRS spectra. """ amplitude = Parameter(min=0) fwhm = Parameter(min=0) x_0 = Parameter(min=0) def evaluate(self, x, amplitude, fwhm, x_0): num = amplitude * (fwhm/x_0)**2 denom = (x/x_0 - x_0/x)**2 + (fwhm/x_0)**2 return num/denom def luminosity(self, ldist): """ Calculate luminosity of Drude profile for a specific luminosity distance. ldist = luminosity distance in Mpc """ a = np.pi*3e14/2.*self.amplitude*(self.fwhm/self.x_0)/self.x_0/10**23 b = 4*np.pi*(ldist*10**6*3.086e18)**2 return a*b
class DifferentialRefraction(Fittable1DModel): """ See Filippenko, A. 1982 (PASP 94, 715). Wavelengths must be in microns! """ n_inputs = 1 n_outputs = 1 temperature = Parameter(default=7.0, min=-60.0, max=40.0) pressure = Parameter(default=500.0, min=100.0, max=800.0) water_vapour = Parameter(default=8.0, min=0.0, max=800.0) air_mass = Parameter(default=1.5, min=1.0, max=5.0) wl_0 = Parameter(default=5000.0) @staticmethod def evaluate(x, temperature, pressure, water_vapour, air_mass, wl_0): def n_lambda(wavelength): r = np.square(1.0 / wavelength) a = 29498.1 / (146.0 - r) b = 255.4 / (41.0 - r) n_sea_level = 1e-6 * (64.328 + a + b) a = 1.0 + (1.049 - (0.0157 * temperature)) * 1e-6 * pressure b = 720.883 * (1.0 + 0.003661 * temperature) n_tp = n_sea_level * pressure * (a / b) a = 0.0624 - (0.000680 * r) b = 1.0 + (0.003661 * temperature) water_factor = water_vapour * (a / b) * 1e-6 return n_tp - water_factor k = np.tan(np.arcsin(1 / air_mass)) delta_r = 206265.0 * (n_lambda(x * 1e-4) - n_lambda(wl_0 * 1e-4)) * k return delta_r
class NFW(Fittable1DModel): '''Navarro-Frenk-White halo model Inputs: r: array_like. Radius in Kpc. Must be non negative. par_list: list, of length 2, of Parameters of NFW model. par_list[0]: float or int. v200 in km/s par_list[1]: float or int. concentration parameter, no units. Outputs v: velocity in km/s. ''' inputs = ('r', ) outputs = ('v', ) v200 = Parameter(bounds=(0, 200)) c = Parameter(bounds=(1e-12, 30)) fit_deriv = None @staticmethod def evaluate(r, v200, c): r = r * u.kpc v200 = v200 * u.km / u.s r200 = (v200 / cosmo.H0).to(u.kpc) # r200 = (v200/(68.0*u.km/u.s/u.Mpc)*100).to(u.kpc) # r200 = v200/cosmo.h*1e3 x = r / r200 v = v200 * np.power((np.log(1.0 + c * x) - c * x / (1.0 + c * x)) / (x * (np.log(1.0 + c) - c / (1.0 + c))), 0.5) v = v.to(u.km / u.s) v = v.value return (v)