예제 #1
0
def build_model(fixed_metallicity=None, luminosity_distance=None, **extras):
    """Construct a model.  This method defines a number of parameter
    specification dictionaries and uses them to initialize a
    `models.sedmodel.SedModel` object.
    :param object_redshift:
        If given, given the model redshift to this value.
    :param add_dust: (optional, default: False)
        Switch to add (fixed) parameters relevant for dust emission.
    :param add_neb: (optional, default: False)
        Switch to add (fixed) parameters relevant for nebular emission, and
        turn nebular emission on.
    :param luminosity_distance: (optional)
        If present, add a `"lumdist"` parameter to the model, and set it's
        value (in Mpc) to this.  This allows one to decouple redshift from
        distance, and fit, e.g., absolute magnitudes (by setting
        luminosity_distance to 1e-5 (10pc))
    """
    from prospect.models.templates import TemplateLibrary, adjust_continuity_agebins
    from prospect.models import priors, sedmodel, transforms

    model_params = TemplateLibrary['continuity_sfh']

    ### BASIC PARAMETERS ###

    model_params["imf_type"] = {
        'N': 1,
        'isfree': False,
        'init': 1,  #1=Chabrier
        'prior': None
    }

    model_params['zred'] = {
        'N': 1,
        'isfree': True,
        'init': obj_red,
        "prior": priors.TopHat(mini=obj_red - 0.05, maxi=obj_red + 0.05)
    }

    model_params['add_igm_absorption'] = {
        'N': 1,
        'isfree': False,
        'init': 1,
        'units': None,
        'prior': None
    }

    model_params['add_agb_dust_model'] = {
        'N': 1,
        'isfree': False,
        'init': 1,
        'units': None,
        'prior': None
    }

    # model_params['pmetals'] = {'N': 1,
    #                             'isfree': False,
    #                             'init': -99,
    #                             'units': '',
    #                             'prior': priors.TopHat(mini=-3, maxi=-1)}

    ### SFH ###

    tuniv = WMAP9.age(obj_red).value
    model_params = adjust_continuity_agebins(model_params,
                                             tuniv=tuniv,
                                             nbins=7)

    ### DUST ABSORPTION ###

    model_params['dust_type'] = {
        'N': 1,
        'isfree': False,
        'init': 4,  #4=Kriek & Conroy
        'units': 'index',
        'prior': None
    }

    model_params['dust1'] = {
        'N': 1,
        'isfree': False,
        'depends_on': transforms.dustratio_to_dust1,
        'init': 0.,
        'units': 'optical depth towards young stars'
    }

    model_params['dust_ratio'] = {
        'N': 1,
        'isfree': True,
        'init': 1.0,
        'init_disp': 0.8,
        'disp_floor': 0.8,
        '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['dust2'] = {
        'N': 1,
        'isfree': True,
        'init': 1.0,
        'init_disp': 0.25,
        'disp_floor': 0.15,
        'units': 'optical depth at 5500AA',
        'prior': priors.ClippedNormal(mini=0.0, maxi=4.0, mean=0.3, sigma=1)
    }

    model_params['dust_index'] = {
        'N': 1,
        'isfree': True,
        'init': 0.0,
        'init_disp': 0.25,
        'disp_floor': 0.15,
        'units': 'power-law multiplication of Calzetti',
        'prior': priors.TopHat(mini=-2.0, maxi=0.5)
    }

    ### DUST EMISSION ###

    model_params.update(TemplateLibrary["dust_emission"])

    ### NEBULAR EMISSION ###

    model_params['add_neb_emission'] = {
        'N': 1,
        'isfree': False,
        'init': True,
        'prior': None
    }

    model_params['add_neb_continuum'] = {
        'N': 1,
        'isfree': False,
        'init': True,
        'prior': None
    }

    model_params['gas_logz'] = {
        'N': 1,
        'isfree': True,
        'init': 0.0,
        'units': r'log Z/Z_\odot',
        'prior': priors.TopHat(mini=-2.0, maxi=0.5)
    }

    model_params['gas_logu'] = {
        'N': 1,
        'isfree': True,
        'init': -1.0,
        'units': '',
        'prior': priors.TopHat(mini=-4.0, maxi=-1.0)
    }

    ### CALIBRATION ###
    model_params['polyorder'] = {'N': 1, 'init': 10, 'isfree': False}

    model_params['spec_norm'] = {
        'N': 1,
        'init': 1.0,
        'isfree': True,
        'prior': priors.Normal(sigma=0.2, mean=1.0),
        'units': 'f_true/f_obs'
    }

    model_params['spec_jitter'] = {
        "N": 1,
        "isfree": True,
        "init": 1.0,
        "prior": priors.TopHat(mini=0., maxi=4.0)
    }

    model_params['f_outlier_spec'] = {
        "N": 1,
        "isfree": True,
        "init": 0.01,
        "prior": priors.TopHat(mini=1e-5, maxi=0.5)
    }

    model_params['nsigma_outlier_spec'] = {
        "N": 1,
        "isfree": False,
        "init": 5.0
    }

    ### SMOOTHING ###

    model_params.update(TemplateLibrary["spectral_smoothing"])
    model_params["sigma_smooth"]["prior"] = priors.TopHat(mini=150, maxi=250)

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

    return model
예제 #2
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
예제 #3
0
def build_model(objid=1,
                non_param_sfh=False,
                dirichlet_sfh=False,
                add_duste=False,
                add_neb=False,
                add_agn=False,
                switch_off_mix=False,
                marginalize_neb=True,
                n_bins_sfh=8,
                use_eline_prior=False,
                add_jitter=False,
                fit_continuum=False,
                switch_off_phot=False,
                switch_off_spec=False,
                fixed_dust=False,
                **extras):
    """Construct a model.  This method defines a number of parameter
    specification dictionaries and uses them to initialize a
    `models.sedmodel.SedModel` object.
    :param object_redshift:
        If given, given the model redshift to this value.
    :param add_dust: (optional, default: False)
        Switch to add (fixed) parameters relevant for dust emission.
    :param add_neb: (optional, default: False)
        Switch to add (fixed) parameters relevant for nebular emission, and
        turn nebular emission on.
    """
    # read in data table
    obs = build_obs(objid=objid)

    # get SFH template
    if non_param_sfh and not dirichlet_sfh:
        model_params = TemplateLibrary["continuity_sfh"]
    elif dirichlet_sfh:
        model_params = TemplateLibrary["dirichlet_sfh"]
    else:
        model_params = TemplateLibrary["parametric_sfh"]

    # fit for redshift
    # use catalog value as center of the prior
    model_params["zred"]['isfree'] = True
    model_params["zred"]["init"] = obs['redshift']
    model_params["zred"]["prior"] = priors.TopHat(mini=obs['redshift'] - 0.005,
                                                  maxi=obs['redshift'] + 0.005)

    # get SFH template
    if non_param_sfh:
        t_univ = cosmo.age(obs['redshift']).value
        tbinmax = 0.95 * t_univ * 1e9
        lim1, lim2, lim3, lim4 = 7.4772, 8.0, 8.5, 9.0
        agelims = [0, lim1, lim2, lim3] + np.log10(
            np.linspace(10**lim4, tbinmax,
                        n_bins_sfh - 4)).tolist() + [np.log10(t_univ * 1e9)]
        if dirichlet_sfh:
            model_params = adjust_dirichlet_agebins(model_params,
                                                    agelims=agelims)
            model_params["total_mass"]["prior"] = priors.LogUniform(mini=3e9,
                                                                    maxi=1e12)
        else:
            model_params = adjust_continuity_agebins(model_params,
                                                     tuniv=t_univ,
                                                     nbins=n_bins_sfh)
            agebins = np.array([agelims[:-1], agelims[1:]])
            model_params['agebins']['init'] = agebins.T
            model_params["logmass"]["prior"] = priors.TopHat(mini=9.5,
                                                             maxi=12.0)
    else:
        model_params["tau"]["prior"] = priors.LogUniform(mini=1e-1, maxi=10)
        model_params["tage"]["prior"] = priors.TopHat(
            mini=1e-3, maxi=cosmo.age(obs['redshift']).value)
        model_params["mass"]["prior"] = priors.LogUniform(mini=3e9, maxi=1e12)

    # metallicity (no mass-metallicity prior yet!)
    if fixed_dust:
        model_params["logzsol"]["prior"] = priors.ClippedNormal(mini=-1.0,
                                                                maxi=0.19,
                                                                mean=0.0,
                                                                sigma=0.15)
    else:
        model_params["logzsol"]["prior"] = priors.TopHat(mini=-1.0, maxi=0.19)

    # complexify the dust
    if fixed_dust:
        model_params['dust_type']['init'] = 2
        model_params["dust2"]["prior"] = priors.ClippedNormal(mini=0.0,
                                                              maxi=4.0,
                                                              mean=0.3,
                                                              sigma=1)
        model_params['dust1'] = {
            "N": 1,
            "isfree": False,
            "init": 0.0,
            "units": "optical depth towards young stars",
            "prior": None
        }
    else:
        model_params['dust_type']['init'] = 4
        model_params["dust2"]["prior"] = priors.ClippedNormal(mini=0.0,
                                                              maxi=4.0,
                                                              mean=0.3,
                                                              sigma=1)
        model_params["dust_index"] = {
            "N": 1,
            "isfree": True,
            "init": 0.0,
            "units": "power-law multiplication of Calzetti",
            "prior": priors.TopHat(mini=-1.0, maxi=0.4)
        }

        def to_dust1(dust1_fraction=None, dust1=None, dust2=None, **extras):
            return (dust1_fraction * dust2)

        model_params['dust1'] = {
            "N": 1,
            "isfree": False,
            'depends_on': to_dust1,
            "init": 0.0,
            "units": "optical depth towards young stars",
            "prior": None
        }
        model_params['dust1_fraction'] = {
            'N': 1,
            'isfree': True,
            'init': 1.0,
            'prior': priors.ClippedNormal(mini=0.0,
                                          maxi=2.0,
                                          mean=1.0,
                                          sigma=0.3)
        }

    # velocity dispersion
    model_params.update(TemplateLibrary['spectral_smoothing'])
    model_params["sigma_smooth"]["prior"] = priors.TopHat(mini=40.0,
                                                          maxi=400.0)

    # Change the model parameter specifications based on some keyword arguments
    if add_duste:
        # Add dust emission (with fixed dust SED parameters)
        model_params.update(TemplateLibrary["dust_emission"])
        model_params['duste_gamma']['isfree'] = True
        model_params['duste_gamma']['init'] = 0.01
        model_params['duste_gamma']['prior'] = priors.LogUniform(mini=1e-4,
                                                                 maxi=0.1)
        model_params['duste_qpah']['isfree'] = True
        model_params['duste_qpah']['prior'] = priors.TopHat(mini=0.5, maxi=7.0)
        model_params['duste_umin']['isfree'] = True
        model_params['duste_umin']['init'] = 1.0
        model_params['duste_umin']['prior'] = priors.ClippedNormal(mini=0.1,
                                                                   maxi=15.0,
                                                                   mean=2.0,
                                                                   sigma=1.0)

    if add_agn:
        # Allow for the presence of an AGN in the mid-infrared
        model_params.update(TemplateLibrary["agn"])
        model_params['fagn']['isfree'] = True
        model_params['fagn']['prior'] = priors.LogUniform(mini=1e-5, maxi=3.0)
        model_params['agn_tau']['isfree'] = True
        model_params['agn_tau']['prior'] = priors.LogUniform(mini=5.0,
                                                             maxi=150.)

    if add_neb:
        # Add nebular emission
        model_params.update(TemplateLibrary["nebular"])
        model_params['gas_logu']['isfree'] = True
        model_params['gas_logu']['init'] = -2.0
        model_params['gas_logz']['isfree'] = True
        _ = model_params["gas_logz"].pop("depends_on")
        model_params['nebemlineinspec'] = {
            'N': 1,
            'isfree': False,
            'init': False
        }

        if marginalize_neb:
            model_params.update(TemplateLibrary['nebular_marginalization'])
            #model_params.update(TemplateLibrary['fit_eline_redshift'])
            model_params['eline_prior_width']['init'] = 3.0
            model_params['use_eline_prior']['init'] = use_eline_prior

            # only marginalize over a few (strong) emission lines
            if True:
                #SPS_HOME = os.getenv('SPS_HOME')
                #emline_info = np.genfromtxt(SPS_HOME + '/data/emlines_info.dat', dtype=[('wave', 'f8'), ('name', 'S20')], delimiter=',')
                to_fit = [
                    '[OII]3726', '[OII]3729', 'H 3798', 'H 3835', 'H 3889',
                    'H 3970', '[NeIII]3870', 'H delta 4102', 'H gamma 4340',
                    '[OIII]4364', 'H beta 4861', '[OIII]4960', '[OIII]5007',
                    '[NII]6549', 'H alpha 6563', '[NII]6585'
                ]
                #idx = np.array([1 if name in to_fit else 0 for name in emline_info['name']], dtype=bool)
                model_params['lines_to_fit']['init'] = to_fit

            # model_params['use_eline_prior']['init'] = False
        else:
            model_params['nebemlineinspec']['init'] = True

    # This removes the continuum from the spectroscopy. Highly recommend
    # using when modeling both photometry & spectroscopy
    if fit_continuum:
        # order of polynomial that's fit to spectrum
        polyorder_estimate = int(
            np.clip(
                np.round((np.min([7500 * (obs['redshift'] + 1), 9150.0]) -
                          np.max([3525.0 * (obs['redshift'] + 1), 6000.0])) /
                         (obs['redshift'] + 1) * 100), 10, 30))
        model_params['polyorder'] = {
            'N': 1,
            'init': polyorder_estimate,
            'isfree': False
        }
        # fit for normalization of spectrum
        # model_params['spec_norm'] = {'N': 1,
        #                              'init': 0.8,
        #                              'isfree': True,
        #                              'prior': priors.Normal(sigma=0.2, mean=0.8),
        #                              'units': 'f_true/f_obs'}

    # This is a pixel outlier model. It helps to marginalize over
    # poorly modeled noise, such as residual sky lines or
    # even missing absorption lines
    if not switch_off_mix:
        model_params['f_outlier_spec'] = {
            "N": 1,
            "isfree": True,
            "init": 0.01,
            "prior": priors.TopHat(mini=1e-5, maxi=0.5)
        }
        model_params['nsigma_outlier_spec'] = {
            "N": 1,
            "isfree": False,
            "init": 50.0
        }

    # This is a multiplicative noise inflation term. It inflates the noise in
    # all spectroscopic pixels as necessary to get a good fit.
    if add_jitter:
        model_params['spec_jitter'] = {
            "N": 1,
            "isfree": True,
            "init": 1.0,
            "prior": priors.TopHat(mini=1.0, maxi=5.0)
        }

    # Now instantiate the model using this new dictionary of parameter specifications
    model = PolySpecModel(model_params)

    return model