def sobol_analysis(sp, VPD, tmax): # retrieve sample with open( '../Si_' + sp + '_vpd' + str(int(VPD)) + '_tmax' + str(tmax) + '_perPlantNL_outcomes.pickle', 'rb') as handle: Y = pickle.load(handle) # perform analysis problem = define_problem(sp) Si_A = sobol.analyze(problem, Y[:, 1], calc_second_order=True, print_to_console=True) try: Si_H = sobol.analyze(problem, Y[:, 0], calc_second_order=True, print_to_console=True) except: pass Si_depo = np.zeros((n_vars, 4)) Si_depo[:, 0] = Si_H['ST'] Si_depo[:, 1] = Si_H['ST_conf'] Si_depo[:, 2] = Si_A['ST'] Si_depo[:, 3] = Si_A['ST_conf'] # Si_depo[:,0] = Si_H['S1'] # Si_depo[:,1] = Si_H['S1_conf'] # Si_depo[:,2] = Si_A['S1'] # Si_depo[:,3] = Si_A['S1_conf'] return Si_depo
def test_include_print(): problem, param_values = setup_samples() Y = Ishigami.evaluate(param_values) sobol.analyze(problem, Y, calc_second_order=True, conf_level=0.95, print_to_console=True)
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 test_bad_conf_level(): problem, param_values = setup_samples() Y = Ishigami.evaluate(param_values) with raises(RuntimeError): sobol.analyze(problem, Y, calc_second_order=True, conf_level=1.01, print_to_console=False)
def sensititivity_analysis(path_to_unconstrained_potentials_prefer_pv, path_to_unconstrained_potentials_prefer_wind, path_to_demand, path_to_population, path_to_units, path_to_result_urban_population, path_to_result_rural_population, path_to_result_number, threads): demand = pd.read_csv(path_to_demand, index_col=0)["demand_twh_per_year"] population = pd.read_csv(path_to_population, index_col=0)["population_sum"].reindex(demand.index) area_size_km2 = area_in_squaremeters(gpd.read_file(path_to_units).set_index("id").reindex(demand.index)) / 1e6 urban = (population / area_size_km2) >= URBAN_POPULATION_DENSITY_THRESHOLD unconstrained_prefer_pv = pd.read_csv( path_to_unconstrained_potentials_prefer_pv, index_col=0 ).reindex(demand.index) unconstrained_prefer_wind = pd.read_csv( path_to_unconstrained_potentials_prefer_wind, index_col=0 ).reindex(demand.index) problem = { 'num_vars': 6, 'names': ['share-protected-areas-used', 'share-farmland-used', 'share-forest-used-for-wind', 'share-other-land-used', 'share-offshore-used', 'share-rooftops-used'], 'bounds': [[0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1]] } param_values = saltelli.sample(problem, 80) with Pool(threads) as pool: y = pool.map( evaluate_model, [[unconstrained_prefer_pv, unconstrained_prefer_wind, demand, population, urban] + [x] for x in param_values] ) y_urban_pop = np.zeros([param_values.shape[0]]) y_rural_pop = np.zeros([param_values.shape[0]]) y_num = np.zeros([param_values.shape[0]]) for i, x in enumerate(y): y_urban_pop[i], y_rural_pop[i], y_num[i] = x s_urban_pop = sobol.analyze(problem, y_urban_pop) s_rural_pop = sobol.analyze(problem, y_rural_pop) s_num = sobol.analyze(problem, y_num) with open(path_to_result_urban_population, "w") as f_out: print_indices(s_urban_pop, problem, True, f_out) with open(path_to_result_rural_population, "w") as f_out: print_indices(s_rural_pop, problem, True, f_out) with open(path_to_result_number, "w") as f_out: print_indices(s_num, problem, True, f_out)
def test_Sobol_with_no_NAN_flag_as_default(): ''' Test if sobol.analyze raise ValueError when nan are passed with ignore_nans flag is set to False as default value ''' problem, model_results, _ = setup_samples() # Should raise a ValueError type of error with pytest.raises(ValueError): sobol.analyze(problem, model_results)
def analyze_output(self, problem, output): ''' Analyze the output after reducing the values using the sobol.analyze function from SALib The returned value is either a dictionary with an analysis per state, or a single analysis object if there is only one input list ''' if isinstance(output, dict): # Perform the sobol analysis seperately for every status return { var: sobol.analyze(problem, output[var]) for var in self.states } elif isinstance(output, np.ndarray): return sobol.analyze(problem, output)
def analyse_results(df): global problem si_friends_score = sobol.analyze(problem, df['friends_score'].values, print_to_console=True) si_social_dist = sobol.analyze(problem, df['social_distance'].values, print_to_console=True) si_spatial_dist = sobol.analyze(problem, df['spatial_distance'].values, print_to_console=True) return [si_friends_score, si_social_dist, si_spatial_dist]
def Sobol(sp, n_runs): 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 = { '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) VPD = 2.0 gridsize = 10 Si_depo = np.zeros( (gridsize, n_vars, 4)) # number of increments, parameters, Assm/HF/CIs for i, tmax in enumerate(np.linspace(60, 240, gridsize)): print i, ''' 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) # perform analysis Si_A = sobol.analyze(problem, Y[:, 1], calc_second_order=False, print_to_console=True) try: Si_H = sobol.analyze(problem, Y[:, 0], calc_second_order=False, print_to_console=True) except: pass # store Si_depo[i, :, 0] = Si_H['ST'] Si_depo[i, :, 1] = Si_A['ST_conf'] Si_depo[i, :, 2] = Si_H['ST'] Si_depo[i, :, 3] = Si_A['ST_conf'] with open( '/Users/xuefeng/Dropbox/Projects/Isohydricity/Sobol/Si_' + sp + '_vpd' + str(int(VPD)) + '_tmax' + str(tmax) + '.pickle', 'wb') as handle: pickle.dump(Si_depo, handle) return Si_depo
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 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 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 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 analyse_sobal_sensitivity(salib_problem, output_to_analyse, second_order=False, num_resample=100, conf_level=0.95): """ Run the SALib sobal sensitivity analysis Args: salib_problem (dict): The salib problem used to make the samples output_to_analyse (np.array): A np.array containing the output of interest. second_order (bool): Look at second order interactions. Default=Fa;se num_resample(int): salib, number of resamples. Default=100 conf_level (float): salib confidence level, default = 0.95 Returns: A dataframe containing the output from the sobal sensitivity analysis """ analysis = sobol.analyze(salib_problem, output_to_analyse, calc_second_order=second_order, num_resamples=num_resample, conf_level=conf_level, print_to_console=False, parallel=False, n_processors=None) rows = salib_problem['names'] dataframe_output = pd.DataFrame(analysis, index=rows) return dataframe_output
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 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 performAnalysis(problem, Y): Si = sobol.analyze(problem, Y, print_to_console=True) pd.DataFrame.from_dict(Si, orient='index').to_csv('sa_results.csv') return
def process(args): imethod, method = args print("Processing sobol for " + str(method)) y = Y[Y.columns[imethod]] res = sobol.analyze(problem, y.to_numpy(), calc_second_order=True) return imethod, res
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 perform_SALib_sobol(model, model_output, output_name, subplot): # Returns a dict with a problem specificatin as required by SALib problem = get_SALib_problem(model.uncertainties) Si = sobol.analyze(problem, model_output, calc_second_order=True, print_to_console=False) # If the total-order indices are substantially larger than the first-order indices, # then there is likely higher-order interactions occurring. We can look at the second-order indices # to see these higher-order interactions scores_filtered = {k: Si[k] for k in ['ST', 'ST_conf', 'S1', 'S1_conf']} Si_df = pd.DataFrame(scores_filtered, index=problem['names']) Si_df.sort_values(by='ST', ascending=False) sns.set_style('white') indices = Si_df[['S1', 'ST']] err = Si_df[['S1_conf', 'ST_conf']] indices.plot.bar(yerr=err.values.T, ax=subplot) print("\n" + output_name) print("") print(Si_df)
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 main(): """Run Sobol Analysis""" # Setup Problem Def For Sobol Analysis. This Should match the filemaker.py problem statement. problem = { 'num_vars': 8, 'names': [ 'Volume Fraction', 'E1f', 'E2f', 'Nu12f', 'Nu23f', 'G12f', 'EMa', 'NuMa' ], 'bounds': [[.3, .8], [229000 * .7, 229000 * 1.3], [14000 * .7, 14000 * 1.3], [.3 * .7, .3 * 1.3], [.3 * .7, .3 * 1.3], [20000 * .7, 20000 * 1.3], [4340 * .7, 4340 * 1.3], [.34 * .7, .34 * 1.3]] } # Import Data targdir = (os.path.dirname(os.path.abspath(__name__))) basename = os.path.join(targdir, "UnitCell_compiled.csv") data = pd.read_csv(basename) # Parse data into separate valriables E2vals = data['Composite E2'].values nu23vals = data['Composite nu23'].values ## Perform analysis print('Composite E2:') SiE2 = sobol.analyze(problem, E2vals, print_to_console=True, calc_second_order=False) print('\n') print('Composite nu23:') Sinu23 = sobol.analyze(problem, nu23vals, print_to_console=True, calc_second_order=False) print('\n') # Write Results to CSV SiE2Out = pd.DataFrame(SiE2, index=problem['names']) SiE2Out.to_csv('SiE2.csv') Sinu23Out = pd.DataFrame(Sinu23, index=problem['names']) Sinu23Out.to_csv('Sinu23.csv')
def test_Sobol_with_NAN(): ''' Test if sobol.analyze can calculate S1 and ST with NAN values in the model results. ''' problem, model_results, _ = setup_samples() out = sobol.analyze(problem, model_results, ignore_nans=True) assert np.all(np.isfinite(out['S1'])), 'S1 index has NAN values' assert np.all(np.isfinite(out['ST'])), 'ST index has NAN values'
def fit(self, X, y): """ Fits the regressor to the data `(X, y)` and performs a sensitivity analysis on the result of the regression. :param X: Training data :param y: Target values :return: `self` """ from numpy import argpartition N = len(X[0]) if (self.domain is None) or (self.probs is None): self._avg_fucn(X, y) if self.regressor is None: from sklearn.svm import SVR self.regressor = SVR() self.regressor.fit(self.domain, self.probs) bounds = [[ min(self.domain[:, idx]) - self.margin, max(self.domain[:, idx]) + self.margin ] for idx in range(N)] problem = dict(num_vars=N, names=['x%d' % idx for idx in range(N)], bounds=bounds) res = [] if self.method == 'sobol': from SALib.sample import saltelli from SALib.analyze import sobol param_values = saltelli.sample(problem, self.num_smpl) y_ = self.regressor.predict(param_values) res = sobol.analyze(problem, y_)['ST'] self.weights_ = res elif self.method == 'morris': from SALib.sample import morris as mrs from SALib.analyze import morris param_values = mrs.sample(problem, self.num_smpl, num_levels=self.num_levels) y_ = self.regressor.predict(param_values) res = morris.analyze(problem, param_values, y_, num_levels=self.num_levels)['mu_star'] self.weights_ = res elif self.method == 'delta-mmnt': from SALib.sample import latin from SALib.analyze import delta param_values = latin.sample(problem, self.num_smpl) y_ = self.regressor.predict(param_values) res = delta.analyze(problem, param_values, y_, num_resamples=self.num_resmpl)['delta'] self.weights_ = res self.top_features_ = argpartition( res, -self.n_features_to_select)[-self.n_features_to_select:] return self
def sobol_index(input_filename, N, B): import sys import numpy as np import time sys.path.append('./SALib-master') from SALib.analyze import sobol from SALib.util import read_param_file start = time.time() Y_names = ['NPV_Abat.txt', 'NPV_Dam.txt'] #Load in data filename = "SALib/%s" % input_filename problem = read_param_file(filename, ' ') S1 = np.zeros((29, 2)) S1_conf = np.zeros((29, 2)) S2 = np.zeros((29, 29, 2)) S2_conf = np.zeros((29, 29, 2)) ST = np.zeros((29, 2)) ST_conf = np.zeros((29, 2)) cnt = 0 for i in range(2): filename = Y_names[i] Y = np.loadtxt(filename) Y = Y[:, 17] #2200 Si = sobol.analyze(problem, Y, calc_second_order=True, conf_level=0.95, num_resamples=B, print_to_console=False, parallel=True, n_processors=15) S1[:, cnt] = Si.get("S1") S1_conf[:, cnt] = Si.get("S1_conf") S2[:, :, cnt] = Si.get("S2") S2_conf[:, :, cnt] = Si.get("S2_conf") ST[:, cnt] = Si.get("ST") ST_conf[:, cnt] = Si.get("ST_conf") cnt = cnt + 1 filename = "Dam_%i.txt" % N np.savez(filename, S1=S1, S1_conf=S1_conf, S2=S2, S2_conf=S2_conf, ST=ST, ST_conf=ST_conf) end = time.time() print(end - start)
def sensitivity_sobol(output, param_ranges, measures=None, **kwargs): """ Calculates Sobol Sensitivity Indices and adds them to the output, using :func:`SALib.analyze.sobol.analyze`. Arguments: output (DataDict): The output of an experiment that was set to only one iteration (default) and used a parameter sample that was generated with :func:`sample_saltelli`. param_ranges (dict): The same dictionary that was used for the generation of the parameter sample with :func:`sample_saltelli`. measures (str or list of str, optional): The measures that should be used for the analysis. If none are passed, all are used. **kwargs: Will be forwarded to :func:`SALib.analyze.sobol.analyze`. The kwarg ``calc_second_order`` must be the same as for :func:`sample_saltelli`. """ # STEP 1 - Convert param_ranges to SALib Format param_ranges_tuples = {k: v for k, v in param_ranges.items() if isinstance(v, tuple)} param_ranges_salib = param_tuples_to_salib(param_ranges_tuples) # STEP 2 - Calculate Sobol Sensitivity Indices if measures is None: measures = output.measures.columns if isinstance(measures, str): measures = make_list(measures) dfs_si = [] dfs_si_conf = [] dfs_list = [dfs_si, dfs_si_conf] for measure in measures: y = np.array(output.measures[measure]) si = sobol.analyze(param_ranges_salib, y, **kwargs) # Make dataframes out of sensitivities keys_list = [['S1', 'ST'], ['S1_conf', 'ST_conf']] for dfs, keys in zip(dfs_list, keys_list): s = {k: v for k, v in si.items() if k in keys} df = pd.DataFrame(s) var_pars = output._combine_pars(varied=True, fixed=False) df['parameter'] = var_pars.keys() df['measure'] = measure df = df.set_index(['measure', 'parameter']) dfs.append(df) output['sensitivity'] = pd.concat(dfs_si) output['sensitivity_conf'] = pd.concat(dfs_si_conf) # TODO Second-Order Entries Missing return output
def principal_feature_analysis(self, calc_second_order=False): mins = self.tol_df.min() maxs = self.tol_df.max() problem = { 'num_vars': len(self.feature_names), 'names': self.feature_names, 'bounds': [[mins[i], maxs[i]] for i in range(len(mins))] } results = self.sobol_sampling(problem, calc_second_order=calc_second_order) sizes = list(results.loc[:, "droplet_size"]) gens = list(results.loc[:, "generation_rate"]) si_size = sobol.analyze(problem, np.array(sizes), calc_second_order=calc_second_order, print_to_console=False) si_gen = sobol.analyze(problem, np.array(gens), calc_second_order=calc_second_order, print_to_console=False) return si_size, si_gen
def sobol_analysis(self, num_samples, prob_def, use_torch=False, var_types=None): def create_input_tensor(name, samples): type_info = var_types[name] if type_info[0] == str: (val1, val2) = type_info[1] return np.where(samples >= 0.5, val1, val2) else: return torch.tensor(samples) def get_input(name, sample): type_info = var_types[name] if type_info[0] == str: (val1, val2) = type_info[1] return val1 if sample >= 0.5 else val2 else: return sample samples = saltelli.sample(prob_def, num_samples, calc_second_order=True) if use_torch: samples = np.split(samples, samples.shape[1], axis=1) samples = [s.squeeze() for s in samples] if var_types is None: values = { n: torch.tensor(s) for n, s in zip(prob_def["names"], samples) } else: values = { n: create_input_tensor(n, s) for n, s in zip(prob_def["names"], samples) } Y = self.run(values, torch_size=len(samples[0])).numpy() else: Y = np.zeros(samples.shape[0]) for i, sample in enumerate(samples): if var_types is None: values = {n: v for n, v in zip(prob_def["names"], sample)} else: values = { n: get_input(n, val) for n, val in zip(prob_def["names"], sample) } res = self.run(values) Y[i] = res return sobol.analyze(prob_def, Y)
def analyze(self, output_simulation): problem = { 'num_vars': len(self.constants_included) + len(self.initial_included), 'names': self.constants_included + self.initial_included, 'bounds': self.bounds } #Do the sobel analysis Si = sobol.analyze(problem, output_simulation) print (self.constants_included, self.initial_included) print("Sobel first index: {}".format(Si['S1'])) print("Sobel total index: {}".format(Si['ST']))
def d_eff(): problem = { 'num_vars': 3, 'names': ['D', 'q', 'l'], 'bounds': [[gfp // 10, sa * 10], [0.001, 10], [25, 200]] } param_values = saltelli.sample(problem, 10000) Y = np.array([D_eff(*pv) for pv in param_values]) return sobol.analyze(problem, Y, print_to_console=True)
def sobolanalysis(qoi): problem = problem_definition() Si = analyze( problem, qoi, calc_second_order=calc_second_order(), print_to_console=False, seed=get_seed(), ) return Si
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 _analizar(símismo, vec_res, muestra, ops): if símismo.método == 'sobol': return sobol.analyze(problem=símismo.problema, Y=vec_res, **ops) elif símismo.método == 'fast': return fast.analyze(problem=símismo.problema, Y=vec_res, **ops) elif símismo.método == 'morris': return morris_anlz.analyze(problem=símismo.problema, X=muestra, Y=vec_res, **ops) elif símismo.método == 'dmim': return delta.analyze(problem=símismo.problema, X=muestra, Y=vec_res, **ops) elif símismo.método == 'dgsm': return dgsm.analyze(problem=símismo.problema, X=muestra, Y=vec_res, **ops) elif símismo.método == 'ff': return ff_anlz.analyze(problem=símismo.problema, X=muestra, Y=vec_res, **ops) else: raise ValueError('Método de análisis de sensibilidad "{}" no reconocido.'.format(símismo.método))
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 sensiAnal(model_results,Problem): weather = [] X = [] Y = [] for row in model_results: weather.append(row[0]) X.append(row[1:len(row)-2]) Y.append(row[len(row)-1]) climate = ['1A','2A','2B','3A','3B','3C','4A','4B','4C','5A','5B','6A','6B','7A','8A'] S1 = []#first-order indices S1_conf = []#confidence of first-order indices ST = []#total-order indices ST_conf = []#confidence of total-order indices Name = [] Clim = [] for x in climate: X_clim = [] Y_clim = [] for ind,val in enumerate(weather): if val == x: X_clim.append(X[ind]) Y_clim.append(Y[ind]) for row in Problem: if row[0] == x: problem = row[1] if len(X_clim) > 0: Si = sobol.analyze(problem,np.array(Y_clim),print_to_console=False) s1_clim = Si['S1'] s1_conf_clim = Si['S1_conf'] st_clim = Si['ST'] st_conf_clim = Si['ST_conf'] name_clim = problem['names'] S1.append(s1_clim) S1_conf.append(s1_conf_clim) ST.append(st_clim) ST_conf.append(st_conf_clim) Name.append(name_clim) Clim.append(x) return Clim,Name,S1,S1_conf,ST,ST_conf
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 analyze(results, ooi): '''analyze results using SALib sobol, returns a dataframe ''' _, outcomes = results problem = get_SALib_problem(lake_model.uncertainties) y = outcomes[ooi] sobol_indices = sobol.analyze(problem, y) sobol_stats = {key: sobol_indices[key] for key in ['ST', 'ST_conf', 'S1', 'S1_conf']} sobol_stats = pd.DataFrame(sobol_stats, index=problem['names']) sobol_stats.sort_values(by='ST', ascending=False) s2 = pd.DataFrame(sobol_indices['S2'], index=problem['names'], columns=problem['names']) s2_conf = pd.DataFrame(sobol_indices['S2_conf'], index=problem['names'], columns=problem['names']) return sobol_stats, s2, s2_conf
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 fid = open('SGOutput2.txt','at') for val in out: fid.write('%.10e '%val) fid.write('\n') fid.close() for i in range(len(out)): Si = sobol.analyze(param_file, 'SGOutput2.txt', column = i, calc_second_order = False, conf_level = 0.95)
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 test_incorrect_second_order_setting(): # note this will still be a problem if N(2D+2) also divides by (D+2) problem,param_values = setup_samples(N=501, calc_second_order=False) Y = Ishigami.evaluate(param_values) sobol.analyze(problem, Y, calc_second_order=True)
def test_incorrect_sample_size(): problem,param_values = setup_samples() Y = Ishigami.evaluate(param_values) sobol.analyze(problem, Y[:-10], calc_second_order=True)
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
__author__ = 'Newsteinwell' from SALib.sample import saltelli from SALib.analyze import sobol from SALib.test_functions import Ishigami import numpy as np problem = { 'num_vars': 3, 'names': ['x1', 'x2', 'x3'], 'bounds': [[-3.14159265359, 3.14159265359], [-3.14159265359, 3.14159265359], [-3.14159265359, 3.14159265359]] } # Generate samples param_values = saltelli.sample(problem, 1000, calc_second_order=True) # Run model (example) Y = Ishigami.evaluate(param_values) # Perform analysis Si = sobol.analyze(problem, Y, print_to_console=False) print Si # Returns a dictionary with keys 'S1', 'S1_conf', 'ST', and 'ST_conf' # (first and total-order indices with bootstrap confidence intervals)
def sensitivity_main(locator, weather_path, gv, output_parameters, groups_var, num_samples, method): """ This function creates the sensitivity analysis problem for either sobol or morris methods. It calculates the number of samples for the analysis and calls the CEA to run every sample. :param locator: locator class :param weather_path: path to weather file :param gv: global variables class :param output_parameters: list of output parameters to analyse :param groups_var: list of names of groups of variables to analyse. Possible values are: 'THERMAL', 'ARCHITECTURE', 'INDOOR_COMFORT', 'INTERNAL_LOADS'. This list links to the probability density functions of the variables contained in locator.get_uncertainty_db(). :param num_samples: number of samples to calculate :param method: 'morris' or 'sobol' method :return: .xls file stored in locator.get_sensitivity_output(). every spreadsheet of the workbook stores a matrix whose content is the output of one sensitivity parameter and one output_parameter: - columns: groups of variables to anlyse. - rows: number of buildings of the case study under analysis. - content: sensitivity parameter per output parameter every sensitivity parameter depends on the method: - sobol: S1, ST and ST_conf >>for more information refereto SaBil documentation - morris: mu_star, sigma and mu_star_conf >> for more information refereto SaBil documentation """ t0 = time.clock() # Model constants gv.multiprocessing = False # false to deactivate the multiprocessing in the demand algorithm # write only monthly instead of hourly values gv.demand_writer = cea.demand.demand_writers.MonthlyDemandWriter(gv) # Define the model inputs pdf = pd.concat([pd.read_excel(locator.get_uncertainty_db(), group, axis=1) for group in groups_var]) num_vars = pdf.name.count() # integer with number of variables names = pdf.name.values # [,,] with names of each variable bounds = [] for var in range(num_vars): limits = [pdf.loc[var, 'min'], pdf.loc[var, 'max']] bounds.append(limits) # define the problem problem = {'num_vars': num_vars, 'names': names, 'bounds': bounds, 'groups': None} # create samples (combinations of variables) if method is 'sobol': second_order = False samples = sampler_sobol(problem, N=num_samples, calc_second_order=second_order) else: grid = 2 levels = 4 optimal_trajects = int(0.04 * num_samples) samples = sampler_morris(problem, N=num_samples, grid_jump=grid, num_levels=levels) #optimal_trajectories=optimal_trajects, local_optimization=True) gv.log('Sampling done, time elapsed: %(time_elapsed).2f seconds', time_elapsed=time.clock() - t0) gv.log('Running %i samples' %len(samples)) #call the CEA for building demand and store the results of every sample in a vector simulations = screening_cea_multiprocessing(samples, names, output_parameters, locator, weather_path, gv) gv.log('Simulations done - time elapsed: %(time_elapsed).2f seconds', time_elapsed=time.clock() - t0) #do morris analysis and output to excel buildings_num = simulations[0].shape[0] writer = pd.ExcelWriter(locator.get_sensitivity_output(method, num_samples)) for parameter in output_parameters: results_1 = [] results_2 = [] results_3 = [] for building in range(buildings_num): simulations_parameter = np.array([x.loc[building, parameter] for x in simulations]) if method is 'sobol': VAR1, VAR2, VAR3 = 'S1', 'ST', 'ST_conf' sobol_result = sobol.analyze(problem, simulations_parameter, calc_second_order=second_order) results_1.append(sobol_result['S1']) results_2.append(sobol_result['ST']) results_3.append(sobol_result['ST_conf']) else: VAR1, VAR2, VAR3 = 'mu_star', 'sigma', 'mu_star_conf' morris_result = morris.analyze(problem, samples, simulations_parameter, grid_jump=grid, num_levels=levels) results_1.append(morris_result['mu_star']) results_2.append(morris_result['sigma']) results_3.append(morris_result['mu_star_conf']) pd.DataFrame(results_1, columns=problem['names']).to_excel(writer, parameter + VAR1) pd.DataFrame(results_2, columns=problem['names']).to_excel(writer, parameter + VAR2) pd.DataFrame(results_3, columns=problem['names']).to_excel(writer, parameter + VAR3) writer.save() gv.log('Sensitivity analysis done - time elapsed: %(time_elapsed).2f seconds', time_elapsed=time.clock() - t0)
# 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=' ') # Perform the sensitivity analysis using the model output # Specify which column of the output file to analyze (zero-indexed) sobol.analyze(param_file, 'SGOutput.txt', column = 0, calc_second_order = True) # morris.analyze(param_file, 'SGInput.txt', 'SGOutput.txt', column = 0) # extended_fast.analyze(param_file, 'SGOutput.txt', column = 0)