def _generate_samples(self, problemdef, savefile = None): """ Generate a set of evenly-spaced Saltelli samples to use for variance analysis. """ # Generate evenly-distributed samples within the defined parameter bounds using Saltelli Sampling if self.second_order == True: k = 2 else: k = 1 if savefile is not None: if os.path.isfile(savefile) is True: with open(savefile, 'w') as pf: sample_list = pickle.load(savefile) else: # Generate the samples sample_list = saltelli.sample(problemdef, int(round(float(self.nsamples)/(k * problem['num_vars'] + 2))), calc_second_order = self.second_order) # Save the generated samples to a pickle file for later use with open(savefile, 'w') as pf: pickle.dump(param_list, pf) else: # Generate the samples sample_list = saltelli.sample(problemdef, int(round(float(self.nsamples)/(k * problem['num_vars'] + 2))), calc_second_order = self.second_order) return sample_list
def _hyper_params_create(second_order=True): problem = {'num_vars': 1, 'names': ['alpha'], 'bounds': [[0, 2]]} if second_order: # includes second-order indices return saltelli.sample(problem, 1000) # N * (2D + 2); here, N = 10, D = 3 # excludes second-order indices return saltelli.sample( problem, 1000, calc_second_order=False) # N * (D + 2); here, N = 10, D = 3
def test_saltelli_sample_seed(): N, problem = problem_setup() sample1 = saltelli.sample(problem, N, calc_second_order=False, skip_values=1000) sample2 = saltelli.sample(problem, N, calc_second_order=False, skip_values=1001) np.testing.assert_equal(np.any(np.not_equal(sample1, sample2)), True)
def _gen_muestrea(símismo, n, ops): if símismo.método == 'sobol': return saltelli.sample(problem=símismo.problema, N=n, **ops) elif símismo.método == 'fast': return fast_sampler.sample(problem=símismo.problema, N=n, **ops) elif símismo.método == 'morris': return morris_muestra.sample(problem=símismo.problema, N=n, **ops) elif símismo.método == 'dmim': return latin.sample(problem=símismo.problema, N=n) elif símismo.método == 'dgsm': return saltelli.sample(problem=símismo.problema, N=n) elif símismo.método == 'ff': return ff_muestra.sample(problem=símismo.problema) else: raise ValueError('Método de análisis de sensibilidad "{}" no reconocido.'.format(símismo.método))
def sobol_analyze(model, X, logger, N=500000, **kwargs): ''' INPUT: ::model:: the NN that takes X as input, ::X:: a 2D vector of input [batch_size, feature_length] ::N:: the analyze point size, see more detail in SALib ::**kwargs:: specify optional kwargs for 'sobel.analyze(**kwargs)' RETURN: a dict of sobol importance analysis ''' upper = X.max(axis=0) lower = X.min(axis=0) bounds = [[i, j] for i, j in zip(lower, upper)] for i in range(len(bounds)): if bounds[i][1] == 0: bounds[i][1] = 0.01 break # print(bounds) all_feature_problem = { 'num_vars': X.shape[1], 'names': ['x' + str(i) for i in range(X.shape[1])], 'bounds': bounds } logger.info("Generate feature samples") params_value = saltelli.sample(all_feature_problem, N) y_est = model.predict_batch(params_value).flatten() logger.info("Start analyze") result = sobol.analyze(all_feature_problem, y_est, **kwargs) return result
def scatter_plot(): n = 100 mod = models['adequate'] for param in param_bounds.keys(): prob = { 'num_vars': 1, 'names': [param], 'bounds': [param_bounds[param]] } par_sets = [p[0] for p in sampling_method.sample(prob, n)] solver = Solver(mod, t) res_sets = {out: [] for out in outputs['adequate']} for par_set in par_sets: pars = {p.name: p.value for p in mod.parameters} pars[param] = par_set solver.run(pars) for out in outputs['adequate']: res_sets[out].append(solver.yobs[out][-1]) # last result # Plot simulation results for the observables in the model pl.ion() pl.figure(figsize=(8, 8)) for res in res_sets.keys(): pl.scatter(par_sets, res_sets[res], label=res) pl.legend() pl.xlabel(param) pl.ylabel("Outputs") pl.savefig('scatterplots/' + param + '.png', dpi=300) pl.clf()
def SALib(result_title, input_title, bounds): num_vars = len(bounds[1]) + 1 for i in range(len(result_title)): input_title.insert(0, result_title[i]) print(input_title) new_bounds = bounds[1] new_bounds.insert(0, bounds[0][i]) problem = { 'num_vars': num_vars, 'names': input_title, 'bounds': new_bounds } # Generate samples param_values = saltelli.sample(problem, 1000) # Run model (example) Y = Ishigami.evaluate(param_values) # Perform analysis _ = sobol.analyze(problem, Y, print_to_console=True) del(input_title[0]) del(new_bounds[0])
def make_saltelli_samples(model, salib_problem, num_samples, second_order=False, log=[]): """ Use SALib to make saltelli samples Args: model (Model): The model object salib_problem (dict): An SALib Problem num_samples (int): number of samples to take second_order (bool): look at second order interactions Returns: Samples from salib which have been parsed into a set of samples which run_all_models can take. """ saltelli_samples = saltelli.sample(salib_problem, num_samples, calc_second_order=second_order) saltelli_samples = samples_to_normal_space(saltelli_samples, salib_problem, log) samples = parse_samples(saltelli_samples, list(model.parameter_distributions.keys()), list(model.species_distributions.keys())) return samples
def get_saltelli_sample( problem: dict, n_saltelli: int, calc_second_order: bool = False ) -> pd.DataFrame: """Encapsulates Saltelli sampling function from SALib Parameters ---------- problem: dict problem definition in SALib format (see problem.py) n_saltelli: int 'N' parameter of SALib.sample.saltelli: The number of samples to generate calc_second_order: bool 'calc_second_order' parameter of SALib.sample.saltelli: Option to compute second order Sobol indices Returns ------- df_sample: pd.DataFrame dataframe of Saltelli samples """ param_values = saltelli.sample( problem, n_saltelli, calc_second_order=calc_second_order ) # Replace column names df_sample = pd.DataFrame(param_values, columns=problem["names"]) return df_sample
def sample_parameters(problem: dict, seed: int, method: str): if method == "FAST": return fast_sampler.sample(problem, seed) if method == "sobol": return saltelli.sample(problem, seed) if (method == "RBD_FAST") or (method == "DMIM"): return latin.sample(problem, seed)
def d_analysis(d_eff_on=False): if d_eff_on: problem = { 'num_vars': 4, 'names': ['D', 'x', 'l', 'q'], 'bounds': [[gfp, sa], [0, 50], [50, 100], [0, 10]] } def analytical(x, D, q, l): D = D_eff(D, q, l) t = 60 return ((1 / np.sqrt(4 * np.pi * D * t)) * np.exp(-((np.square(x)) / (4 * D * t)))) else: problem = { 'num_vars': 3, 'names': ['D', 'q', 'l'], 'bounds': [[gfp // 10, sa * 10], [0.001, 10], [25, 200]] } def analytical(x, D, t): return ((1 / np.sqrt(4 * np.pi * D * t)) * np.exp(-((np.square(x)) / (4 * D * t)))) param_values = saltelli.sample(problem, 10000) Y = np.array([analytical(*pv) for pv in param_values]) return sobol.analyze(problem, Y, print_to_console=True)
def _saltelli_sampling(n, doe_variables, seed): dim = len(doe_variables) N = int(n / (2 * dim + 2)) problem = _define_salib_problem(doe_variables) points = saltelli.sample(problem, N, seed=seed) return points
def main(): problem = { 'num_vars': 2, 'names': ['a', 'b'], 'bounds': [ [0.0, 3.0], #'bounds':[a,b], a<b [0.0, 1.0] ] } param_values = saltelli.sample(problem, 1, calc_second_order=True) #run model print param_values #Y = run_model(param_values) #Si = sobol.analyze(problem, Y, print_to_console=True) Y = np.empty([param_values.shape[0]]) for i, XX in enumerate(param_values): #print i, XX[0],XX[1],1,0 Y[i] = run_model(XX[0], XX[1], 1, 0) #parallel run on HPC #Y[i] = run_model(XX(i,0), XX(i,1), 1, 0) print Y[i] Si = sobol.analyze(problem, Y, print_to_console=False) print Si['S1'], Si['ST']
def get_sampling_df(nr_samples=160): # STEP 1: Create samples with Sobol sequence using SALib parameter = problem_definition() param_values = saltelli.sample(parameter, int(nr_samples / 8), calc_second_order=True, seed=111) # Step 2: Make samples readable for suqc param_values = pd.DataFrame(param_values, columns=["number_of_agents_mean", "p1", "p2"]) param_values["number_of_agents_mean"] = round( param_values["number_of_agents_mean"], 0) # Step 2.1: Distribute number of agents at four sources and determine number of agents/(1 second) for x in [1, 2, 5, 6]: param_values[ f"sources.[id=={x}].distributionParameters"] = param_values.apply( lambda row: [row.number_of_agents_mean * 0.01 / 4], axis=1) # Step 2.2: Add units param_values["*.hostMobile[*].app[1].messageLength"] = param_values.apply( lambda row: f"{int(row.p1)}B", axis=1) param_values["**wlan[*].radio.transmitter.power"] = param_values.apply( lambda row: f"{round(row.p2,2)}mW", axis=1) param_values = param_values.drop(columns=["p1", "p2"]) return param_values
def sensitivity_analysis(self): female, relation, factors = self.sensitivity_analysis_detect_intervals( [15, 40, 90]) factors_names = list( sorted(map(lambda k: 'factor_{}'.format(k), factors), key=lambda k: int(k[7]))) problem = { 'num_vars': len(factors) + 2, 'names': ['female', 'relation'] + factors_names, 'bounds': [[female['min'], female['max']], [relation['min'], relation['max']]] + list( map(lambda k: [factors[k]['min'], factors[k]['max']], sorted(factors.keys()))) } param_values = saltelli.sample(problem, 100) for year in [2010, 2020, 2050, 2100]: Y = self.sensitivity_analysis_evaluate(param_values, year) Si = sobol.analyze(problem, Y, print_to_console=False) print("__________________ {} __________________".format(year)) print("") print(Si['S1']) print("")
def generate_samples(problem, params, project_dir, method): """ The Saltelli sampler generated 8000 samples. The Saltelli sampler generates N*(2D+2) samples, where in this example N is 1000 (the argument we supplied) and D is 3 (the number of model inputs). """ if method == 'Saltelli': param_values = saltelli.sample(problem, params['samples']) elif method == 'FAST': param_values = fast_sampler.sample(problem, params['samples']) count = 0 for i, X in enumerate(param_values): count += 1 p, w, pred_fle = par.get_params(innate, X) _numpoints = 100 t = [ par._stoptime * float(i) / (_numpoints - 1) for i in range(_numpoints) ] w0 = innate.get_init(w, params) t, wsol = innate.solve(p, w0, t, params) APE_blood = [] CH = [] ACH = [] for t1, w1 in zip(t, wsol): APE_blood.append(w1[1]) CH.append(w1[10]) ACH.append(w1[13]) # Y_list.append(APE_blood) write_file(project_dir, method, APE_blood, 'AP') write_file(project_dir, method, CH, 'CH') write_file(project_dir, method, ACH, 'ACH') print(count, ' of ', len(param_values))
def test_sobol_to_df(): params = ['x1', 'x2', 'x3'] problem = {'num_vars': 3, 'names': params, 'bounds': [[-np.pi, np.pi]] * 3} X = saltelli.sample(problem, 1000) Y = Ishigami.evaluate(X) Si = sobol.analyze(problem, Y, print_to_console=False) total, first, second = Si.to_df() assert isinstance(total, pd.DataFrame), \ "Total Si: Expected DataFrame, got {}".format(type(total)) assert isinstance(first, pd.DataFrame), \ "First Si: Expected DataFrame, got {}".format(type(first)) assert isinstance(second, pd.DataFrame), \ "Second Si: Expected DataFrame, got {}".format(type(second)) expected_index = set(params) assert set(total.index) == expected_index, \ "Index for Total Si are incorrect" assert set(first.index) == expected_index, \ "Index for first order Si are incorrect" assert set(second.index) == set([('x1', 'x2'), ('x1', 'x3'), ('x2', 'x3')]), \ "Index for second order Si are incorrect"
def setup_samples(N=500, calc_second_order=True): param_file = 'src/SALib/test_functions/params/Ishigami.txt' problem = read_param_file(param_file) param_values = saltelli.sample(problem, N=N, calc_second_order=calc_second_order) return problem, param_values
def test_sample_saltelli_second(): parameters = { 'a': ap.IntRange(1, 2), 'b': ap.Range(3, 3.5), 'c': ap.Values(*'xyz'), 'd': True } sample = ap.Sample(parameters, n=2, method='saltelli', calc_second_order=True) problem = { 'num_vars': 3, 'names': ['a', 'b', 'c'], 'bounds': [ [1., 3.], [3., 3.5], [0., 3.], ] } param_values = saltelli.sample(problem, 2, calc_second_order=True) for s1, s2 in zip(sample, param_values): assert s1['a'] == int(s2[0]) assert s1['b'] == s2[1] assert s1['c'] == parameters['c'].values[int(s2[2])] assert s1['d'] == parameters['d']
def redraw(self, random_method: str): """Redraw the random number with the given method :param random_method: the random method to use """ problem = { "num_vars": self.num_dim, "names": list(range(self.num_dim)), "bounds": [[0, 1]] * self.num_dim, } if random_method == "pseudo_random": seq = np.random.random((self.bucket_size, 2)) elif random_method == "sobol_sequence": seq = sobol_sequence.sample(self.bucket_size, 2) elif random_method == "saltelli": seq = saltelli.sample(problem, self.bucket_size, calc_second_order=False) elif random_method == "latin_hypercube": seq = latin.sample(problem, self.bucket_size) elif random_method == "finite_differences": seq = finite_diff.sample(problem, self.bucket_size) elif random_method == "fast": seq = fast_sampler.sample(problem, self.bucket_size, M=45) else: raise ValueError(f"Unknown random method {random_method}") self.random_draws[random_method] = seq
def sensitivityAnalysis(model, mlKind, dfInputData, config): problem = { 'num_vars': len(config._featureList), 'names': config._featureList, 'bounds': [] } for xcol in config._featureList: problem['bounds'].append([ dfInputData[xcol].min() - 0.01, dfInputData[xcol].max() + 0.01 ]) # Generate samples XSample = saltelli.sample(problem, 1000) # Run model (example) Y = model.predict(XSample) Y = Y.reshape((Y.shape[0], )) print('Sensitivity_' + mlKind, XSample.shape, Y.shape) Si = sobol.analyze(problem, Y, print_to_console=False) from pandas import DataFrame feature_importances = [ (feature, round(importance, 3)) for feature, importance in zip(config._featureList, Si['ST']) ] # Sort the feature importances by most important first feature_importances = sorted(feature_importances, key=lambda x: x[1], reverse=True) df_feature_importances = DataFrame(feature_importances) df_feature_importances.columns = ['Feature', '敏感度' + mlKind] return df_feature_importances
def analyse(model,n_samples): problem = { 'num_vars': 5, 'names': ['flow1', 'flow2', 'flow3', 'flow4', 'lost_time'], 'bounds': [[0.0, 1.0], [0.0, 1.0], [0.0, 1.0], [0.0, 1.0], [0.0, 1.0],] } param_values = saltelli.sample(problem, n_samples) Y1 = np.zeros([param_values.shape[0]]) Y2 = np.zeros([param_values.shape[0]]) Y3 = np.zeros([param_values.shape[0]]) Y4 = np.zeros([param_values.shape[0]]) for i, X in enumerate(param_values): X = np.column_stack((X[0],X[1],X[2],X[3],X[4])) temp = model.predict(X) Y1[i] = temp[0][0] Y2[i] = temp[0][1] Y3[i] = temp[0][2] Y4[i] = temp[0][3] Si = sobol.analyze(problem, Y1) print('sensitivity analysis for phase split 1') print(Si['S1']) print(Si['ST']) print("x1-x2:", Si['S2'][0, 1]) print("x1-x3:", Si['S2'][0, 2]) print("x2-x3:", Si['S2'][1, 2]) print("x3-x4:", Si['S2'][2, 3]) Si = sobol.analyze(problem, Y2) print('sensitivity analysis for phase split 2') print(Si['S1']) print(Si['ST']) print("x1-x2:", Si['S2'][0, 1]) print("x1-x3:", Si['S2'][0, 2]) print("x2-x3:", Si['S2'][1, 2]) print("x3-x4:", Si['S2'][2, 3]) Si = sobol.analyze(problem, Y3) print('sensitivity analysis for phase split 3') print(Si['S1']) print(Si['ST']) print("x1-x2:", Si['S2'][0, 1]) print("x1-x3:", Si['S2'][0, 2]) print("x2-x3:", Si['S2'][1, 2]) print("x3-x4:", Si['S2'][2, 3]) Si = sobol.analyze(problem, Y4) print('sensitivity analysis for phase split 4') print(Si['S1']) print(Si['ST']) print("x1-x2:", Si['S2'][0, 1]) print("x1-x3:", Si['S2'][0, 2]) print("x2-x3:", Si['S2'][1, 2]) print("x3-x4:", Si['S2'][2, 3]) return True
def __init__(self): self.simulation = oc.simulation() self.simulation.data().setStartingPoint(0) self.simulation.data().setEndingPoint(3900) self.simulation.data().setPointInterval(1) self.constants = self.simulation.data().constants() self.constant_parameter_names = sorted(list(self.constants.keys())) for i in range(0, len(fit_parameters_exclude)): self.constant_parameter_names.remove(fit_parameters_exclude[i]) self.model_constants = OrderedDict( {k: self.constants[k] for k in self.constant_parameter_names}) # default the parameter bounds to something sensible, needs to be set directly bounds = [] for c in self.constant_parameter_names: v = self.constants[c] bounds.append([bounds_dictionary[c][0], bounds_dictionary[c][1]]) # define our sensitivity analysis problem self.problem = { 'num_vars': len(self.constant_parameter_names), 'names': self.constant_parameter_names, 'bounds': bounds } self.samples = saltelli.sample(self.problem, num_samples) #print(self.samples) np.savetxt("self.samples.txt", self.samples)
def test_sobol_to_df(): params = ['x1', 'x2', 'x3'] problem = { 'num_vars': 3, 'names': params, 'bounds': [[-np.pi, np.pi]]*3 } X = saltelli.sample(problem, 1000) Y = Ishigami.evaluate(X) Si = sobol.analyze(problem, Y, print_to_console=False) total, first, second = Si.to_df() assert isinstance(total, pd.DataFrame), \ "Total Si: Expected DataFrame, got {}".format(type(total)) assert isinstance(first, pd.DataFrame), \ "First Si: Expected DataFrame, got {}".format(type(first)) assert isinstance(second, pd.DataFrame), \ "Second Si: Expected DataFrame, got {}".format(type(second)) expected_index = set(params) assert set(total.index) == expected_index, \ "Index for Total Si are incorrect" assert set(first.index) == expected_index, \ "Index for first order Si are incorrect" assert set(second.index) == set([('x1', 'x2'), ('x1', 'x3'), ('x2', 'x3')]), \ "Index for second order Si are incorrect"
def _generate_sample(self, n, sample_type, generate_pars): # create the array using the spacing method of choice raw_sample = None if sample_type == "sobol": from sobol_seq import i4_sobol_generate raw_sample = i4_sobol_generate(len(generate_pars), n) elif sample_type == "saltelli": from SALib.sample import saltelli problem = { "names": generate_pars, "bounds": [[0, 1] for x in generate_pars], "num_vars": len(generate_pars), } raw_sample = saltelli.sample(problem, n, True) elif sample_type == "grid": from sklearn.utils.extmath import cartesian temp = np.linspace(0, 1, n) raw_sample = cartesian([temp for i in range(len(generate_pars))]) elif sample_type == "random": raw_sample = np.random.random((n, len(generate_pars))) assert raw_sample is not None, "something went wrong - check that type is correct" print("expected shape is {}".format(raw_sample.shape)) # map the raw array to bounds, adhering to log scaling rules scaled_sample = self.log_scale_matrix(raw_sample) return scaled_sample
def sample(self, nobs, method='saltelli', seed=933090936): """ Generate the random parameter values using SALib Parameters ---------- nobs: int, required Number of sample realizations method: string, optional The sampling method, default saltelli seed : int, optional The random seed Returns ------- A NumPy matrix containing the model inputs using Saltelli's sampling scheme. The resulting matrix has size of N * D, where D is the number of parameters. """ sampling_methods_allowed = ['saltelli'] if method.lower() not in sampling_methods_allowed: raise ValueError('Sampling method not supported: choose one of %s' %', '.join(sampling_methods_allowed)) nvars = len(self.pars['names']) problem = self.pars.copy() problem['num_vars'] = nvars if method.lower()=='saltelli': from SALib.sample import saltelli values = saltelli.sample(problem, nobs, seed=seed, calc_second_order=False)[::nvars + 2, :] return values
def generate_samples(sp, n_runs, VPD=2.0, tmax=180): var_vals = [traits[sp][get_part(v)][v] for v in var_names[:-1]] var_vals.extend([Rmax]) problem_bounds = [[min(0.5 * v, 2.0 * v), max(0.5 * v, 2.0 * v)] for v in var_vals] # problem_bounds = [[min(0.25*v,4.0*v), max(0.25*v,4.0*v)] for v in var_vals] problem = { 'num_vars': n_vars, 'names': var_names, 'bounds': problem_bounds } # generate samples param_values = saltelli.sample(problem, n_runs, calc_second_order=False) print len(param_values) ''' parallel processing ''' ncores = mp.cpu_count() print('There are %s cores on this machine ' % (str(ncores), )) pool = mp.Pool() param_cores = np.array_split(param_values, ncores, axis=0) param_augmented = [(p, VPD, tmax) for p in param_cores] Y_pooled = pool.map(evaluate_model, param_augmented) Y = np.vstack(Y_pooled) # output shape (len(param_values), 2) with open( '/Users/xuefeng/Dropbox/Projects/Isohydricity/Sobol/Si_' + sp + '_vpd' + str(int(VPD)) + '_tmax' + str(tmax) + '_outcomes.pickle', 'wb') as handle: pickle.dump(Y, handle) with open( '/Users/xuefeng/Dropbox/Projects/Isohydricity/Sobol/Si_' + sp + '_vpd' + str(int(VPD)) + '_tmax' + str(tmax) + '_params.pickle', 'wb') as handle: pickle.dump(param_values, handle) return Y, param_values
def ranges_adjust(Nsamples=Nsamples): sample_range_change = np.round( saltelli.sample(problem_adjust, N=Nsamples, calc_second_order=False, seed=121), 4) return sample_range_change
def generate_spectra(sample_number=10000, bounds='../assets/prosail_param_bounds.txt', save_to_npy=False, spectra_save='../data/spectra.npy', params_save='../data/params.npy', params_norm_save='../data/params_norm.npy'): param_dimension = 15 wavelength_start = 400 wavelength_end = 2500 wavelength_num = wavelength_end - wavelength_start + 1 problem = read_param_file(bounds) params = saltelli.sample(problem, sample_number) params_norm = params.copy() num = sample_number * (param_dimension + 1) * 2 cores = multiprocessing.cpu_count() pool = multiprocessing.Pool(processes=cores) spec = pool.map(generate_spectrum, params) spec = np.array(spec).reshape(num, 2101) for i in range(num): p = params[i] for j in range(param_dimension): params_norm[i][j] = (p[j] - problem['bounds'][j][0]) / ( problem['bounds'][j][1] - problem['bounds'][j][0]) if save_to_npy: np.save(spectra_save, spec) np.save(params_save, params) return spec, params, params_norm
def runModelManyTimes(parameters, scaling_factor): # Collect problem parameters, names, and bounds problem = problemParameters(parameters, scaling_factor) # Generate samples param_values = saltelli.sample(problem, 100) # Create empty array of same shape to store values Y = np.zeros([param_values.shape[0]]) print(Y.shape) # Store results of model in Y array for i, option in enumerate(param_values): # Put parameters back into dictionary needed for duct model function option = dict() for j, parameter in enumerate(problem['names']): var_dict = dict() var_dict[parameter] = dict() var_dict[parameter]['Value'] = param_values[i][j] option[parameter] = var_dict[parameter] # Store peak bicarbonate secretion as measure of model performance Y[i] = np.max(runBaseModel(option)['bl']) print(i, Y[i]) return problem, Y
def sensitivity(fertility, ratio, x1, x14, x18, x28, x41): model = init_model() problem = { 'num_vars': 7, 'names': ['fertility', 'babies_fraction', 'x1', 'x14', 'x18', 'x28', 'x41'], 'bounds': [[fertility["min"], fertility["max"]], [ratio['min'], ratio['max']], [x1['min'], x1['max']], [x14['min'], x14['max']], [x18['min'], x18['max']], [x28['min'], x28['max']], [x41['min'], x41['max']]] } params = sample(problem, 10) years = [i for i in range(2005, 2106, 5)] simulated_population = [] for year in years: print("YEAR: ", year) population = eval(model, params, year) population = population.flatten() simulated_population.append(population) # si = sobol.analyze(problem, population, print_to_console=False) # vis.sensitivity_analysis(si, problem['names'], year) # vis.sensitivity_analysis(si, problem['names'], year, num=1) max_population = [max(i) for i in simulated_population] min_population = [min(i) for i in simulated_population] avg_population = [np.mean(i) for i in simulated_population] vis.uncertainty_plot(min_population, max_population, avg_population, years)
def create_data(problem, new_path): """ problem : dict with specified input variables and range instead of discrete values otherwise saltelli will not work Run each batch iterations with all the samples obtained from saltelli and save at the end of the run Saves data with time stamp as .csv and .pickle """ # Set the repetitions, the amount of steps, and the amount of distinct values per variable replicates = 10 max_steps = 100 distinct_samples= 10 # Define output parameters model_reporters = { 'step_data': lambda m: m.datacollector.get_model_vars_dataframe(), 'obstacle_density': lambda m: m.obstacle_density, 'food_density': lambda m: m.food_density, 'nr_hives': lambda m: m.nr_hives } data = {} # Sample from data with every interactions, computationally expensive but gives all combinations params_values = saltelli.sample(problem,N=distinct_samples) #transform to int value and overwrite array if copy needed set flag to True params_values = params_values.astype(int, copy=False) batch = BatchRunnerMP(BeeForagingModel, nr_processes=os.cpu_count(), max_steps=max_steps, variable_parameters={val:[] for val in problem['names']}, model_reporters=model_reporters, display_progress=True) counter = 0 # progress bar pbar = tqdm(total=len(params_values)) for _ in range(replicates): for values in params_values: var_parameters = {} # #collect all data samples from salteli sampling for n, v, in zip(problem['names'],values): var_parameters[n] = v batch.run_iteration(var_parameters, tuple(values),counter) counter +=1 pbar.update(counter) pbar.close() data = batch.get_model_vars_dataframe() data.to_csv(f'pickles/analysis_{new_path}.csv') data.to_pickle(f'pickles/analysis_{new_path}.p') return data
def test_regression_sobol(): param_file = 'SALib/test_functions/params/Ishigami.txt' problem = read_param_file(param_file) param_values = saltelli.sample(problem, 10000, calc_second_order=True) Y = Ishigami.evaluate(param_values) Si = sobol.analyze(problem, Y, calc_second_order=True, conf_level=0.95, print_to_console=False) assert_allclose(Si['S1'], [0.31, 0.44, 0.00], atol=5e-2, rtol=1e-1) assert_allclose(Si['ST'], [0.55, 0.44, 0.24], atol=5e-2, rtol=1e-1) assert_allclose([Si['S2'][0][1], Si['S2'][0][2], Si['S2'][1][2]], [0.00, 0.25, 0.00], atol=5e-2, rtol=1e-1)
def test_regression_sobol_groups(): problem = { 'num_vars': 3, 'names': ['x1', 'x2', 'x3'], 'bounds': [[-np.pi, np.pi]]*3, 'groups': ['G1', 'G2', 'G1'] } param_values = saltelli.sample(problem, 10000, calc_second_order=True) Y = Ishigami.evaluate(param_values) Si = sobol.analyze(problem, Y, calc_second_order=True, parallel=True, conf_level=0.95, print_to_console=False) assert_allclose(Si['S1'], [0.55, 0.44], atol=5e-2, rtol=1e-1) assert_allclose(Si['ST'], [0.55, 0.44], atol=5e-2, rtol=1e-1) assert_allclose(Si['S2'][0][1], [0.00], atol=5e-2, rtol=1e-1)
def perform_analsis(self, n=10, **kwds): """Perform Sobol sensitivity analysis with SALib methods **Arguments**: - *n* = int : number of sobol iterations (default: 10) **Optional keywords**: - *calc_second_order* = bool : second order stats (default: True) """ calc_second_order = kwds.get("calc_second_order", True) # freeze base stats self.freeze() # import SALib method from SALib.sample import saltelli from SALib.analyze import sobol # create temporary parameter file param_file = "params_file_tmp.txt" self.create_params_file(filename = param_file) # perform sampling self.param_values = saltelli.sample(10, param_file, calc_second_order = calc_second_order) # calculate distances - compute intensive step! self.distances = self.determine_distances() # save results results_file = 'dist_tmp.txt' np.savetxt(results_file, self.distances, delimiter=' ') # perform sobol analysis Si = sobol.analyze(param_file, results_file, column = 0, conf_level = 0.95, calc_second_order = calc_second_order, print_to_console=False) # create composite matrix for sensitivities n_params = len(self.param_stats) self.comp_matrix = np.ndarray(shape = (n_params,n_params)) for j in range(n_params): for i in range(n_params): if i == j: self.comp_matrix[i,j] = Si['S1'][i] else: self.comp_matrix[i,j] = Si['S2'][i,j] self.comp_matrix[j,i] = Si['S2'][i,j] # remove temporary files import os os.remove(results_file) os.remove(param_file)
def test_Sobol_G_using_sobol(): ''' Tests the accuracy of the Sobol/Saltelli procedure using the Sobol_G test function, comparing the results from the Sobol/Saltelli analysis against the analytically computed sensitivity index from the Sobol_G function. ''' problem = {'num_vars': 6, 'names': ['x1', 'x2', 'x3', 'x4', 'x5', 'x6'], 'bounds': [[0, 1], [0, 1], [0, 1], [0, 1],[0, 1], [0, 1]]} N = 5000 a = np.array([78, 12, 0.5, 2, 97, 33]) param_values = saltelli.sample(problem, N, calc_second_order=False) model_results = Sobol_G.evaluate(param_values, a) Si = sobol.analyze(problem, model_results, calc_second_order=False) # expected = Sobol_G.total_sensitivity_index(a) # assert_allclose(Si['ST'], expected) expected = Sobol_G.sensitivity_index(a) assert_allclose(Si['S1'], expected, atol=1e-2, rtol=1e-6)
def setup_samples(N = 500, calc_second_order = True): param_file = 'SALib/test_functions/params/Ishigami.txt' problem = read_param_file(param_file) param_values = saltelli.sample(problem, N=N, calc_second_order=calc_second_order) return problem,param_values
def sa(model, response, policy={}, method="sobol", nsamples=1000, **kwargs): if len(model.uncertainties) == 0: raise ValueError("no uncertainties defined in model") problem = { 'num_vars' : len(model.uncertainties), 'names' : model.uncertainties.keys(), 'bounds' : [[0.0, 1.0] for u in model.uncertainties], 'groups' : kwargs.get("groups", None) } # estimate the argument N passed to the sampler that produces the requested # number of samples N = _predict_N(method, nsamples, problem["num_vars"], kwargs) # generate the samples if method == "sobol": samples = saltelli.sample(problem, N, **_cleanup_kwargs(saltelli.sample, kwargs)) elif method == "morris": samples = morris_sampler.sample(problem, N, **_cleanup_kwargs(morris_sampler.sample, kwargs)) elif method == "fast": samples = fast_sampler.sample(problem, N, **_cleanup_kwargs(fast_sampler.sample, kwargs)) elif method == "ff": samples = ff_sampler.sample(problem, **_cleanup_kwargs(ff_sampler.sample, kwargs)) elif method == "dgsm": samples = finite_diff.sample(problem, N, **_cleanup_kwargs(finite_diff.sample, kwargs)) elif method == "delta": if "samples" in kwargs: samples = kwargs["samples"] else: samples = latin.sample(problem, N, **_cleanup_kwargs(latin.sample, kwargs)) # convert from samples in [0, 1] to uncertainty domain for i, u in enumerate(model.uncertainties): samples[:,i] = u.ppf(samples[:,i]) # run the model and collect the responses responses = np.empty(samples.shape[0]) for i in range(samples.shape[0]): sample = {k : v for k, v in zip(model.uncertainties.keys(), samples[i])} responses[i] = evaluate(model, overwrite(sample, policy))[response] # run the sensitivity analysis method if method == "sobol": result = sobol.analyze(problem, responses, **_cleanup_kwargs(sobol.analyze, kwargs)) elif method == "morris": result = morris_analyzer.analyze(problem, samples, responses, **_cleanup_kwargs(morris_analyzer.analyze, kwargs)) elif method == "fast": result = fast.analyze(problem, responses, **_cleanup_kwargs(fast.analyze, kwargs)) elif method == "ff": result = ff_analyzer.analyze(problem, samples, responses, **_cleanup_kwargs(ff_analyzer.analyze, kwargs)) elif method == "dgsm": result = dgsm.analyze(problem, samples, responses, **_cleanup_kwargs(dgsm.analyze, kwargs)) elif method == "delta": result = delta.analyze(problem, samples, responses, **_cleanup_kwargs(delta.analyze, kwargs)) # convert the SALib results into a form allowing pretty printing and # lookups using the parameter name pretty_result = SAResult(result["names"] if "names" in result else problem["names"]) if "S1" in result: pretty_result["S1"] = {k : float(v) for k, v in zip(problem["names"], result["S1"])} if "S1_conf" in result: pretty_result["S1_conf"] = {k : float(v) for k, v in zip(problem["names"], result["S1_conf"])} if "ST" in result: pretty_result["ST"] = {k : float(v) for k, v in zip(problem["names"], result["ST"])} if "ST_conf" in result: pretty_result["ST_conf"] = {k : float(v) for k, v in zip(problem["names"], result["ST_conf"])} if "S2" in result: pretty_result["S2"] = _S2_to_dict(result["S2"], problem) if "S2_conf" in result: pretty_result["S2_conf"] = _S2_to_dict(result["S2_conf"], problem) if "delta" in result: pretty_result["delta"] = {k : float(v) for k, v in zip(problem["names"], result["delta"])} if "delta_conf" in result: pretty_result["delta_conf"] = {k : float(v) for k, v in zip(problem["names"], result["delta_conf"])} if "vi" in result: pretty_result["vi"] = {k : float(v) for k, v in zip(problem["names"], result["vi"])} if "vi_std" in result: pretty_result["vi_std"] = {k : float(v) for k, v in zip(problem["names"], result["vi_std"])} if "dgsm" in result: pretty_result["dgsm"] = {k : float(v) for k, v in zip(problem["names"], result["dgsm"])} if "dgsm_conf" in result: pretty_result["dgsm_conf"] = {k : float(v) for k, v in zip(problem["names"], result["dgsm_conf"])} if "mu" in result: pretty_result["mu"] = {k : float(v) for k, v in zip(result["names"], result["mu"])} if "mu_star" in result: pretty_result["mu_star"] = {k : float(v) for k, v in zip(result["names"], result["mu_star"])} if "mu_star_conf" in result: pretty_result["mu_star_conf"] = {k : float(v) for k, v in zip(result["names"], result["mu_star_conf"])} if "sigma" in result: pretty_result["sigma"] = {k : float(v) for k, v in zip(result["names"], result["sigma"])} return pretty_result
def gen_params(num_vars, names, bounds, n, save_loc, second_ord=True): """ Generate the parameter sets for the Sobol sensitivity analysis. Saves a file with the information required for the analysis that will be performed later. Parameters ----------- num_vars : int the number of parameters you will vary. names : list list of strings with the names of the parameters bounds : list list of lists, where each inner list contains the upper and lower bounds for a given parameter. n : int number of initial samples to generate from the pseudo-random Sobol sequence. n parameter sets will be generated using the Sobol sequence, then the Saltelli cross-sampling method will be applied to give a total of 2n(p+1) parameter sets to be run if second_ord = True. save_loc : str path to the directory where you would like to save the parameters. second_ord : bool, optional a boolean to indicate whether or not to calculate second order sensitivity indices. If False, only 1st and total order indices will be calculated and n(p+2) parameter sets will be generated. Returns -------- param_sets : numpy ndarray an ndarray where each row is one set of parameter values. You must run your model (in whatever environment is appropriate) with each of the sets of parameters from this array. The output must be stored in the same order as given in this parameter set array (one row of results for each row of parameters). """ # Check that num_vars is an integer if not isinstance(num_vars, int): raise TypeError('num_vars must be an integer') # Check that bounds are specified for every variable if num_vars != len(bounds): raise ValueError('bounds must be same length as num_vars') # Check that a name is given for every parameter if num_vars != len(names): raise ValueError('length of `names` must equal num_vars') problem = {'num_vars': num_vars, 'names': names, 'bounds': bounds} param_sets = saltelli.sample(problem, n, calc_second_order=second_ord) if second_ord: print '%s simulations will be run' % (2*n * (problem['num_vars'] + 1)) elif second_ord is False: print '%s simulations will be run' % (n * (problem['num_vars'] + 2)) # Write the problem description to a file (required to run the analysis # after your model has been run with all the generated parameter sets) body = '' for i, name in enumerate(problem['names']): body += '%s %s %s\n' % (name, problem['bounds'][i][0], problem['bounds'][i][1]) with open(save_loc+'/saparams_%s-parameters_%s-n.txt' % (num_vars, n), 'wb') as params: params.write(body) return param_sets
import sys sys.path.append('../..') from SALib.analyze import sobol from SALib.sample import saltelli from SALib.test_functions import Ishigami from SALib.util import read_param_file # Read the parameter range file and generate samples problem = read_param_file('../../SALib/test_functions/params/Ishigami.txt') # Generate samples param_values = saltelli.sample(problem, 1000, calc_second_order=True) # Run the "model" and save the output in a text file # This will happen offline for external models Y = Ishigami.evaluate(param_values) # Perform the sensitivity analysis using the model output # Specify which column of the output file to analyze (zero-indexed) Si = sobol.analyze(problem, Y, calc_second_order=True, conf_level=0.95, print_to_console=True) # Returns a dictionary with keys 'S1', 'S1_conf', 'ST', and 'ST_conf' # e.g. Si['S1'] contains the first-order index for each parameter, in the same order as the parameter file # The optional second-order indices are now returned in keys 'S2', 'S2_conf' # These are both upper triangular DxD matrices with nan's in the duplicate # entries.
def sample(self, problem, size): return saltelli.sample(problem, size, calc_second_order=self.second_order)
import random as rd # Example: Run Sobol, Morris, or FAST on a test function (Sobol G Function) # The parameters shown for each method are also the default values if omitted # Set random seed (does not affect quasi-random Sobol sampling) seed = 1 np.random.seed(seed) rd.seed(seed) # Read the parameter range file and generate samples param_file = './SALib/test_functions/params/Sobol_G.txt' pf = read_param_file(param_file) # Generate samples (choose method here) param_values = saltelli.sample(100, pf['num_vars'], calc_second_order = True) # param_values = morris_oat.sample(100, pf['num_vars'], num_levels = 10, grid_jump = 5) # param_values = fast_sampler.sample(100, pf['num_vars']) # Samples are given in range [0, 1] by default. Rescale them to your parameter bounds. (If using normal distributions, use "scale_samples_normal" instead) scale_samples(param_values, pf['bounds']) # For Method of Morris, save the parameter values in a file (they are needed in the analysis) # FAST and Sobol do not require this step, unless you want to save samples to input into an external model np.savetxt('SGInput.txt', param_values, delimiter=' ') # Run the "model" and save the output in a text file # This will happen offline for external models Y = Sobol_G.evaluate(param_values) np.savetxt("SGOutput.txt", Y, delimiter=' ')
sys.dont_write_bytecode = True from SALib.sample import saltelli, morris_oat, fast_sampler from SALib.analyze import sobol, morris, extended_fast from SALib.test_functions import Sobol_G, Ishigami from SALib.util import scale_samples, read_param_file import numpy as np import random as rd from ucav_design_1 import DesignFormulation np.random.seed(10) param_file = 'ucav_sensitivity_input.txt' pf = read_param_file(param_file) param_values = saltelli.sample(25, pf['num_vars'], calc_second_order = False) scale_samples(param_values, pf['bounds']) ac = DesignFormulation() ac.load_xls('Baseline1') ac.setup() Y = np.zeros([len(param_values),9]) fid = open('SGOutput2.txt','wt') fid.close() for i,param in enumerate(param_values): out = ac.run_full_analysis(param) Y[i] = out