def build_model(**kwargs): from prospect.models.templates import TemplateLibrary from prospect.models import priors, sedmodel model_params = TemplateLibrary["parametric_sfh"] model_params.update(TemplateLibrary["dust_emission"]) #fixed delayed-tau SFH model_params['tau']['isfree'] = False model_params['tau']['init'] = 1.0 model_params['sf_start'] = { "N": 1, "isfree": False, "init": 1.0, "units": "start of SF, Gyr" } model_params["lumdist"] = { "N": 1, "isfree": False, "init": 1.0e-5, "units": "Mpc" } model_params['tage']['prior'] = priors.TopHat(mini=1.0, maxi=10.0) model_params['tage']['init'] = 5.0 model_params['mass']['prior'] = priors.TopHat(mini=1e7, maxi=1e13) model_params['logzsol']['init'] = 0.2 model_params['logzsol']['isfree'] = True model_params['logzsol']['prior'] = priors.ClippedNormal(mini=-1.5, maxi=0.5, mean=0.0, sigma=0.3) #dust emission model_params['duste_gamma']['init'] = 0.01 model_params['duste_qpah']['init'] = 3.5 model_params['duste_umin']['init'] = 1.0 model_params = model_library(model_params, int(sys.argv[1]), False) model = sedmodel.SedModel(model_params) return model
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
def loss_function(args): tau_mean, const_mean, tage_mean, fburst_mean, tburst_mean, logzsol_mean, gas_logz_mean, gas_logu_mean,\ tau_sig, const_sig, tage_sig, fburst_sig, tburst_sig, logzsol_sig, gas_logz_sig, gas_logu_sig = args set_size = 3000 tau_arr = [ float( priors.ClippedNormal(mean=abs(tau_mean), sigma=abs(tau_sig), mini=1.0, maxi=8.0).sample()) for _ in range(set_size) ] const_arr = [ float( priors.ClippedNormal(mean=abs(const_mean), sigma=abs(const_sig), mini=0.0, maxi=0.5).sample()) for _ in range(set_size) ] tage_arr = [ float( priors.ClippedNormal(mean=abs(tage_mean), sigma=abs(tage_sig), mini=1.0, maxi=11.0).sample()) for _ in range(set_size) ] fburst_arr = [ float( priors.ClippedNormal(mean=abs(fburst_mean), sigma=abs(fburst_sig), mini=0.0, maxi=0.8).sample()) for _ in range(set_size) ] tburst_arr = [ float( priors.ClippedNormal(mean=abs(tburst_mean), sigma=abs(tburst_sig), mini=0.0, maxi=abs(tage_mean)).sample()) for _ in range(set_size) ] logzsol_arr = [ float( priors.ClippedNormal(mean=-1 * abs(logzsol_mean), sigma=abs(logzsol_sig), mini=-1.5, maxi=0.0).sample()) for _ in range(set_size) ] gas_logz_arr = [ float( priors.ClippedNormal(mean=-1 * abs(gas_logz_mean), sigma=abs(gas_logz_sig), mini=-1.5, maxi=0.0).sample()) for _ in range(set_size) ] gas_logu_arr = [ float( priors.ClippedNormal(mean=-1 * abs(gas_logu_mean), sigma=abs(gas_logu_sig), mini=-4.0, maxi=-1.0).sample()) for _ in range(set_size) ] # Fix the fburst + const > 1 issue for ii in np.arange(len(const_arr)): if const_arr[ii] + fburst_arr[ii] >= 0.95: f_over = (const_arr[ii] + fburst_arr[ii]) - 0.95 if fburst_arr[ii] >= (f_over + 0.01): fburst_arr[ii] = fburst_arr[ii] - (f_over + 0.01) else: const_arr[ii] = const_arr[ii] - (f_over + 0.01) # Fixed the rest dust1_arr = np.full(set_size, 0.1) dust2_arr = np.full(set_size, 0.0) sf_trunc_arr = np.full(set_size, 0.0) # List of model parameters dwarf_sample_parameters = [{ 'dust1': dust1_arr[ii], 'dust2': dust2_arr[ii], 'logzsol': logzsol_arr[ii], 'gas_logz': gas_logz_arr[ii], 'gas_logu': gas_logu_arr[ii], 'const': const_arr[ii], 'tau': tau_arr[ii], 'tage': tage_arr[ii], 'sf_trunc': sf_trunc_arr[ii], 'fburst': fburst_arr[ii], 'tburst': tburst_arr[ii] } for ii in np.arange(set_size)] # Double check for ii, model in enumerate(dwarf_sample_parameters): if model['fburst'] + model['const'] >= 0.99: print(ii, model['fburst'], model['const']) # Initialize the spop model spop_tau = setup_fsps_spop(zcontinuous=1, imf_type=2, sfh=1, dust_type=0, dust_index=-1.3, dust1_index=-1.0) # Get the SDSS filters sdss_bands = fsps.find_filter('SDSS') dwarf_sample_gaussian = generate_dwarf_population(spop_tau, dwarf_sample_parameters, filters=sdss_bands, n_jobs=6) # Measure colors and emission line EWs # - SDSS_EMLINES is a pre-defined dict of emission lines center wavelength and the # wavelength window for measuring EW. # - You can save the results in a numpy array dwarf_sample_table = measure_color_ew(dwarf_sample_gaussian, em_list=SDSS_EMLINES, output=None) bin_size = 200 ur_size = np.linspace(0.0, 2.5, bin_size) ug_size = np.linspace(0.0, 2.0, bin_size) gr_size = np.linspace(-0.1, 0.8, bin_size) gi_size = np.linspace(-0.2, 1.3, bin_size) ha_size = np.linspace(0.0, 3.0, bin_size) hb_size = np.linspace(-0.5, 2.5, bin_size) oiii_size = np.linspace(-1.0, 3.0, bin_size) obs_ur = data_to_distribution( np.asarray(sdss_use['M_u'] - sdss_use['M_r']), ur_size) obs_ug = data_to_distribution( np.asarray(sdss_use['M_u'] - sdss_use['M_g']), ug_size) obs_gr = data_to_distribution( np.asarray(sdss_use['M_g'] - sdss_use['M_r']), gr_size) obs_gi = data_to_distribution( np.asarray(sdss_use['M_g'] - sdss_use['M_i']), gi_size) obs_ha = data_to_distribution(np.log10(abs(sdss_use['H_ALPHA_EQW'])), ha_size) obs_hb = data_to_distribution(np.log10(abs(sdss_use['H_BETA_EQW'])), hb_size) obs_oiii = data_to_distribution(np.log10(abs(sdss_use['OIII_5007_EQW'])), oiii_size) model_ur = data_to_distribution(dwarf_sample_table['ur_color'], ur_size) model_ug = data_to_distribution(dwarf_sample_table['ug_color'], ug_size) model_gr = data_to_distribution(dwarf_sample_table['gr_color'], gr_size) model_gi = data_to_distribution(dwarf_sample_table['gi_color'], gi_size) model_ha = data_to_distribution( np.log10(abs(dwarf_sample_table['ew_halpha'])), ha_size) model_hb = data_to_distribution( np.log10(abs(dwarf_sample_table['ew_hbeta'])), hb_size) model_oiii = data_to_distribution( np.log10(abs(dwarf_sample_table['ew_oiii_5007'])), oiii_size) obs_stack = np.transpose( np.vstack([obs_ur, obs_ug, obs_gr, obs_gi, obs_ha, obs_hb, obs_oiii])) model_stack = np.transpose( np.vstack([ model_ur, model_ug, model_gr, model_gi, model_ha, model_hb, model_oiii ])) total_loss = entropy(obs=obs_stack, model=model_stack) return total_loss
'name': 'dust2', 'N': 1, 'isfree': False, 'init': 0.7, 'init_disp': 0.25, 'disp_floor': 0.15, 'units': '', 'prior': priors.ClippedNormal(mini=0.0, maxi=2.0, mean=0.3, sigma=1) }) model_params.append({ 'name': 'dust_index', 'N': 1, 'isfree': False, 'init': -0.7, 'init_disp': 0.25, 'disp_floor': 0.15, 'units': '', 'prior': priors.TopHat(mini=-1.8, maxi=0.4) }) model_params.append({ 'name': 'dust1_index',
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 loss_function(args): tau_mean, const_mean, tage_mean, fburst_mean, tburst_mean, logzsol_mean, gas_logz_mean, gas_logu_mean = args set_size = 3000 tau_arr = [ float( priors.ClippedNormal(mean=tau_mean, sigma=tau_sig, mini=1.0, maxi=8.0).sample()) for _ in range(set_size) ] const_arr = [ float( priors.ClippedNormal(mean=const_mean, sigma=const_sig, mini=0.0, maxi=0.5).sample()) for _ in range(set_size) ] tage_arr = [ float( priors.ClippedNormal(mean=tage_mean, sigma=tage_sig, mini=1.0, maxi=11.0).sample()) for _ in range(set_size) ] fburst_arr = [ float( priors.ClippedNormal(mean=fburst_mean, sigma=fbust_sig, mini=0.0, maxi=0.8).sample()) for _ in range(set_size) ] tburst_arr = [ float( priors.ClippedNormal(mean=tburst_mean, sigma=tburst_sig, mini=0.0, maxi=8.0).sample()) for _ in range(set_size) ] logzsol_arr = [ float( priors.ClippedNormal(mean=logzsol_mean, sigma=logzsol_sig, mini=-1.5, maxi=0.0).sample()) for _ in range(set_size) ] gas_logz_arr = [ float( priors.ClippedNormal(mean=gas_logz_mean, sigma=gas_logz_sig, mini=-1.5, maxi=0.0).sample()) for _ in range(set_size) ] gas_logu_arr = [ float( priors.ClippedNormal(mean=gas_logu_mean, sigma=gas_logu_sig, mini=-4.0, maxi=-1.0).sample()) for _ in range(set_size) ] # Fix the fburst + const > 1 issue for ii in np.arange(len(const_arr)): if const_arr[ii] + fburst_arr[ii] >= 0.95: f_over = (const_arr[ii] + fburst_arr[ii]) - 0.95 if fburst_arr[ii] >= (f_over + 0.01): fburst_arr[ii] = fburst_arr[ii] - (f_over + 0.01) else: const_arr[ii] = const_arr[ii] - (f_over + 0.01) # Fixed the rest dust1_arr = np.full(set_size, 0.1) dust2_arr = np.full(set_size, 0.0) sf_trunc_arr = np.full(set_size, 0.0) # List of model parameters dwarf_sample_parameters = [{ 'dust1': dust1_arr[ii], 'dust2': dust2_arr[ii], 'logzsol': logzsol_arr[ii], 'gas_logz': gas_logz_arr[ii], 'gas_logu': gas_logu_arr[ii], 'const': const_arr[ii], 'tau': tau_arr[ii], 'tage': tage_arr[ii], 'sf_trunc': sf_trunc_arr[ii], 'fburst': fburst_arr[ii], 'tburst': tburst_arr[ii] } for ii in np.arange(set_size)] # Double check for ii, model in enumerate(dwarf_sample_parameters): if model['fburst'] + model['const'] >= 0.99: print(ii, model['fburst'], model['const']) # Initialize the spop model spop_tau = setup_fsps_spop(zcontinuous=1, imf_type=2, sfh=1, dust_type=0, dust_index=-1.3, dust1_index=-1.0) # Get the SDSS filters sdss_bands = fsps.find_filter('SDSS') dwarf_sample_gaussian = generate_dwarf_population(spop_tau, dwarf_sample_parameters, filters=sdss_bands, n_jobs=4) # Measure colors and emission line EWs # - SDSS_EMLINES is a pre-defined dict of emission lines center wavelength and the # wavelength window for measuring EW. # - You can save the results in a numpy array dwarf_sample_table = measure_color_ew(dwarf_sample_gaussian, em_list=SDSS_EMLINES, output=None) bin_size = 200 ur_loss = loss(dwarf_sample_table['ur_color'], np.asarray(sdss_use['M_u'] - sdss_use['M_r']), np.linspace(0, 2.5, bin_size)) ug_loss = loss(dwarf_sample_table['ug_color'], np.asarray(sdss_use['M_u'] - sdss_use['M_g']), np.linspace(0, 1.75, bin_size)) gr_loss = loss(dwarf_sample_table['gr_color'], np.asarray(sdss_use['M_g'] - sdss_use['M_r']), np.linspace(-0.1, 0.8, bin_size)) gi_loss = loss(dwarf_sample_table['gi_color'], np.asarray(sdss_use['M_g'] - sdss_use['M_i']), np.linspace(-0.2, 1.2, bin_size)) OIII_loss = loss(np.log10(dwarf_sample_table['ew_oiii_5007']), np.log10(-1.0 * (sdss_use['OIII_5007_EQW'])), np.linspace(-1, 3, bin_size)) Ha_loss = loss(np.log10(np.log10(dwarf_sample_table['ew_halpha'])), np.log10(-1.0 * sdss_use['H_ALPHA_EQW']), np.linspace(0, 3, bin_size)) Hb_loss = loss(np.log10(dwarf_sample_table['ew_hbeta']), np.log10(-1.0 * sdss_use['H_BETA_EQW']), np.linspace(-0.5, 2.5, bin_size)) total_loss = (ur_loss + ug_loss + gr_loss + gi_loss + OIII_loss + Ha_loss + Hb_loss) / 7 part_loss = [ ur_loss, ug_loss, gr_loss, gi_loss, OIII_loss, Ha_loss, Hb_loss ] return total_loss
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(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