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