Source code for easyvvuq.sampling.mc_sampler

from . import RandomSampler
from .base import Vary
import logging
import numpy as np
import chaospy as cp

__author__ = "Wouter Edeling"
"""
    Copyright 2018 Robin A. Richardson, David W. Wright

    This file is part of EasyVVUQ

    EasyVVUQ is free software: you can redistribute it and/or modify
    it under the terms of the Lesser GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    EasyVVUQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    Lesser GNU General Public License for more details.

    You should have received a copy of the Lesser GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

"""
__license__ = "LGPL"


[docs]class MCSampler(RandomSampler, sampler_name='mc_sampler'): """ This is a Monte Carlo sampler, used to compute the Sobol indices, mean and variance of the different QoIs. """ def __init__(self, vary, n_mc_samples, **kwargs): """ Parameters ---------- + vary : a dictionary of chaospy input distributions + n_mc_samples : the number of MC samples. The total number of MC samples required to compute the Sobol indices using a Saltelli sampling plan will be n_mc_samples * (n_params + 1), where n_params is the number of uncertain parameters in vary. Returns ------- None. """ super().__init__(vary=vary, max_num=n_mc_samples, **kwargs) # the number of uncertain inputs self.n_params = len(vary) # the number of MC samples, for each of the n_params + 2 input matrices self.n_mc_samples = n_mc_samples self.vary = Vary(vary) self.count = 0 # joint distribution self.joint = cp.J(*list(vary.values())) # create the Saltelli sampling plan self.saltelli(n_mc_samples) def __next__(self): if self.is_finite(): if self.count >= self.max_num: raise StopIteration run_dict = {} for idx, param_name in enumerate(self.vary.get_keys()): run_dict[param_name] = self.xi_mc[self.count][idx] self.count += 1 return run_dict
[docs] def saltelli(self, n_mc): """ Generates a Saltelli sampling plan of n_mc*(n_params + 2) input samples needed to compute the Sobol indices. Stored in xi_mc. Method: A. Saltelli, Making best use of model evaluations to compute sensitivity indices, Computer Physics Communications, 2002. Parameters ---------- n_mc : the number of Monte Carlo samples per input matrix. The total number of samples is n_mc*(n_params + 2) Returns ------- None. """ logging.debug('Drawing input samples for Sobol index computation.') # the number of MC samples required to compute the Sobol indices self.max_num = n_mc * (self.n_params + 2) logging.debug('Generating {} input samples spread over {} sample matrices.'.format( self.max_num, self.n_params + 2)) # Matrix M1, the sample matrix M_1 = self.joint.sample(n_mc).T # Matrix M2, the resample matrix (see reference above) M_2 = self.joint.sample(n_mc).T # array which contains all samples self.xi_mc = np.zeros([self.max_num, self.n_params]) # The order in which the inputs samples must be stored is # [M2_1 N1_1, ..., Nd_1, M1_1, M2_2, N1_2, ...Nd_2, M1_2, M1_3 etc] # number of different sampling matrices step = self.n_params + 2 # store M2 first, with entries separated by step places if M_2.ndim == 1: M_2 = M_2.reshape([-1, 1]) self.xi_mc[0:self.max_num:step] = M_2 # store M1 entries last if M_1.ndim == 1: M_1 = M_1.reshape([-1, 1]) self.xi_mc[(step - 1):self.max_num:step] = M_1 # store N_i entries between M2 and M1 for i in range(self.n_params): N_i = np.array(M_2) # N_i = M2 with i-th colum from M1 N_i[:, i] = M_1[:, i] self.xi_mc[(i + 1):self.max_num:step] = N_i logging.debug('Done.')
@property def analysis_class(self): """Return a corresponding analysis class. """ from easyvvuq.analysis import QMCAnalysis return QMCAnalysis