easyvvuq.sampling.qmc
This sampler is meant to be used with the QMC Analysis module.
1"""This sampler is meant to be used with the QMC Analysis module. 2""" 3 4import chaospy as cp 5from SALib.sample import sobol 6#from SALib.sample import saltelli 7from .base import BaseSamplingElement, Vary 8import logging 9 10__author__ = "Jalal Lakhlili" 11__copyright__ = """ 12 13 Copyright 2018 Robin A. Richardson, David W. Wright 14 15 This file is part of EasyVVUQ 16 17 EasyVVUQ is free software: you can redistribute it and/or modify 18 it under the terms of the Lesser GNU General Public License as published by 19 the Free Software Foundation, either version 3 of the License, or 20 (at your option) any later version. 21 22 EasyVVUQ is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 Lesser GNU General Public License for more details. 26 27 You should have received a copy of the Lesser GNU General Public License 28 along with this program. If not, see <https://www.gnu.org/licenses/>. 29 30""" 31__license__ = "LGPL" 32 33 34class QMCSampler(BaseSamplingElement, sampler_name="QMC_sampler"): 35 def __init__(self, vary, n_mc_samples, count=0): 36 """Create a Quasi Monte Carlo sampler. 37 38 Parameters 39 ---------- 40 41 vary: dict 42 Expects a dictionary where the keys are variable names 43 (inputs for your simulation that you want to vary during 44 sampling) and values are ChaosPy distributions you want to 45 sample from. 46 n_mc_samples : int 47 An estimate for how many samples the monte carlo run will need. 48 count : int 49 This is used to resume sampling. It will skip the first 50 count samples if this parameter is not zero. 51 """ 52 if not isinstance(vary, dict): 53 msg = ("'vary' must be a dictionary of the names of the " 54 "parameters you want to vary, and their corresponding " 55 "distributions.") 56 raise RuntimeError(msg) 57 if len(vary) == 0: 58 msg = "'vary' cannot be empty." 59 raise RuntimeError(msg) 60 61 discrete_input = [isinstance(p, cp.DiscreteUniform) for p in vary.values()] 62 assert (True in discrete_input) == False, \ 63 "QMCSampler cannot handle DiscreteUniform, use MCSampler instead" 64 65 self.vary = Vary(vary) 66 self.n_mc_samples = n_mc_samples 67 68 # List of the probability distributions of uncertain parameters 69 params_distribution = list(vary.values()) 70 71 # Multivariate distribution 72 self.distribution = cp.J(*params_distribution) 73 74 # Generate samples 75 self.n_params = len(vary) 76 77 dist_U = [] 78 for i in range(self.n_params): 79 dist_U.append(cp.Uniform()) 80 dist_U = cp.J(*dist_U) 81 82 problem = { 83 "num_vars": self.n_params, 84 "names": list(vary.keys()), 85 "bounds": [[0, 1]] * self.n_params 86 } 87 88 nodes = sobol.sample(problem, n_mc_samples, calc_second_order=False,scramble=True) 89 90 self._samples = self.distribution.inv(dist_U.fwd(nodes.transpose())) 91 92 self._n_samples = n_mc_samples * (self.n_params + 2) 93 94 # Fast forward to specified count, if possible 95 self.count = 0 96 if count >= self._n_samples: 97 msg = (f"Attempt to start sampler fastforwarded to count {count}, " 98 f"but sampler only has {self._n_samples} samples, therefore" 99 f"this sampler will not provide any more samples.") 100 logging.debug(msg) 101 else: 102 for _ in range(count): 103 self.__next__() 104 105 def is_finite(self): 106 """Can this sampler produce only a finite number of samples.""" 107 return True 108 109 @property 110 def n_samples(self): 111 """Returns the number of samples in this sampler. 112 113 Returns 114 ------- 115 This computed with the formula (d + 2) * N, where d is the number 116 of uncertain parameters and N is the (estimated) number of samples 117 for the Monte Carlo method. 118 """ 119 return self._n_samples 120 121 @property 122 def analysis_class(self): 123 """Return a corresponding analysis class. 124 """ 125 from easyvvuq.analysis import QMCAnalysis 126 return QMCAnalysis 127 128 def __next__(self): 129 if self.count < self.n_samples: 130 run_dict = {} 131 i_par = 0 132 for param_name in self.vary.get_keys(): 133 run_dict[param_name] = self._samples.T[self.count][i_par] 134 i_par += 1 135 self.count += 1 136 return run_dict 137 else: 138 raise StopIteration
35class QMCSampler(BaseSamplingElement, sampler_name="QMC_sampler"): 36 def __init__(self, vary, n_mc_samples, count=0): 37 """Create a Quasi Monte Carlo sampler. 38 39 Parameters 40 ---------- 41 42 vary: dict 43 Expects a dictionary where the keys are variable names 44 (inputs for your simulation that you want to vary during 45 sampling) and values are ChaosPy distributions you want to 46 sample from. 47 n_mc_samples : int 48 An estimate for how many samples the monte carlo run will need. 49 count : int 50 This is used to resume sampling. It will skip the first 51 count samples if this parameter is not zero. 52 """ 53 if not isinstance(vary, dict): 54 msg = ("'vary' must be a dictionary of the names of the " 55 "parameters you want to vary, and their corresponding " 56 "distributions.") 57 raise RuntimeError(msg) 58 if len(vary) == 0: 59 msg = "'vary' cannot be empty." 60 raise RuntimeError(msg) 61 62 discrete_input = [isinstance(p, cp.DiscreteUniform) for p in vary.values()] 63 assert (True in discrete_input) == False, \ 64 "QMCSampler cannot handle DiscreteUniform, use MCSampler instead" 65 66 self.vary = Vary(vary) 67 self.n_mc_samples = n_mc_samples 68 69 # List of the probability distributions of uncertain parameters 70 params_distribution = list(vary.values()) 71 72 # Multivariate distribution 73 self.distribution = cp.J(*params_distribution) 74 75 # Generate samples 76 self.n_params = len(vary) 77 78 dist_U = [] 79 for i in range(self.n_params): 80 dist_U.append(cp.Uniform()) 81 dist_U = cp.J(*dist_U) 82 83 problem = { 84 "num_vars": self.n_params, 85 "names": list(vary.keys()), 86 "bounds": [[0, 1]] * self.n_params 87 } 88 89 nodes = sobol.sample(problem, n_mc_samples, calc_second_order=False,scramble=True) 90 91 self._samples = self.distribution.inv(dist_U.fwd(nodes.transpose())) 92 93 self._n_samples = n_mc_samples * (self.n_params + 2) 94 95 # Fast forward to specified count, if possible 96 self.count = 0 97 if count >= self._n_samples: 98 msg = (f"Attempt to start sampler fastforwarded to count {count}, " 99 f"but sampler only has {self._n_samples} samples, therefore" 100 f"this sampler will not provide any more samples.") 101 logging.debug(msg) 102 else: 103 for _ in range(count): 104 self.__next__() 105 106 def is_finite(self): 107 """Can this sampler produce only a finite number of samples.""" 108 return True 109 110 @property 111 def n_samples(self): 112 """Returns the number of samples in this sampler. 113 114 Returns 115 ------- 116 This computed with the formula (d + 2) * N, where d is the number 117 of uncertain parameters and N is the (estimated) number of samples 118 for the Monte Carlo method. 119 """ 120 return self._n_samples 121 122 @property 123 def analysis_class(self): 124 """Return a corresponding analysis class. 125 """ 126 from easyvvuq.analysis import QMCAnalysis 127 return QMCAnalysis 128 129 def __next__(self): 130 if self.count < self.n_samples: 131 run_dict = {} 132 i_par = 0 133 for param_name in self.vary.get_keys(): 134 run_dict[param_name] = self._samples.T[self.count][i_par] 135 i_par += 1 136 self.count += 1 137 return run_dict 138 else: 139 raise StopIteration
Baseclass for all EasyVVUQ sampling elements.
Attributes
- sampler_name (str): Name of the particular sampler.
QMCSampler(vary, n_mc_samples, count=0)
36 def __init__(self, vary, n_mc_samples, count=0): 37 """Create a Quasi Monte Carlo sampler. 38 39 Parameters 40 ---------- 41 42 vary: dict 43 Expects a dictionary where the keys are variable names 44 (inputs for your simulation that you want to vary during 45 sampling) and values are ChaosPy distributions you want to 46 sample from. 47 n_mc_samples : int 48 An estimate for how many samples the monte carlo run will need. 49 count : int 50 This is used to resume sampling. It will skip the first 51 count samples if this parameter is not zero. 52 """ 53 if not isinstance(vary, dict): 54 msg = ("'vary' must be a dictionary of the names of the " 55 "parameters you want to vary, and their corresponding " 56 "distributions.") 57 raise RuntimeError(msg) 58 if len(vary) == 0: 59 msg = "'vary' cannot be empty." 60 raise RuntimeError(msg) 61 62 discrete_input = [isinstance(p, cp.DiscreteUniform) for p in vary.values()] 63 assert (True in discrete_input) == False, \ 64 "QMCSampler cannot handle DiscreteUniform, use MCSampler instead" 65 66 self.vary = Vary(vary) 67 self.n_mc_samples = n_mc_samples 68 69 # List of the probability distributions of uncertain parameters 70 params_distribution = list(vary.values()) 71 72 # Multivariate distribution 73 self.distribution = cp.J(*params_distribution) 74 75 # Generate samples 76 self.n_params = len(vary) 77 78 dist_U = [] 79 for i in range(self.n_params): 80 dist_U.append(cp.Uniform()) 81 dist_U = cp.J(*dist_U) 82 83 problem = { 84 "num_vars": self.n_params, 85 "names": list(vary.keys()), 86 "bounds": [[0, 1]] * self.n_params 87 } 88 89 nodes = sobol.sample(problem, n_mc_samples, calc_second_order=False,scramble=True) 90 91 self._samples = self.distribution.inv(dist_U.fwd(nodes.transpose())) 92 93 self._n_samples = n_mc_samples * (self.n_params + 2) 94 95 # Fast forward to specified count, if possible 96 self.count = 0 97 if count >= self._n_samples: 98 msg = (f"Attempt to start sampler fastforwarded to count {count}, " 99 f"but sampler only has {self._n_samples} samples, therefore" 100 f"this sampler will not provide any more samples.") 101 logging.debug(msg) 102 else: 103 for _ in range(count): 104 self.__next__()
Create a Quasi Monte Carlo sampler.
Parameters
- vary (dict): Expects a dictionary where the keys are variable names (inputs for your simulation that you want to vary during sampling) and values are ChaosPy distributions you want to sample from.
- n_mc_samples (int): An estimate for how many samples the monte carlo run will need.
- count (int): This is used to resume sampling. It will skip the first count samples if this parameter is not zero.
def
is_finite(self):
106 def is_finite(self): 107 """Can this sampler produce only a finite number of samples.""" 108 return True
Can this sampler produce only a finite number of samples.
n_samples
110 @property 111 def n_samples(self): 112 """Returns the number of samples in this sampler. 113 114 Returns 115 ------- 116 This computed with the formula (d + 2) * N, where d is the number 117 of uncertain parameters and N is the (estimated) number of samples 118 for the Monte Carlo method. 119 """ 120 return self._n_samples
Returns the number of samples in this sampler.
Returns
- This computed with the formula (d + 2) * N, where d is the number
- of uncertain parameters and N is the (estimated) number of samples
- for the Monte Carlo method.