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
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
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