Exemplo n.º 1
0
def posterior_function_many_stars_real(changing_parameter, error_list,
                                       error_element_list):
    '''
	This is the actual posterior function for many stars. But the functionality is explained in posterior_function_many_stars.
	'''
    import numpy.ma as ma
    from .cem_function import get_prior, posterior_function_returning_predictions
    from .data_to_test import likelihood_evaluation, read_out_wildcard
    from .parameter import ModelParameters

    ## Initialising the model parameters
    a = ModelParameters()

    ## extracting from 'changing_parameters' the global parameters and the local parameters
    global_parameters = changing_parameter[:len(a.SSP_parameters)]
    local_parameters = changing_parameter[len(a.SSP_parameters):]
    local_parameters = local_parameters.reshape(
        (len(a.stellar_identifier_list), len(a.ISM_parameters)))

    ## getting the prior for the global parameters in order to subtract it in the end for each time it was evaluated too much
    a.to_optimize = a.SSP_parameters_to_optimize
    global_parameter_prior = get_prior(global_parameters, a)

    ## Chempy is evaluated one after the other for each stellar identifier with the prescribed parameter combination and the element predictions for each star are stored
    predictions_list = []
    elements_list = []
    log_prior_list = []

    for i, item in enumerate(a.stellar_identifier_list):
        b = ModelParameters()
        b.stellar_identifier = item
        changing_parameter = np.hstack(
            (global_parameters, local_parameters[i]))
        args = (changing_parameter, b)
        abundance_list, element_list = posterior_function_returning_predictions(
            args)
        predictions_list.append(abundance_list)
        elements_list.append(element_list)
        log_prior_list.append(get_prior(changing_parameter, b))

    ## The wildcards are read out so that the predictions can be compared with the observations
    args = zip(a.stellar_identifier_list, predictions_list, elements_list)
    list_of_l_input = []
    for item in args:
        list_of_l_input.append(read_out_wildcard(*item))
        list_of_l_input[-1] = list(list_of_l_input[-1])

    ## Here the predictions and observations are brought into the same array form in order to perform the likelihood calculation fast
    elements = np.unique(np.hstack(elements_list))
    # Masking the elements that are not given for specific stars and preparing the likelihood input
    star_errors = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                           mask=True)
    star_abundances = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                               mask=True)
    model_abundances = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                                mask=True)

    for star_index, item in enumerate(list_of_l_input):
        for element_index, element in enumerate(item[0]):
            assert element in elements, 'observed element is not predicted by Chempy'
            new_element_index = np.where(elements == element)[0][0]
            star_errors[new_element_index, star_index] = item[1][element_index]
            model_abundances[new_element_index,
                             star_index] = item[2][element_index]
            star_abundances[new_element_index,
                            star_index] = item[3][element_index]

    ## given model error from error_list is read out and brought into the same element order (compatibility between python 2 and 3 makes the decode method necessary)
    if not a.error_marginalization:
        error_elements_decoded = []
        for item in error_element_list:
            error_elements_decoded.append(item.decode('utf8'))
        error_element_list = np.hstack(error_elements_decoded)

        error_list = np.hstack(error_list)
        model_error = []
        for element in elements:
            assert element in error_element_list, 'for this element the model error was not given, %s' % (
                element)
            model_error.append(
                error_list[np.where(error_element_list == element)])
        model_error = np.hstack(model_error)

    ## likelihood is calculated (the model error vector is expanded)
    if a.error_marginalization:
        from scipy.stats import beta
        likelihood_list = []
        model_errors = np.linspace(a.flat_model_error_prior[0],
                                   a.flat_model_error_prior[1],
                                   a.flat_model_error_prior[2])
        if a.beta_error_distribution[0]:
            error_weight = beta.pdf(model_errors,
                                    a=a.beta_error_distribution[1],
                                    b=a.beta_error_distribution[2])
            error_weight /= sum(error_weight)
        else:
            error_weight = np.ones_like(model_errors) * 1. / float(
                flat_model_error_prior[2])
        for i, item in enumerate(model_errors):
            error_temp = np.ones(len(elements)) * item
            likelihood_list.append(
                likelihood_evaluation(error_temp[:, None], star_errors,
                                      model_abundances, star_abundances))
        likelihood = logsumexp(likelihood_list, b=error_weight)
    else:
        if a.zero_model_error:
            model_error = np.zeros_like(model_error)
        likelihood = likelihood_evaluation(model_error[:, None], star_errors,
                                           model_abundances, star_abundances)

    ## Prior from all stars is added
    prior = sum(log_prior_list)
    ## Prior for global parameters is subtracted
    prior -= (len(a.stellar_identifier_list) - 1) * global_parameter_prior
    posterior = prior + likelihood
    assert np.isnan(posterior) == False, ('returned posterior = ', posterior,
                                          'prior = ', prior, 'likelihood = ',
                                          likelihood, 'changing parameter = ',
                                          changing_parameter)
    ########
    if a.verbose:
        print('prior = ', prior, 'likelihood = ', likelihood)

    return (posterior, model_abundances)
Exemplo n.º 2
0
def global_optimization_real(changing_parameter, result):
    '''
	This function calculates the predictions from several Chempy zones in parallel. It also calculates the likelihood for common model errors
	BEWARE: Model parameters are called as saved in parameters.py!!!

	INPUT:

	   changing_parameter = the global SSP parameters (parameters that all stars share)

	   result = the complete parameter set is handed over as an array of shape(len(stars),len(all parameters)). From those the local ISM parameters are taken
	
	OUTPUT:

	   -posterior = negative log posterior for all stellar zones

	   error_list = the optimal standard deviation of the model error

	   elements = the corresponding element symbols
	'''
    import multiprocessing as mp
    import numpy.ma as ma
    from scipy.stats import beta
    from .cem_function import get_prior, posterior_function_returning_predictions
    from .data_to_test import likelihood_evaluation
    from .parameter import ModelParameters

    ## Calculating the prior
    a = ModelParameters()
    a.to_optimize = a.SSP_parameters_to_optimize
    prior = get_prior(changing_parameter, a)

    ## Handing over to posterior_function_returning_predictions
    parameter_list = []
    p0_list = []
    for i, item in enumerate(a.stellar_identifier_list):
        parameter_list.append(ModelParameters())
        parameter_list[-1].stellar_identifier = item
        p0_list.append(
            np.hstack((changing_parameter, result[i, len(a.SSP_parameters):])))
    args = zip(p0_list, parameter_list)
    p = mp.Pool(len(parameter_list))
    t = p.map(posterior_function_returning_predictions, args)
    p.close()
    p.join()
    z = np.array(t)
    # Predictions including element symbols are returned

    # Reading out the wildcards
    elements = np.unique(np.hstack(z[:, 1]))
    from Chempy.data_to_test import read_out_wildcard
    args = zip(a.stellar_identifier_list, z[:, 0], z[:, 1])
    list_of_l_input = []
    for item in args:
        list_of_l_input.append(read_out_wildcard(*item))
        list_of_l_input[-1] = list(list_of_l_input[-1])
    # Now the input for the likelihood evaluating function is almost ready

    # Masking the elements that are not given for specific stars and preparing the likelihood input
    star_errors = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                           mask=True)
    star_abundances = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                               mask=True)
    model_abundances = ma.array(np.zeros(
        (len(elements), len(a.stellar_identifier_list))),
                                mask=True)

    for star_index, item in enumerate(list_of_l_input):
        for element_index, element in enumerate(item[0]):
            assert element in elements, 'observed element is not predicted by Chempy'
            new_element_index = np.where(elements == element)[0][0]
            star_errors[new_element_index, star_index] = item[1][element_index]
            model_abundances[new_element_index,
                             star_index] = item[2][element_index]
            star_abundances[new_element_index,
                            star_index] = item[3][element_index]

    # Brute force testing of a few model errors
    model_errors = np.linspace(a.flat_model_error_prior[0],
                               a.flat_model_error_prior[1],
                               a.flat_model_error_prior[2])
    if a.beta_error_distribution[0]:
        error_weight = beta.pdf(model_errors,
                                a=a.beta_error_distribution[1],
                                b=a.beta_error_distribution[2])
        error_weight /= sum(error_weight)
    else:
        error_weight = np.ones_like(model_errors) * 1. / float(
            flat_model_error_prior[2])
    error_list = []
    likelihood_list = []
    for i, element in enumerate(elements):
        error_temp = []
        for item in model_errors:
            error_temp.append(
                likelihood_evaluation(item, star_errors[i],
                                      model_abundances[i], star_abundances[i]))
        cut = np.where(np.hstack(error_temp) == np.max(error_temp))
        if len(cut) == 2:
            cut = cut[0][0]
        error_list.append(float(model_errors[cut]))
        ## Adding the marginalization over the model error (within the prior borders). Taking the average of the likelihoods (they are log likelihoods so exp needs to be called)
        if a.error_marginalization:
            likelihood_list.append(logsumexp(error_temp, b=error_weight))
        else:
            if a.zero_model_error:
                likelihood_list.append(error_temp[0])
            else:
                likelihood_list.append(np.max(error_temp))

    error_list = np.hstack(error_list)
    likelihood_list = np.hstack(likelihood_list)
    likelihood = np.sum(likelihood_list)

    # returning the best likelihood together with the prior as posterior
    return (-(prior + likelihood), error_list, elements)