Beispiel #1
0
 def modify_model(self, changes=None, removings=None, verbose=False, warnings=True, describe=False):
     """
     Apply changes on the loaded model.
     
     Parameters
     ----------
     changes : [dict or None]
         Dictionary containing the desired changes for the desired parameters.
         As an example, changes={"zred"={"init"=2.}}) will change the initial value of the 'zred' parameter, without changing anything else.
         Default is None.
     
     removings : [string or list(string) or None]
         List of every parameters you want to remove from the model.
         Default is None.
     
     Options
     -------
     verbose : [bool]
         If True, print the SED model before and after modifications.
         Default is False.
     
     warnings : [bool]
         If True, allow warnings to be printed.
         Default is True.
     
     describe : [bool]
         If True, print the description for any used not native prior.
         Default is False.
     
     
     Returns
     -------
     Void
     """
     from prospect.models.sedmodel import SedModel
     
     _model = self.model.config_dict
     if verbose:
         print(tools.get_box_title(title="Previous model", box="\n#=#\n#   {}   #\n#=#\n"))
         pprint(_model)
     
     #Changes
     _describe_priors = []
     if changes is not None:
         _model, _describe_priors = self._model_changes_(_model, changes, warnings)
     if describe and len(_describe_priors) > 0:
         self.describe_priors(_describe_priors)
     
     #Removing
     if removings is not None:
         _model = self._model_removings_(_model, removings, warnings)
     
     if verbose:
         print(tools.get_box_title(title="New model", box="\n\n\n#=#\n#   {}   #\n#=#\n"))
         pprint(_model)
     
     self._model = SedModel(_model)
Beispiel #2
0
def load_model(zred=None, **extras):
    # In principle (and we've done it) you could have the model depend on
    # command line arguments (or anything in run_params) by making changes to
    # `model_params` here before instantiation the SedModel object.  Up to you.

    # Here we are going to set the intial value (and the only value, since it
    # is not a free parameter) of the redshift parameter to whatever was used
    # to generate the mock, listed in the run_params dictionary.
    pn = [p['name'] for p in model_params]
    zind = pn.index('zred')
    model_params[zind]['init'] = zred

    return SedModel(model_params)
def build_model(binNum=0,
                fit_metallicity=1,
                fit_redshift=1,
                infile=None,
                add_neb=0,
                **extras):

    from astropy.table import Table
    from prospect.models.priors import LogUniform, TopHat, Normal
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.sources.constants import cosmo

    table = Table.read(infile)
    zobs = table['z'][binNum]
    max_age = cosmo.age(zobs).value

    model_params = TemplateLibrary['parametric_sfh']  # delay-tau model

    model_params['zred']['init'] = zobs
    model_params['zred']['isfree'] = bool(fit_redshift)
    model_params['zred']['prior'] = TopHat(mini=zobs - 0.01, maxi=zobs + 0.01)

    model_params['mass']['init'] = 1e7
    model_params['mass']['prior'] = LogUniform(mini=1e5, maxi=1e9)

    model_params['logzsol']['init'] = -0.15
    model_params['logzsol']['isfree'] = bool(fit_metallicity)
    model_params['logzsol']['prior'] = Normal(mean=-0.15, sigma=0.22)

    model_params['dust2']['init'] = 0.3
    model_params['dust2']['prior'] = TopHat(mini=0.0, maxi=2.0)

    model_params['tage']['init'] = 6.24
    model_params['tage']['prior'] = TopHat(mini=0.001, maxi=max_age)

    model_params['tau']['init'] = 0.29
    model_params['tau']['prior'] = LogUniform(mini=0.1, maxi=10)

    model_params['imf_type']['init'] = 1  # Chabrier (2003) IMF
    model_params['dust_type']['init'] = 1  # Cardelli+ (1989) MW extinction

    if add_neb:
        model_params.update(TemplateLibrary['nebular'])

    model = SedModel(model_params)

    return model
Beispiel #4
0
def build_model(binNum=0, fit_metallicity=1, fit_redshift=1, infile=None,
                **extras) :
    
    import numpy as np
    from astropy.table import Table
    from prospect.models.priors import StudentT, TopHat
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    
    table = Table.read(infile)
    zobs = table['z'][binNum]
    nbins = 10
    
    model_params = TemplateLibrary['continuity_sfh'] # non-parametric SFH
    
    model_params['zred']['init'] = zobs
    model_params['zred']['isfree'] = bool(fit_redshift)
    model_params['zred']['prior'] = TopHat(mini=zobs-0.01, maxi=zobs+0.01)
    
    model_params['logmass']['init'] = 6
    model_params['logmass']['prior'] = TopHat(mini=3, maxi=16)
    model_params['mass']['N'] = nbins
    
    model_params['logzsol']['init'] = -0.5
    model_params['logzsol']['isfree'] = bool(fit_metallicity)
    model_params['logzsol']['prior'] = TopHat(mini=-2, maxi=0.2)
    
    model_params['dust2']['init'] = 0.5
    model_params['dust2']['prior'] = TopHat(mini=0.0, maxi=4.0)
    
    model_params['agebins']['N'] = nbins
    model_params['agebins']['init'] = [[0.0, 7.47712125], [7.47712125, 8.0],
        [8.0, 8.69897], [8.69897, 9.0], [9.0, 9.5261747], [9.5261747, 9.75720267],
        [9.75720267,  9.90720604], [9.90720604, 10.01848862],
        [10.01848862, 10.10699395], [10.10699395, 10.12927034]]
    
    model_params['logsfr_ratios']['N'] = nbins - 1
    model_params['logsfr_ratios']['init'] = np.full(nbins-1, 0.0)
    model_params['logsfr_ratios']['prior'] = StudentT(mean=np.full(nbins-1,0.0),
                                                      scale=np.full(nbins-1,0.3),
                                                      df=np.full(nbins-1, 2))
    
    model_params['imf_type']['init'] = 1 # Chabrier (2003) IMF
    model_params['dust_type']['init'] = 1 # Cardelli+ (1989) MW extinction
    
    model = SedModel(model_params)
    
    return model
def load_model(zred=0.0,
               add_neb=False,
               complex_atten=False,
               atten_bump=False,
               **extras):
    """Instantiate and return a ProspectorParams model subclass.
    
    :param zred: (optional, default: 0.1)
        The redshift of the model
        
    :param add_neb: (optional, default: False)
        If True, turn on nebular emission and add relevant parameters to the
        model.
    """
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary

    model_params = TemplateLibrary["alpha"]

    model_params["fagn"]["isfree"] = False
    model_params["agn_tau"]["isfree"] = False
    model_params["sfh"]["init"] = 0

    if add_neb == True:
        model_params['add_neb_emission']['init'] = True

    if complex_atten == True:
        # --- Complexify dust attenuation ---
        # Switch to Kriek and Conroy 2013
        model_params["dust_type"] = {
            'N': 1,
            'isfree': False,
            'init': 4,
            'prior': None
        }
    if atten_bump == True:
        # Slope of the attenuation curve, expressed as the index of the power-law
        # that modifies the base Kriek & Conroy/Calzetti shape.
        # I.e. a value of zero is basically calzetti with a 2175AA bump
        model_params["dust_index"] = {
            'N': 1,
            'isfree': False,
            'init': 0.0,
            'prior': None
        }

    return SedModel(model_params)
def build_model(object_redshift=None,ldist=None,fixed_metallicity=None,add_duste=None,
                add_nebular=True,add_burst=True,**extras):
    model_params = TemplateLibrary["parametric_sfh"]
    model_params["tau"]["init"] = 3.0
    model_params["dust2"]["init"] = 0.1
    model_params["logzsol"]["init"] = -0.8
    model_params["tage"]["init"] = 6.5
    model_params["mass"]["init"] = 1e8
    model_params["tage"]["prior"] = priors.TopHat(mini=0.1, maxi=11.)
    model_params["dust2"]["prior"] = priors.TopHat(mini=0.0, maxi=2.0)
    model_params["tau"]["prior"] = priors.LogUniform(mini=1., maxi=7.)
    model_params["mass"]["prior"] = priors.LogUniform(mini=1e7, maxi=1e12)
    model_params["zred"]["prior"] = priors.TopHat(mini=0.005, maxi=4.0)
    model_params["mass"]["disp_floor"] = 1e5
    model_params["tau"]["disp_floor"] = 1.0
    model_params["tage"]["disp_floor"] = 1.0
    
    if fixed_metallicity is not None:
        model_params["logzsol"]["isfree"] = False
        model_params["logzsol"]['init'] = fixed_metallicity
    if object_redshift is not None:
        model_params["zred"]['isfree'] = False
        model_params["zred"]['init'] = object_redshift
    if object_redshift is None:
        model_params["zred"]['isfree'] = True
        model_params["zred"]['init'] = 0.1
    if add_duste:
        model_params.update(TemplateLibrary["dust_emission"])
    if add_nebular:
        model_params.update(TemplateLibrary["nebular"])
    if add_burst:
        model_params.update(TemplateLibrary["burst_sfh"])

    model_params["mass"]["isfree"] = True
    model_params["logzsol"]["isfree"] = True
    model_params["dust2"]["isfree"] = True
    model_params["tage"]["isfree"] = True
    model_params["tau"]["isfree"] = True
    model = SedModel(model_params)

    return model
def build_model(object_redshift=None,
                fixed_metallicity=None,
                add_duste=False,
                **extras):
    """Build a prospect.models.SedModel object
    
    :param object_redshift: (optional, default: None)
        If given, produce spectra and observed frame photometry appropriate 
        for this redshift. Otherwise, the redshift will be zero.
        
    :param fixed_metallicity: (optional, default: None)
        If given, fix the model metallicity (:math:`log(Z/Z_sun)`) to the given value.
        
    :param add_duste: (optional, default: False)
        If `True`, add dust emission and associated (fixed) parameters to the model.
        
    :returns model:
        An instance of prospect.models.SedModel
    """

    # Get (a copy of) one of the prepackaged model set dictionaries.
    # This is, somewhat confusingly, a dictionary of dictionaries, keyed by parameter name
    model_params = TemplateLibrary["alpha"]
    #model_params = TemplateLibrary["parametric_sfh"]

    # Set agebins manually
    #age_at_z = astropy_cosmo.age(object_redshift).value

    nbins_sfh = 8
    model_params['agebins']['N'] = nbins_sfh
    model_params['mass']['N'] = nbins_sfh

    # This will give the stellar mass as the surviving
    # mass which is what we want. Otherwise by default
    # it gives total mass formed.
    #model_params["mass"]["units"] = 'mstar'
    # Set dust type. # Fixed for parametric sfh
    #model_params["dust_type"] = 4

    # Let's make some changes to initial values appropriate for our objects and data
    #model_params["logmass"]["init"] = 10
    #model_params["logzsol"]["init"] = -0.5
    #model_params["dust2"]["init"] = 0.05
    #model_params["mass"]["init"] = 1e10
    #model_params["tage"]["init"] = 4.0
    #model_params["tau"]["init"] = 1.0

    # Choose priors
    # Priors not specified in here are left at default values

    #model_params["mass"]["prior"] = priors.LogUniform(mini=1e8, maxi=1e12)
    #model_params["tau"]["prior"] = priors.LogUniform(mini=1e-1, maxi=1e2)

    # If we are going to be using emcee, it is useful to provide a
    # minimum scale for the cloud of walkers (the default is 0.1)
    #model_params["mass"]["disp_floor"] = 1e8
    #model_params["tau"]["disp_floor"] = 1.0
    #model_params["tage"]["disp_floor"] = 1.0

    # Change the model parameter specifications based on some keyword arguments
    if fixed_metallicity is not None:
        # make it a fixed parameter
        model_params["logzsol"]["isfree"] = False
        #And use value supplied by fixed_metallicity keyword
        model_params["logzsol"]['init'] = fixed_metallicity

    if object_redshift is not None:
        # make sure zred is fixed
        model_params["zred"]['isfree'] = False
        # And set the value to the object_redshift keyword
        model_params["zred"]['init'] = object_redshift

    if add_duste:
        # Add dust emission (with fixed dust SED parameters)
        # Since `model_params` is a dictionary of parameter specifications,
        # and `TemplateLibrary` returns dictionaries of parameter specifications,
        # we can just update `model_params` with the parameters described in the
        # pre-packaged `dust_emission` parameter set.
        model_params.update(TemplateLibrary["dust_emission"])

    # Now instantiate the model object using this dictionary of parameter specifications
    model = SedModel(model_params)

    return model
Beispiel #8
0
def load_model(zred=None, add_neb=False, complex_atten=False, atten_bump=False, **extras):
    """Instantiate and return a ProspectorParams model subclass.
    
    :param zred: (optional, default: 0.1)
        The redshift of the model
        
    :param add_neb: (optional, default: False)
        If True, turn on nebular emission and add relevant parameters to the
        model.
    """
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary

    model_params = TemplateLibrary["parametric_sfh"]
    
    if complex_atten == True:
        # --- Complexify dust attenuation ---
        # Switch to Kriek and Conroy 2013
        model_params["dust_type"] = {'N': 1, 'isfree': False,
                                     'init': 4, 'prior': None}
    if atten_bump == True:
        # Slope of the attenuation curve, expressed as the index of the power-law
        # that modifies the base Kriek & Conroy/Calzetti shape.
        # I.e. a value of zero is basically calzetti with a 2175AA bump
        model_params["dust_index"] = {'N': 1, 'isfree': False,
                                     'init': 0.0, 'prior': None}


    # --- Distance ---
    model_params.update({'zred': {'N': 1,
                            'isfree': False,
                            'init': zred,
                            'units': '',
                            'prior': priors.TopHat(mini=0.0, maxi=5.8)}})
    
    
    # --- SFH --------
    # FSPS parameter
    model_params.update({'sfh': {'N': 1,
                            'isfree': False,
                            'init': 4,  # This is delay-tau
                            'units': 'type',
                            'prior': None}})

    model_params.update({'mass':{'N': 1, 'isfree': True,
                                'init': 1e10,
                                'init_disp': 1e9,
                                'units': r'M_\odot',
                                'prior': priors.LogUniform(mini=1e6, maxi=1e12)}})

    model_params.update({'logzsol': {'N': 1,
                            'isfree': True,
                            'init': -0.3,
                            'init_disp': 0.3,
                            'units': r'$\log (Z/Z_\odot)$',
                            'prior': priors.TopHat(mini=-2.0, maxi=0.19)}})

    # If zcontinuous > 1, use 3-pt smoothing
    model_params.update({'pmetals': {'N': 1,
                            'isfree': False,
                            'init': -99,
                            'prior': None}})

    # FSPS parameter
    model_params.update({'tau': {'N': 1,
                            'isfree': True,
                            'init': 1.0,
                            'init_disp': 0.5,
                            'units': 'Gyr',
                            'prior':priors.LogUniform(mini=0.101, maxi=100)}})

    # FSPS parameter
    model_params.update({'tage':{'N': 1,
                            'isfree': True,
                            'init': 5.0,
                            'init_disp': 3.0,
                            'units': 'Gyr',
                            'prior': priors.TopHat(mini=0.101, maxi=13.6)}})

    model_params.update({'fage_burst': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': 'time at wich burst happens, as a fraction of `tage`',
                            'prior': priors.TopHat(mini=0.9, maxi=1.0)}})

    # If we are going to be using emcee, it is useful to provide a 
    # minimum scale for the cloud of walkers (the default is 0.1)
    model_params["mass"]["disp_floor"] = 1e7
    model_params["mass"]["init_disp"] = 1e8
    model_params["tau"]["disp_floor"] = 1.0
    model_params["tage"]["disp_floor"] = 1.0


    # FSPS parameter
    model_params.update({'tburst': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': '',
                            'prior': None,}})
                            #'depends_on': tburst_fage}})  # uncomment if using bursts.

    # FSPS parameter
    model_params.update({'fburst': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': '',
                            'prior': priors.TopHat(mini=0.0, maxi=0.5)}})
    
    # ------  IMF  ---------

    model_params.update({'imf_type': {'N': 1,
                                 'isfree': False,
                                 'init': 1, #1 = chabrier
                                 'units': None,
                                 'prior': None}})

    # --- Dust ---------
    # FSPS parameter
    model_params.update({'dust_type': {'N': 1,
                            'isfree': False,
                            'init': 0,  # power-laws
                            'units': 'index',
                            'prior': None}})
    # FSPS parameter
    model_params.update({'dust2': {'N': 1,
                            'isfree': True,
                            'init': 0.35,
                            'reinit': True,
                            'init_disp': 0.3,
                            'units': 'Diffuse dust optical depth towards all stars at 5500AA',
                            'prior': priors.TopHat(mini=0.0, maxi=2.0)}})

    # FSPS parameter
    model_params.update({'dust1': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': 'Extra optical depth towards young stars at 5500AA',
                            'prior': None}})

    # FSPS parameter
    model_params.update({'dust_tesc': {'N': 1,
                            'isfree': False,
                            'init': 7.0,
                            'units': 'definition of young stars for the purposes of the CF00 dust model, log(Gyr)',
                            'prior': None}})

    # FSPS parameter
    model_params.update({'dust_index': {'N': 1,
                            'isfree': False,
                            'init': -0.7,
                            'units': 'power law slope of the attenuation curve for diffuse dust',
                            'prior': priors.TopHat(mini=-1.0, maxi=0.4)}})

    # FSPS parameter
    model_params.update({'dust1_index': {'N': 1,
                            'isfree': False,
                            'init': -1.0,
                            'units': 'power law slope of the attenuation curve for young-star dust',
                            'prior': None}})
    # ---- Dust Emission ---
    # FSPS parameter
    model_params.update({'add_dust_emission': {'N': 1,
                            'isfree': False,
                            'init': False,
                            'units': 'index',
                            'prior': None}})

    # An example of the parameters controlling the dust emission SED.  There are others!
 
    model_params.update({'duste_gamma': {'N': 1,
                            'isfree': False,
                            'init': 0.01,
                            'init_disp': 0.2,
                            'disp_floor': 0.15,
                            'units': None,
                            'prior': priors.TopHat(mini=0.0, maxi=1.0)}})


    model_params.update({'duste_umin': {'N': 1,
                            'isfree': False,
                            'init': 1.0,
                            'init_disp': 5.0,
                            'disp_floor': 4.5,
                            'units': None,
                            'prior': priors.TopHat(mini=0.1, maxi=25.0)}})

    model_params.update({'duste_qpah': {'N': 1,
                            'isfree': False,
                            'init': 2.0,
                            'init_disp': 3.0,
                            'disp_floor': 3.0,
                            'units': 'percent',
                            'prior': priors.TopHat(mini=0.0, maxi=7.0)}})

    # --- Stellar Pops ------------
    # One could imagine changing these, though doing so *during* the fitting will
    # be dramatically slower.
    # FSPS parameter
    model_params.update({'tpagb_norm_type': {'N': 1,
                            'isfree': False,
                            'init': 2,
                            'units': 'index',
                            'prior': None}})

    # FSPS parameter
    model_params.update({'add_agb_dust_model': {'N': 1,
                            'isfree': False,
                            'init': True,
                            'units': 'index',
                            'prior': None}})

    # FSPS parameter
    model_params.update({'agb_dust': {'N': 1,
                            'isfree': False,
                            'init': 1,
                            'units': 'index',
                            'prior': None}})

    # --- Nebular Emission ------

    # For speed we turn off nebular emission in the demo
    model_params.update({'add_neb_emission': {'N': 1,
                            'isfree': False,
                            'init': False,
                            'prior': None}})

    # FSPS parameter
    model_params.update({'gas_logz': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': r'log Z/Z_\odot',
    #                        'depends_on': stellar_logzsol,
                            'prior': priors.TopHat(mini=-2.0, maxi=0.5)}})

    # FSPS parameter
    model_params.update({'gas_logu': {'N': 1,
                            'isfree': False,
                            'init': -2.0,
                            'units': '',
                            'prior': priors.TopHat(mini=-4, maxi=-1)}})

    # --- Calibration ---------
    # Only important if using a NoiseModel
    model_params.update({'phot_jitter': {'N': 1,
                            'isfree': False,
                            'init': 0.0,
                            'units': 'mags',
                            'prior': priors.TopHat(mini=0.0, maxi=0.2)}})

    
    return SedModel(model_params)
Beispiel #9
0
def build_model(binNum=0,
                fit_metallicity=1,
                fit_redshift=1,
                infile=None,
                add_neb=0,
                metalfile=None,
                cluster=None,
                ID=0,
                **extras):

    import numpy as np
    from astropy.table import Table
    from prospect.models.priors import ClippedNormal, StudentT, TopHat
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.sources.constants import cosmo

    table = Table.read(infile)
    zobs = table['z'][binNum]
    max_age, nbins = cosmo.age(zobs).value, 10

    # sma, smb = table['sma'][binNum], table['smb'][binNum]
    # R_e, width = table['R_e'][binNum], table['width'][binNum]
    # radius = (sma - width)*np.sqrt(smb/sma)/R_e

    metallicities = Table.read(metalfile)
    idx = np.where((metallicities['cluster'] == cluster)
                   & (metallicities['ID'] == ID))[0][0]
    central_metallicity = metallicities['centrallogZ'][idx]
    sigma_metallicity = metallicities['sigma'][idx]
    init_metallicity = central_metallicity  # - 0.1*radius

    model_params = TemplateLibrary['continuity_sfh']  # non-parametric model

    model_params['zred']['init'] = zobs
    model_params['zred']['isfree'] = bool(fit_redshift)
    model_params['zred']['prior'] = TopHat(mini=zobs - 0.01, maxi=zobs + 0.01)

    model_params['logmass']['init'] = 7
    model_params['logmass']['prior'] = TopHat(mini=5, maxi=10)
    model_params['mass']['N'] = nbins

    model_params['logzsol']['init'] = init_metallicity
    model_params['logzsol']['isfree'] = bool(fit_metallicity)
    model_params['logzsol']['prior'] = ClippedNormal(mean=init_metallicity,
                                                     sigma=sigma_metallicity,
                                                     mini=-2,
                                                     maxi=0.2)

    model_params['dust2']['init'] = 0.3
    model_params['dust2']['prior'] = TopHat(mini=0.0, maxi=2.0)

    model_params['agebins']['N'] = nbins
    agelims = np.concatenate([
        np.log10([1e-9, 0.03, 0.1, 0.5]),
        np.linspace(0, np.log10(0.95 * max_age), 6),
        np.log10([max_age])
    ]) + 9
    model_params['agebins']['init'] = np.array([agelims[:-1], agelims[1:]]).T

    model_params['logsfr_ratios']['N'] = nbins - 1
    model_params['logsfr_ratios']['init'] = np.zeros(nbins - 1)
    model_params['logsfr_ratios']['prior'] = StudentT(
        mean=np.zeros(nbins - 1),
        scale=0.3 * np.ones(nbins - 1),
        df=2 * np.ones(nbins - 1))

    model_params['imf_type']['init'] = 1  # Chabrier (2003) IMF
    model_params['dust_type']['init'] = 1  # Cardelli+ (1989) MW extinction

    if add_neb:
        model_params.update(TemplateLibrary['nebular'])

    model = SedModel(model_params)

    return model
Beispiel #10
0
def build_model(gal_ebv, object_redshift=None, init_theta=None):
    """Build a prospect.models.SedModel object

    :param object_redshift: (optional, default: None)
        If given, produce spectra and observed frame photometry appropriate
        for this redshift. Otherwise, the redshift will be zero.

    :param  init_theta: (optional, default: [1e10, -1, 10, 1])
        The initial guess on the parameters for mcmc.

    :returns model:
        An instance of prospect.models.SedModel
    """
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.models import priors

    # Get (a copy of) one of the prepackaged model set dictionaries.
    model_params = TemplateLibrary["parametric_sfh"]

    model_params["sfh"]["init"] = 4
    Av_init = gal_ebv * 3.1
    # print(init_theta)
    # Changing the initial values appropriate for our objects and data
    model_params["mass"]["init"] = init_theta[0]
    model_params["logzsol"]["init"] = init_theta[1]
    model_params["dust2"]["init"] = Av_init
    model_params["tage"]["init"] = init_theta[2]
    model_params["tau"]["init"] = init_theta[3]

    # Setting the priors forms and limits
    model_params["mass"]["prior"] = priors.LogUniform(mini=1e6, maxi=1e12)
    model_params["logzsol"]["prior"] = priors.Uniform(mini=-1.8, maxi=0.3)
    model_params["dust2"]["prior"] = priors.ClippedNormal(mean=Av_init, sigma=0.05, mini=Av_init,
                                                          maxi=Av_init + 0.1)
    # model_params["dust2"]["prior"] = priors.Uniform(mini=0.0, maxi=0.5)
    model_params["tage"]["prior"] = priors.Uniform(mini=0.1, maxi=13.8)
    model_params["tau"]["prior"] = priors.Uniform(mini=0.001, maxi=30)

    # Setting the spread of the walkers for the mcmc sampling
    model_params["mass"]["disp_floor"] = 1e8
    model_params["logzsol"]['disp_floor'] = 0.5
    model_params["dust2"]["disp_floor"] = 0.01
    model_params["tage"]["disp_floor"] = 5.0
    model_params["tau"]["disp_floor"] = 3.0

    model_params["mass"]["init_disp"] = 1e8
    model_params["logzsol"]['init_disp'] = 0.5
    model_params["dust2"]["init_disp"] = 0.01
    model_params["tage"]["init_disp"] = 5.0
    model_params["tau"]["init_disp"] = 3.0

    # Fixing and defining the object redshift
    model_params["zred"]['isfree'] = False
    model_params["zred"]['init'] = object_redshift

    # ldist = cosmo.luminosity_distance(object_redshift).value
    # model_params["lumdist"] = {"N": 1, "isfree": False, "init": ldist, "units": "Mpc"}

    # Now instantiate the model object using this dictionary of parameter specifications
    model = SedModel(model_params)

    return model
Beispiel #11
0
def load_model(obs, template_library='delayed-tau', verbose=False):
    """
    http://dfm.io/python-fsps/current/stellarpop_api/#api-reference
    https://github.com/moustakas/siena-astrophysics/blob/master/research/redmapper/redmapper-stellar-mass.py#L125-L197    
    
    """
    from prospect.models import priors
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.models.transforms import dustratio_to_dust1

    def base_delayed_tau():
        model_params = TemplateLibrary['parametric_sfh']

        # Initialize with sensible numbers.
        model_params['tau']['init'] = 10.0
        model_params['tage']['init'] = 1.0
        model_params['logzsol']['init'] = 0.2

        # optimize log-stellar mass, not linear stellar mass
        model_params['logmass'] = {
            'N': 1,
            'isfree': True,
            'init': 11.0,
            'prior': priors.TopHat(mini=10.0, maxi=12.0),
            'units': '$M_{\odot}$'
        }

        model_params['mass']['isfree'] = False
        model_params['mass']['init'] = 10**model_params['logmass']['init']
        model_params['mass']['prior'] = None
        model_params['mass']['depends_on'] = logmass2mass

        # Adjust the prior ranges.
        model_params['tau']['prior'] = priors.LogUniform(mini=0.01, maxi=30.0)
        model_params['tage']['prior'] = priors.LogUniform(mini=0.1, maxi=13.0)
        model_params['logzsol']['prior'] = priors.TopHat(mini=-0.5, maxi=0.3)

        #print('HACK!!!!!!!!!!!!!')
        #model_params['tau']['isfree'] = False
        #model_params['tage']['isfree'] = False
        #model_params['logzsol']['isfree'] = False
        #model_params['dust2']['isfree'] = False

        return model_params

    if template_library == 'delayed-tau':
        # Underlying delayed tau model.
        model_params = base_delayed_tau()

    if template_library == 'bursty':
        # Underlying delayed tau model.
        model_params = base_delayed_tau()

        # Add bursts
        model_params.update(TemplateLibrary['burst_sfh'])

        model_params['fburst']['isfree'] = True
        model_params['fburst']['init'] = 0.1
        model_params['fburst']['prior'] = priors.TopHat(mini=0.0, maxi=1.0)

        model_params['fage_burst']['isfree'] = True
        model_params['fage_burst']['init'] = 0.9
        model_params['fage_burst']['prior'] = priors.TopHat(mini=0.5, maxi=1.0)

    # Add dust emission (with fixed dust SED parameters).
    model_params.update(TemplateLibrary['dust_emission'])
    model_params['duste_gamma']['isfree'] = True

    model_params['dust2']['init'] = 1.0  # diffuse dust
    model_params['dust2']['prior'] = priors.TopHat(mini=0.0, maxi=4.0)

    # Add more dust flexibility.
    if True:
        model_params['dust_type'] = {
            'N': 1,
            'isfree': False,
            'init': 0,
            'units': 'dust model'
        }
        model_params['dust_index'] = {
            'N': 1,
            'isfree': False,
            'init': -0.7,
            'units': 'power-law index',
            'prior': None
        }

        #model_params['dust1'] = {'N': 1, 'isfree': False, 'init': 0.0, 'prior': None,
        #                         'units': 'optical depth towards young stars',
        #                         'depends_on': dustratio_to_dust1}
        #model_params['dust_ratio'] = {'N': 1, 'isfree': True, 'init': 1.0,
        #                              'prior': priors.TopHat(mini=1.0, maxi=10.0),
        #                              'units': 'dust1/dust2 ratio (optical depth to young stars vs diffuse)'}

    ## Add nebular emission.
    #model_params.update(TemplateLibrary['nebular'])
    ##model_params['add_neb_continuum']['init'] = False
    #model_params['gas_logu']['init'] = -1.0 # harder radiation field [default is -2.0]

    # Fixed redshift.
    model_params['zred']['init'] = obs['redshift']
    model_params['zred']['isfree'] = False

    # Change the IMF from Kroupa to Salpeter.
    model_params['imf_type']['init'] = 0

    # Now instantiate the model using this new dictionary of parameter specifications
    model = SedModel(model_params)
    if verbose:
        print(model)

    return model
Beispiel #12
0
def build_model(object_redshift=None,
                ldist=10.0,
                fixed_metallicity=None,
                add_duste=False,
                **extras):
    """Build a prospect.models.SedModel object
    
    :param object_redshift: (optional, default: None)
        If given, produce spectra and observed frame photometry appropriate 
        for this redshift. Otherwise, the redshift will be zero.
        
    :param ldist: (optional, default: 10)
        The luminosity distance (in Mpc) for the model.  Spectra and observed 
        frame (apparent) photometry will be appropriate for this luminosity distance.
        
    :param fixed_metallicity: (optional, default: None)
        If given, fix the model metallicity (:math:`log(Z/Z_sun)`) to the given value.
        
    :param add_duste: (optional, default: False)
        If `True`, add dust emission and associated (fixed) parameters to the model.
        
    :returns model:
        An instance of prospect.models.SedModel
    """

    # Get (a copy of) one of the prepackaged model set dictionaries.
    # This is, somewhat confusingly, a dictionary of dictionaries, keyed by parameter name
    model_params = TemplateLibrary["parametric_sfh"]

    # Now add the lumdist parameter by hand as another entry in the dictionary.
    # This will control the distance since we are setting the redshift to zero.
    # In `build_obs` above we used a distance of 10Mpc to convert from absolute to apparent magnitudes,
    # so we use that here too, since the `maggies` are appropriate for that distance.
    model_params["lumdist"] = {
        "N": 1,
        "isfree": False,
        "init": ldist,
        "units": "Mpc"
    }

    # Let's make some changes to initial values appropriate for our objects and data
    model_params["zred"]["init"] = 0.0
    model_params["dust2"]["init"] = 0.05
    model_params["logzsol"]["init"] = -0.5
    model_params["tage"]["init"] = 13.
    model_params["mass"]["init"] = 1e8

    # These are dwarf galaxies, so lets also adjust the metallicity prior,
    # the tau parameter upward, and the mass prior downward
    model_params["dust2"]["prior"] = priors.TopHat(mini=0.0, maxi=2.0)
    model_params["tau"]["prior"] = priors.LogUniform(mini=1e-1, maxi=1e2)
    model_params["mass"]["prior"] = priors.LogUniform(mini=1e6, maxi=1e10)

    # If we are going to be using emcee, it is useful to provide a
    # minimum scale for the cloud of walkers (the default is 0.1)
    model_params["mass"]["disp_floor"] = 1e6
    model_params["tau"]["disp_floor"] = 1.0
    model_params["tage"]["disp_floor"] = 1.0

    # Change the model parameter specifications based on some keyword arguments
    if fixed_metallicity is not None:
        # make it a fixed parameter
        model_params["logzsol"]["isfree"] = False
        #And use value supplied by fixed_metallicity keyword
        model_params["logzsol"]['init'] = fixed_metallicity

    if object_redshift is not None:
        # make sure zred is fixed
        model_params["zred"]['isfree'] = False
        # And set the value to the object_redshift keyword
        model_params["zred"]['init'] = object_redshift

    if add_duste:
        # Add dust emission (with fixed dust SED parameters)
        # Since `model_params` is a dictionary of parameter specifications,
        # and `TemplateLibrary` returns dictionaries of parameter specifications,
        # we can just update `model_params` with the parameters described in the
        # pre-packaged `dust_emission` parameter set.
        model_params.update(TemplateLibrary["dust_emission"])

    # Now instantiate the model object using this dictionary of parameter specifications
    model = SedModel(model_params)

    return model
Beispiel #13
0
 def build_model(self, model=None, templates=None, verbose=False, describe=False):
     """
     Build the model parameters to fit on measurements.
     
     Parameters
     ----------
     templates : [string or list(string) or None]
         Prospector prepackaged parameter set(s) to load.
         Can be one template, or a list.
         Default is None.
     
     Options
     -------
     model :  [prospect.models.sedmodel.SedModel or dict or list or None]
         Can load an already existing prospector compatible 'model' SedModel.
         Can update a SedModel compatible 'model' dictionary before to create the SedModel on it.
         Default is None.
     
     verbose : [bool]
         If True, print the built model.
         Default is False.
     
     describe : [bool]
         If True, print the description for any used SED model template and not native prior.
         Default is False.
     
     
     Returns
     -------
     Void
     """
     from prospect.models.sedmodel import SedModel
     from prospect.models.templates import TemplateLibrary
     
     if type(model) is SedModel:
         self._model = model
         return
     
     if describe:
         self.describe_templates(templates=templates)
     
     _model = {} if model is None else model
     if isinstance(_model, list):
         _model = {_p["name"]:_p for _p in _model}
     for _t in np.atleast_1d(templates):
         if _t in TemplateLibrary._descriptions.keys():
             _model.update(TemplateLibrary[_t])
     _describe_priors = []
     for _p, _pv in _model.items():
         if "prior" in _pv.keys() and type(_pv["prior"]) == dict:
             _describe_priors.append(_pv["prior"])
             _pv["prior"] = self.build_prior(_pv["prior"])
     if describe and len(_describe_priors) > 0:
         self.describe_priors(_describe_priors)
     
     if self.has_z():
         _model["zred"].update({"init":self.obs["zspec"], "isfree":False})
     else:
         _model["zred"].update({"isfree":True})
     
     if verbose:
         print(tools.get_box_title(title="Built model", box="\n#=#\n#   {}   #\n#=#\n"))
         pprint(_model)
     
     self._model = SedModel(_model)
Beispiel #14
0
def build_model_un(object_redshift=None,
                   fixed_metallicity=None,
                   add_duste=False,
                   **extras):

    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.models import priors
    from prospect.models import transforms
    from prospect.models.templates import adjust_continuity_agebins
    from astropy.cosmology import WMAP9 as cosmos
    import prospect
    # Get (a copy of) one of the prepackaged model set dictionaries.
    # Get the 2018 prospector-alpha model manually
    model_params = (TemplateLibrary["continuity_sfh"])
    model_params.update(TemplateLibrary["dust_emission"])
    model_params.update(TemplateLibrary["nebular"])
    model_params.update(TemplateLibrary["agn"])

    # Set the dust and agn emission free
    model_params["fagn"]["isfree"] = True
    model_params["agn_tau"]["isfree"] = True

    # Complexify the dust attenuation
    model_params["dust_type"] = {
        "N": 1,
        "isfree": False,
        "init": 4,
        "units": "FSPS index"
    }
    model_params["dust2"]["prior"] = priors.TopHat(mini=0.0, maxi=4.0)
    model_params["dust1"] = {
        "N": 1,
        "isfree": False,
        'depends_on': transforms.dustratio_to_dust1,
        "init": 0.0,
        "units": "optical depth towards young stars"
    }

    model_params["dust_ratio"] = {
        "N": 1,
        "isfree": True,
        "init": 1.0,
        "units": "ratio of birth-cloud to diffuse dust",
        "prior": priors.ClippedNormal(mini=0.0, maxi=2.0, mean=1.0, sigma=0.3)
    }

    model_params["dust_index"] = {
        "N": 1,
        "isfree": True,
        "init": 0.0,
        "units": "power-law multiplication of Calzetti",
        "prior": priors.TopHat(mini=-2.0, maxi=0.5)
    }
    # in Gyr
    tuniv = cosmos.age(object_redshift).value
    model_params = adjust_continuity_agebins(model_params, tuniv)

    model_params["duste_qpah"]["isfree"] = False
    model_params["duste_umin"]["isfree"] = False
    model_params["duste_gamma"]["isfree"] = False
    model_params["duste_qpah"]["init"] = 2.0
    model_params["duste_umin"]["init"] = 1.0
    model_params["duste_gamma"]["init"] = 0.01
    model_params["duste_qpah"]["prior"] = priors.TopHat(mini=0.0, maxi=7.0)
    model_params["duste_umin"]["prior"] = priors.TopHat(mini=0.1, maxi=25.0)
    model_params["duste_gamma"]["prior"] = priors.TopHat(mini=0.0, maxi=1.0)
    model_params["duste_qpah"]["disp_floor"] = 3.0
    model_params["duste_umin"]["disp_floor"] = 4.5
    model_params["duste_gamma"]["disp_floor"] = 0.15
    model_params["duste_qpah"]["init_disp"] = 3.0
    model_params["duste_umin"]["init_disp"] = 5.0
    model_params["duste_gamma"]["init_disp"] = 0.2
    model_params['gas_logz']["isfree"] = True
    model_params['gas_logz']["init"] = 0.0
    model_params['gas_logz']["prior"] = priors.TopHat(mini=-2.0, maxi=0.5)
    model_params['gas_logu']["isfree"] = False
    model_params['gas_logu']["init"] = -1.0
    model_params['gas_logu']["prior"] = priors.TopHat(mini=-4.0, maxi=-1.0)
    # Now add the lumdist parameter by hand as another entry in the dictionary.
    # This will control the distance since we are setting the redshift to zero.
    # In `build_obs` above we used a distance of 10pc to convert from absolute to apparent magnitudes,
    # so we use that here too, since the `maggies` are appropriate for that distance.

    # Let's make some changes to values appropriate for our objects and data

    model_params["logzsol"]["prior"] = priors.TopHat(mini=-2.0, maxi=0.2)
    model_params["dust_index"]["prior"] = priors.TopHat(mini=-2.2, maxi=0.4)
    model_params["agn_tau"]["prior"] = priors.LogUniform(mini=5, maxi=1.5e2)
    model_params["dust2"]["prior"] = priors.TopHat(mini=1e-6, maxi=3.0)

    model_params['dust_type']['init'] = 0
    model_params['fagn']['init'] = 0.5
    model_params['dust2']['init'] = 0.1
    # If we are going to be using emcee, it is useful to provide a
    # minimum scale for the cloud of walkers (the default is 0.1)
    model_params["agn_tau"]["disp_floor"] = 1
    model_params["dust2"]["disp_floor"] = 1e-2
    model_params["logzsol"]["disp_floor"] = 1e-3
    model_params['fagn']['disp_floor'] = 1e-3
    model_params['dust_index']['disp_floor'] = 1e-3

    # Change the model parameter specifications based on some keyword arguments
    if object_redshift is not None:
        # make sure zred is fixed
        model_params["zred"]['isfree'] = False
        # And set the value to the object_redshift keyword
        model_params["zred"]['init'] = object_redshift

    # Change fit orders
    tparams = {}
    parnames = [m for m in model_params]
    fit_order = [
        'logmass', 'dust_index', 'dust2', 'logzsol', 'fagn', 'dust_ratio'
    ]
    for param in fit_order:
        tparams[param] = model_params[param]
    for param in model_params:
        if param not in fit_order:
            tparams[param] = model_params[param]
    model_params = tparams
    ########
    model_params['add_neb_emission']['init'] = False
    ########
    model_params['sfh']['init'] = 0
    # Now instantiate the model object using this dictionary of parameter specifications
    model = SedModel(model_params)
    #print(model_params['agebins'])
    return model
Beispiel #15
0
def build_model(redshift,
                fixed_metallicity=None,
                dust=False,
                agn_mass=None,
                agn_eb_v=None,
                agn_torus_mass=None,
                igm_absorbtion=True,
                inclination=True,
                **extras):
    """Build a prospect.models.SedModel object
    
    :param object_redshift: (optional, default: None)
        If given, produce spectra and observed frame photometry appropriate 
        for this redshift. Otherwise, the redshift will be zero.
        
    :param ldist: (optional, default: 10)
        The luminosity distance (in Mpc) for the model.  Spectra and observed 
        frame (apparent) photometry will be appropriate for this luminosity distance.
        
    :param fixed_metallicity: (optional, default: None)
        If given, fix the model metallicity (:math:`log(Z/Z_sun)`) to the given value.
        
    :param dust: (optional, default: False)
        If `True`, add dust emission and associated (fixed) parameters to the model.
        
    :returns model:
        An instance of prospect.models.SedModel
    """
    logging.debug(redshift)
    logging.debug(fixed_metallicity)
    logging.debug(dust)
    logging.debug(agn_mass)
    logging.debug(agn_eb_v)
    logging.debug(agn_torus_mass)
    logging.debug(igm_absorbtion)
    logging.debug(extras)
    # TODO increase galaxy extinction to 0.6

    # Get (a copy of) one of the prepackaged model set dictionaries.
    # This is, somewhat confusingly, a dictionary of dictionaries, keyed by parameter name
    model_params = TemplateLibrary["parametric_sfh"]  # add sfh and tau
    # dust2 init -.6, uniform [0, 2] uniform prior
    # delay-tau model with tau [0.1, 30] log-uniform prior
    # tage (burst start?) init 1, uniform (tophat) [0.001, 13.8]

    model_params['dust_type'] = {
        "N": 1,
        "isfree": False,
        "init": 2
    }  # Calzetti, as opposed to 0 for power law
    # fixed: Kroupa IMF

    # mass: lower 10^9, upper 10^12
    # TODO set to logzsol=0 fixed, make this assumption
    # dust (optical depth at 5500A): init=0.6, prior [0, 2], hopefully this is okay?

    # sfh: 'delay-tau' is 4
    # _parametric_["tau"]  = {"N": 1, "isfree": True,
    #                     "init": 1, "units": "Gyr^{-1}",
    #                     "prior": priors.LogUniform(mini=0.1, maxi=30)}

    # my convention: if None, don't model. if value, model as fixed to value. If True, model as free.

    # Change the model parameter specifications based on some keyword arguments
    if fixed_metallicity is None:
        logging.info('Using free metallicity')
        model_params['logzsol']['isfree'] = True
    else:
        # make it a fixed parameter
        logging.info(f'Using fixed metallicity of {fixed_metallicity}')
        model_params["logzsol"]["isfree"] = False
        #And use value supplied by fixed_metallicity keyword
        model_params["logzsol"]['init'] = fixed_metallicity

    if dust:
        # Add dust emission (with fixed dust SED parameters)
        logging.info('Including dust emission fixed parameters')
        model_params.update(TemplateLibrary["dust_emission"])
    else:
        logging.warning('Not using dust emission')

    if igm_absorbtion:
        logging.info('Using fixed IGM absorption (0.1 by default)')
        # Add (fixed) IGM absorption parameters: madau attenuation (fixed to 1.)
        model_params.update(TemplateLibrary["igm"])
    else:
        logging.warning('Not using IGM absorbtion')

    if redshift is None:
        raise ValueError('Redshift set to None - must be included in model!')
    if isinstance(redshift, float):
        logging.info('Using fixed redshift of {}'.format(redshift))
        # Set redshift as fixed to value
        model_params["zred"]['isfree'] = False
        model_params["zred"]['init'] = redshift
    else:
        logging.info('Using free redshift')
        # Set redshift as free
        assert redshift == True  # not just truthy, but exactly True/bool
        model_params["zred"]['isfree'] = True

    if agn_mass is None:
        logging.warning('No AGN mass supplied - AGN not modelled')
        # finish early
        model = SedModel(model_params)
        return model
    elif isinstance(agn_mass, float):
        logging.info('AGN mass will be fixed at {}'.format(agn_mass))
        model_params['agn_mass'] = {
            'N': 1,
            'isfree': False,
            'init': agn_mass
        }  # units?
    else:
        assert agn_mass == True
        logging.info('AGN mass will be free parameter')
        model_params['agn_mass'] = {
            'N': 1,
            'isfree': True,
            'init': 1.,
            'prior': priors.LogUniform(mini=1e-7, maxi=15)
        }
    if agn_eb_v is None:
        logging.warning('AGN extinction not modelled')
    else:
        assert agn_mass

    if isinstance(agn_eb_v, float):
        logging.info('Using fixed agn_eb_v of {}'.format(agn_eb_v))
        assert agn_mass
        model_params['agn_eb_v'] = {
            "N": 1,
            "isfree": False,
            "init": agn_eb_v,
            "units": "",
            'prior': priors.TopHat(mini=0., maxi=0.5)
        }
    elif agn_mass == True:
        logging.info('Using free agn_eb_v')
        model_params['agn_eb_v'] = {
            "N": 1,
            "isfree": True,
            "init": 0.1,
            "units": "",
            'prior': priors.TopHat(mini=0., maxi=0.5)
        }
    else:
        logging.warning('Not modelling AGN disk')

    if agn_torus_mass is None:
        logging.warning('Not modelling AGN torus')
    elif isinstance(agn_torus_mass, float):
        logging.info('Using fixed obscured torus of {}'.format(agn_torus_mass))
        model_params['agn_torus_mass'] = {
            "N": 1,
            "isfree": False,
            "init": agn_torus_mass,
            "units": "",
            'prior': priors.LogUniform(mini=1e-7, maxi=15)
        }
    else:
        logging.info('Using free obscured torus')
        model_params['agn_torus_mass'] = {
            "N": 1,
            "isfree": True,
            "init": .1,
            "units": "",
            'prior': priors.LogUniform(mini=1e-7, maxi=15)
        }

    if inclination is None:
        raise ValueError(
            'No model inclination preference supplied - set float to fix, or set True to leave free, but set something!'
        )
    elif isinstance(inclination, float):
        logging.info('Using fixed inclination of {}'.format(inclination))
        model_params['inclination'] = {
            "N": 1,
            "isfree": False,
            "init": inclination,
            "units": "",
            'prior': priors.TopHat(mini=0., maxi=90.)
        }
    else:
        logging.info('Using free inclination')
        model_params['inclination'] = {
            "N": 1,
            "isfree": True,
            "init": 60.,
            "units": "",
            'prior': priors.TopHat(mini=0., maxi=90.)
        }

    # explicitly no FSPS dusty torus
    # model_params['fagn'] = None
    # model_params['agn_tau'] = None

    # Now instantiate the model object using this dictionary of parameter specifications
    model = SedModel(model_params)

    return model
Beispiel #16
0
def build_model(binNum=0,
                fit_metallicity=1,
                fit_redshift=1,
                infile=None,
                add_neb=0,
                metalfile=None,
                cluster=None,
                ID=0,
                **extras):

    import numpy as np
    from astropy.table import Table
    from prospect.models.priors import ClippedNormal, LogUniform, TopHat
    from prospect.models.sedmodel import SedModel
    from prospect.models.templates import TemplateLibrary
    from prospect.sources.constants import cosmo

    table = Table.read(infile)
    zobs = table['z'][binNum]
    max_age = cosmo.age(zobs).value

    sma, smb = table['sma'][binNum], table['smb'][binNum]
    R_e, width = table['R_e'][binNum], table['width'][binNum]
    radius = (sma - width) * np.sqrt(smb / sma) / R_e

    metallicities = Table.read(metalfile)
    idx = np.where((metallicities['cluster'] == cluster)
                   & (metallicities['ID'] == ID))[0][0]
    central_metallicity = metallicities['centrallogZ'][idx]
    sigma_metallicity = metallicities['sigma'][idx]
    init_metallicity = central_metallicity - 0.1 * radius

    model_params = TemplateLibrary['parametric_sfh']  # delay-tau model

    model_params['zred']['init'] = zobs
    model_params['zred']['isfree'] = bool(fit_redshift)
    model_params['zred']['prior'] = TopHat(mini=zobs - 0.01, maxi=zobs + 0.01)

    model_params['mass']['init'] = 1e7
    model_params['mass']['prior'] = LogUniform(mini=1e5, maxi=1e10)

    model_params['logzsol']['init'] = init_metallicity
    model_params['logzsol']['isfree'] = bool(fit_metallicity)
    model_params['logzsol']['prior'] = ClippedNormal(mean=init_metallicity,
                                                     sigma=sigma_metallicity,
                                                     mini=-2,
                                                     maxi=0.2)

    model_params['dust2']['init'] = 0.3
    model_params['dust2']['prior'] = TopHat(mini=0.0, maxi=2.0)

    model_params['tage']['init'] = 6.24
    model_params['tage']['prior'] = TopHat(mini=0.001, maxi=max_age)

    model_params['tau']['init'] = 0.29
    model_params['tau']['prior'] = LogUniform(mini=0.1, maxi=10)

    model_params['imf_type']['init'] = 1  # Chabrier (2003) IMF
    model_params['dust_type']['init'] = 1  # Cardelli+ (1989) MW extinction

    if add_neb:
        model_params.update(TemplateLibrary['nebular'])

    model = SedModel(model_params)

    return model