Ejemplo n.º 1
0
def ppce_1d_test():
    """
    Test PPCE over 1D parameter space
    """
    def fEx(x, fType, qInfo):
        """
        Simulator
        """
        yEx = analyticTestFuncs.fEx1D(x, fType, qInfo).val
        return yEx

    #
    def noiseGen(n, noiseType):
        """
        Generate a 1D numpy array of the standard deviation of the observation noise
        """
        if noiseType == 'h**o':  #homoscedastic noise
            sd = 0.1  #(non-zero, to avoid instabilities)
            sdV = [sd] * n
            sdV = np.asarray(sdV)
        elif noiseType == 'hetero':  #heteroscedastic noise
            sdMin = 0.02
            sdMax = 0.2
            sdV = sdMin + (sdMax - sdMin) * np.linspace(0.0, 1.0, n)
        return sdV

    #
    def trainData(xInfo, n, noiseType, trainSamplyType, distType, fType):
        """
        Create training data D={X,Y}
        """
        X_ = sampling.trainSample(sampleType=trainSampleType,
                                  GQdistType=distType,
                                  qInfo=xInfo,
                                  nSamp=n)
        x = X_.q
        sdV = noiseGen(n, noiseType)
        y = fEx(x, fType, xInfo) + sdV * np.random.randn(n)
        return x, y, sdV

    #
    #-------SETTINGS------------------------------
    distType = 'Norm'  #type of distribution of the parameter (Acc. gPCE rule)
    trainSampleType = 'normRand'  #how to draw the trainining samples, see trainSample in sampling.py
    qInfo = [0.5, 0.9]  #info about the parameter
    #if 'Unif', qInfo =[min(q),max(q)]
    #if 'Norm', qInfo=[m,v] for q~N(m,v^2)
    n = 30  #number of training samples in GPR
    noiseType = 'h**o'  #'h**o'=homoscedastic, 'hetero'=heterscedastic
    nGQtest = 10  #number of test points (=Gauss quadrature nodes)
    #GPR options
    nIter_gpr = 1000  #number of iterations in optimization of hyperparameters
    lr_gpr = 0.2  #learning rate for the optimization of the hyperparameters
    convPlot_gpr = True  #plot convergence of the optimization of the GPR hyperparameters
    nMC = 1000  #number of samples drawn from GPR surrogate to construct estimates
    #  for the moments of f(q)
    #---------------------------------------------
    if distType == 'Unif':
        fType = 'type1'
    elif distType == 'Norm':
        fType = 'type2'
    #(1) generate synthetic training data
    qTrain, yTrain, noiseSdev = trainData(qInfo, n, noiseType, trainSampleType,
                                          distType, fType)
    #(2) assemble the ppceDict dictionary
    ppceDict = {
        'nGQtest': nGQtest,
        'qInfo': qInfo,
        'distType': distType,
        'nIter_gpr': nIter_gpr,
        'lr_gpr': lr_gpr,
        'convPlot_gpr': convPlot_gpr,
        'nMC': nMC
    }
    #(3) construct the ppce
    ppce_ = ppce(qTrain, yTrain, noiseSdev, ppceDict)
    fMean_samples = ppce_.fMean_samps
    fVar_samples = ppce_.fVar_samps
    optOut = ppce_.optOut
    #(4) postprocess
    #   (a) plot the GPR surrogate along with response from the exact simulator
    pltOpts = {'title': 'PPCE, 1D param, %s-scedastic noise' % noiseType}
    gpr_torch.gprPlot(pltOpts).torch1d(optOut['post_f'], optOut['post_obs'],
                                       qTrain, yTrain, optOut['qTest'][0],
                                       fEx(optOut['qTest'][0], fType, qInfo))
    #   (b) plot histogram and pdf of the mean and variance distribution
    statsUQit.pdfFit_uniVar(fMean_samples, True, [])
    statsUQit.pdfFit_uniVar(fVar_samples, True, [])
    #   (c) compare the exact moments with estimated values by ppce
    fEx = analyticTestFuncs.fEx1D(qTrain, fType, qInfo)
    fEx.moments(qInfo)
    fMean_ex = fEx.mean
    fVar_ex = fEx.var

    fMean_mean = fMean_samples.mean()
    fMean_sdev = fMean_samples.std()
    fVar_mean = fVar_samples.mean()
    fVar_sdev = fVar_samples.std()
    print(writeUQ.printRepeated('-', 80))
    print('>> Exact mean(f) = %g' % fMean_ex)
    print('   ppce estimated: E[mean(f)] = %g , sdev[mean(f)] = %g' %
          (fMean_mean, fMean_sdev))
    print('>> Exact Var(f) = %g' % fVar_ex)
    print('   ppce estimated: E[Var(f)] = %g , sdev[Var(f)] = %g' %
          (fVar_mean, fVar_sdev))
Ejemplo n.º 2
0
def ppce_2d_test():
    """
    Test for ppce for 2D parameter
    """
    def fEx(p, sampleType, n, qInfo, fExName):
        """
        Generate synthetic training data
        """
        #  (a) xTrain
        nSamp = n[0] * n[1]
        xi = []
        q = []
        qBound = []
        if sampleType[0] == 'LHS' and sampleType[1] == 'LHS':
            if distType == ['Unif'] * p:
                qBound = qInfo
                xi = sampling.LHS_sampling(nSamp, [[-1, 1]] * p)
                xTrain = np.zeros((nSamp, p))
                for i in range(p):
                    xTrain[:, i] = pce.mapFromUnit(xi[:, i], qBound[i])
                fEx_ = analyticTestFuncs.fEx2D(xTrain[:, 0], xTrain[:, 1],
                                               fExName, 'comp')
            else:
                raise ValueError(
                    "LHS works only when all q have 'Unif' distribution.")
        else:
            for i in range(p):
                samps = sampling.trainSample(sampleType=sampleType[i],
                                             GQdistType=distType[i],
                                             qInfo=qInfo[i],
                                             nSamp=n[i])
                q.append(samps.q)
            xTrain = reshaper.vecs2grid(q)
            fEx_ = analyticTestFuncs.fEx2D(q[0], q[1], fExName, 'tensorProd')
        return xTrain, fEx_

    #
    def trainDataGen(p, sampleType, n, qInfo, fExName, noiseType):
        """
        Generate synthetic training data
        """
        #  (a) xTrain and noise-free yTrain
        xTrain, fEx_ = fEx(p, sampleType, n, qInfo, fExName)
        yTrain_noiseFree = fEx_.val
        nSamp = xTrain.shape[0]
        #  (b) set the sdev of the observation noise
        noiseSdev = noiseGen(nSamp, noiseType, xTrain, fExName)
        #  (c) Training data
        yTrain = yTrain_noiseFree + noiseSdev * np.random.randn(nSamp)
        return xTrain, yTrain, noiseSdev, yTrain_noiseFree, fEx_

    #
    def noiseGen(n, noiseType, xTrain, fExName):
        """
       Generate a 1D numpy array of standard deviation of the observation noise
       """
        if noiseType == 'h**o':
            sd = 0.2  #(non-zero, to avoid instabilities)
            sdV = sd * np.ones(n)
        elif noiseType == 'hetero':
            sdV = 0.1 * (analyticTestFuncs.fEx2D(xTrain[:, 0], xTrain[:, 1],
                                                 fExName, 'comp').val + 0.001)
        return sdV

    #
    #----- SETTINGS -------------------------------------------
    #settings for parameters and data
    qInfo = [[-2, 2], [-2, 3]]  #info about the parameter
    #if 'Unif', qInfo =[min(q),max(q)]
    #if 'Norm', qInfo=[m,v] for q~N(m,v^2)
    distType = ['Unif', 'Unif']  #distribution type of parameters
    fExName = 'type1'  #name of simulator to generate synthetic dat
    #see analyticTestFuncs.fEx2D()
    trainSampleType = ['LHS',
                       'LHS']  #sampling type, see trainSample in sampling.py
    n = [10, 12]  #number of training samples for each parameter.
    #note: n[0]*n[1]<128, due to GpyTorch
    noiseType = 'hetero'  #type of observation noise
    #'h**o'=homoscedastic, 'hetero'=heterscedastic
    #options for GPR
    nIter_gpr = 1000  #number of iterations in optimization of hyperparameters
    lr_gpr = 0.1  #learning rate for the optimization of the hyperparameters
    convPlot_gpr = True  #plot convergence of optimization of the GPR hyperparameters
    #options for Gauss quadrature test nodes
    nGQtest = [18, 18]  #number of test samples in each param dimension
    nMC = 100  #number of samples drawn from GPR surrogate to construct estimates
    # for the moments of f(q)
    #---------------------------------------------------------
    p = len(distType)
    #(1) generate synthetic training data
    qTrain, yTrain, noiseSdev, yTrain_noiseFree, fEx_ = trainDataGen(
        p, trainSampleType, n, qInfo, fExName, noiseType)
    #(2) probabilistic PCE
    ppceDict = {
        'nGQtest': nGQtest,
        'qInfo': qInfo,
        'distType': distType,
        'nIter_gpr': nIter_gpr,
        'lr_gpr': lr_gpr,
        'convPlot_gpr': convPlot_gpr,
        'nMC': nMC
    }
    ppce_ = ppce(qTrain, yTrain, noiseSdev, ppceDict)
    optOut = ppce_.optOut
    fMean_samples = ppce_.fMean_samps
    fVar_samples = ppce_.fVar_samps
    #(3) estimate reference mean and varaiance of f(q) using Monte-Carlo approach
    fEx_.moments(distType, qInfo)
    fMean_mc = fEx_.mean
    fVar_mc = fEx_.var
    #(4) postprocess
    #   (a) plot the exact and GPR response surfaces
    gpr_torch.gprPlot().torch2d_3dSurf(qTrain, yTrain, optOut['qTest'],
                                       optOut['post_obs'])
    #   (b) plot histogram and fitted pdf of the mean and variance distributions
    statsUQit.pdfFit_uniVar(fMean_samples, True, [])
    statsUQit.pdfFit_uniVar(fVar_samples, True, [])
    #   (c) compare the reference moments with the estimated values by ppce
    fMean_mean = fMean_samples.mean()
    fMean_sdev = fMean_samples.std()
    fVar_mean = fVar_samples.mean()
    fVar_sdev = fVar_samples.std()
    print(writeUQ.printRepeated('-', 80))
    print('Reference mean(f) = %g' % fMean_mc)
    print('PPCE estimated: E[mean(f)] = %g , sdev[mean(f)] = %g' %
          (fMean_mean, fMean_sdev))
    print('Reference var(f) = %g' % fVar_mc)
    print('PPCE estimated: E[var(f)] = %g , sdev[var(f)] = %g' %
          (fVar_mean, fVar_sdev))
Ejemplo n.º 3
0
def pdfFit_uniVar(f, doPlot, pwOpts):
    """
    Fits a PDF to samples `f` and plots both histogram and the fitted PDF. 
    As an option, the plots and data can be saved on disk.

    Args:
      `f`: 1D numpy array of size n 
         Samples
      `doPlot`: bool      
         Whether or not plotting the PDF
      `pwOpts`: dict (optional) 
         Options for plotting and dumping the data with the following keys:
           * 'figDir': string, Directory to save the figure and dump the data
           * 'figName': string, Name of the figure
           * 'header': string, the header of the dumped file
           * 'iLoc': int, After converting to string will be added to the `figName`
    """
    if f.ndim > 1:
        print(
            'Note: input f to pdfFit_uniVar(f) must be a 1D numpy array. We reshape f!'
        )
        nTot = 1
        for i in range(f.ndim):
            nTot *= f.shape[i]
        f = np.reshape(f, nTot)
    # fit kde
    kde = sm.nonparametric.KDEUnivariate(f)
    kde.fit()
    # plot
    if doPlot:
        plt.figure(figsize=(10, 4))
        ax = plt.gca()
        plt.plot(kde.support, kde.density, '-r', lw=2)
        binsNum = 'auto'  # 70
        BIN = plt.hist(f,
                       bins=binsNum,
                       density=True,
                       color='steelblue',
                       alpha=0.4,
                       edgecolor='b')
        plt.xticks(fontsize=15)
        plt.yticks(fontsize=15)
        plt.grid(alpha=0.4)
        if pwOpts:  # if not empty
            # Dump the data of the PDf
            if pwOpts['figDir']:
                figDir = pwOpts['figDir']
                wrtDir = figDir + '/dumpData/'
            if pwOpts['figName']:
                outName = pwOpts['figName']
            if pwOpts['iLoc']:
                outName += '_' + str(pwOpts['iLoc'])
            if not os.path.exists(figDir):
                os.makedirs(figDir)
            if not os.path.exists(wrtDir):
                os.makedirs(wrtDir)
            F1 = open(wrtDir + outName + '.dat', 'w')
            if pwOpts['header']:
                F1.write('# ' + pwOpts['header'] + '\n')
                F1.write('# kde.support \t\t kde.density \n')
                F1.write('# ' + writeUQ.printRepeated('-', 50) + '\n')
                for i in range(len(kde.support)):
                    F1.write('%g \t %g \n' % (kde.support[i], kde.density[i]))
                F1.write('# ' + writeUQ.printRepeated('-', 50) + '\n')
                F1.write('# bin.support \t\t bin.density \n')
                F1.write('# ' + writeUQ.printRepeated('-', 50) + '\n')
                for i in range(len(BIN[0])):
                    F1.write('%g \t %g \n' % (BIN[1][i], BIN[0][i]))
            # Save the figure of the PDF
            fig = plt.gcf()
            DPI = fig.get_dpi()
            fig.set_size_inches(800 / float(DPI), 400 / float(DPI))
            plt.savefig(figDir + outName + '.pdf', bbox_inches='tight')
        else:
            plt.show()
    return kde
Ejemplo n.º 4
0
def pce_3d_test():
    """
    Test PCE for 3D uncertain parameter
    """
    #----- SETTINGS------------
    distType = ['Unif', 'Unif', 'Unif']  #distribution type of the parameters
    qInfo = [
        [-0.75, 1.5],  #range of parameters
        [-0.5, 2.5],
        [1.0, 3.0]
    ]
    nQ = [6, 5, 4]  #number of parameter samples in the 3 dimensions
    funOpt = {'a': 7, 'b': 0.1}  #parameters in the Ishigami function
    #PCE options
    truncMethod = 'TO'  #'TP'=Tensor Product
    #'TO'=Total Order
    sampleType = 'GQ'  #'GQ'=Gauss Quadrature nodes
    #other types: see trainSample in sampling.py
    pceSolveMethod = 'Regression'  #'Regression': for any combination of sample points and truncation methods
    #'Projection': only for 'GQ'+'TP'
    nTest = [5, 4, 3]  #number of test samples for the parameters
    if truncMethod == 'TO':
        LMax = 10  #max polynomial order in each parameter direction
    #--------------------
    p = len(distType)
    #Assemble the pceDict
    pceDict = {
        'p': p,
        'truncMethod': truncMethod,
        'sampleType': sampleType,
        'pceSolveMethod': pceSolveMethod,
        'distType': distType
    }
    if truncMethod == 'TO':
        pceDict.update({'LMax': LMax})
    #Generate training data
    xi = []
    q = []
    qBound = []
    for i in range(p):
        samps = sampling.trainSample(sampleType=sampleType,
                                     GQdistType=distType[i],
                                     qInfo=qInfo[i],
                                     nSamp=nQ[i])
        xi.append(samps.xi)
        q.append(samps.q)
        qBound.append(samps.qBound)
    fEx = analyticTestFuncs.fEx3D(q[0], q[1], q[2], 'Ishigami', 'tensorProd',
                                  funOpt)
    fVal = fEx.val
    #Construct the PCE
    xiGrid = reshaper.vecs2grid(xi)
    pce_ = pce(fVal=fVal, xi=xiGrid, pceDict=pceDict, nQList=nQ)
    fMean = pce_.fMean
    fVar = pce_.fVar
    pceCoefs = pce_.coefs
    kSet = pce_.kSet
    #Convergence of the PCE terms
    convPlot(coefs=pceCoefs, distType=distType, kSet=kSet)
    #Exact moments of the Ishigami function
    fEx.moments(qInfo=qBound)
    m = fEx.mean
    v = fEx.var
    #Compare the moments estimated by PCE with the exact analytical values
    print(writeUQ.printRepeated('-', 50))
    print('\t\t Exact \t\t PCE')
    print('E[f]:  ', m, fMean)
    print('V[f]:  ', v, fVar)
    print(writeUQ.printRepeated('-', 50))
    #Compare the PCE predictions at test points with the exact values of the model response
    qTest = []
    xiTest = []
    for i in range(p):
        testSamps = sampling.testSample('unifSpaced',
                                        GQdistType=distType[i],
                                        qInfo=qInfo[i],
                                        qBound=qBound[i],
                                        nSamp=nTest[i])
        qTest.append(testSamps.q)
        xiTest.append(testSamps.xi)
    fVal_test_ex = analyticTestFuncs.fEx3D(qTest[0], qTest[1], qTest[2],
                                           'Ishigami', 'tensorProd',
                                           funOpt).val
    #PCE prediction at test points
    pcePred_ = pceEval(coefs=pceCoefs, xi=xiTest, distType=distType, kSet=kSet)
    fVal_test_pce = pcePred_.pceVal
    #Plot the exact and PCE response values
    nTest_ = np.prod(np.asarray(nTest))
    fVal_test_pce_ = fVal_test_pce.reshape(nTest_, order='F')
    err = np.linalg.norm(fVal_test_pce_ - fVal_test_ex)
    plt.figure(figsize=(10, 4))
    plt.plot(fVal_test_pce_, '-ob', mfc='none', ms=5, label='Exact')
    plt.plot(fVal_test_ex, '-xr', ms=5, label='PCE')
    plt.xlabel('Index of test samples, k')
    plt.ylabel('Model response')
    plt.legend(loc='best')
    plt.grid(alpha=0.4)
    plt.show()
    print('||fEx(q)-fPCE(q)|| % = ', err * 100)
Ejemplo n.º 5
0
def pce_1d_test():
    """
    Test PCE for 1D uncertain parameter 
    """
    #--- settings -------------------------
    #Parameter settings
    distType = 'Norm'  #distribution type of the parameter
    if distType == 'Unif':
        qInfo = [-2, 4.0]  #parameter range only if 'Unif'
        fType = 'type1'  #Type of test exact model function
    elif distType == 'Norm':
        qInfo = [.5, 0.9]  #[m,v] for 'Norm' q~N(m,v^2)
        fType = 'type2'  #Type of test exact model function
    n = 20  #number of training samples
    nTest = 200  #number of test sample sin the parameter space
    #PCE Options
    sampleType = 'GQ'  #'GQ'=Gauss Quadrature nodes
    #''= any other sample => only 'Regression' can be selected
    # see `trainSample` class in sampling.py
    pceSolveMethod = 'Projection'  #'Regression': for any combination of sample points
    #'Projection': only for GQ
    LMax_ = 10  #number of terms (=K) in PCE (Only used with Regresson method)
    #(LMax will be over written by nSamples if it is provided for 'GQ'+'Projection')
    #-------------------------------------
    #(0) Make the pceDict
    pceDict = {
        'p': 1,
        'sampleType': sampleType,
        'pceSolveMethod': pceSolveMethod,
        'LMax': LMax_,
        'distType': [distType]
    }
    #(1) Generate training data
    samps = sampling.trainSample(sampleType=sampleType,
                                 GQdistType=distType,
                                 qInfo=qInfo,
                                 nSamp=n)
    q = samps.q
    xi = samps.xi
    qBound = samps.qBound
    fEx = analyticTestFuncs.fEx1D(q, fType, qInfo)
    f = fEx.val
    #(2) Compute the exact moments (as the reference data)
    fEx.moments(qInfo)
    fMean_ex = fEx.mean
    fVar_ex = fEx.var
    #(3) Construct the PCE
    pce_ = pce(fVal=f, xi=xi[:, None], pceDict=pceDict)
    fMean = pce_.fMean  #E[f(q)] estimated by PCE
    fVar = pce_.fVar  #V[f(q)] estimated by PCE
    pceCoefs = pce_.coefs  #Coefficients in the PCE
    #(4) Compare moments: exact vs. PCE estimations
    print(writeUQ.printRepeated('-', 70))
    print('-------------- Exact -------- PCE --------- Error % ')
    print('Mean of f(q) = %g\t%g\t%g' % (fMean_ex, fMean,
                                         (fMean - fMean_ex) / fMean_ex * 100.))
    print('Var  of f(q) = %g\t%g\t%g' % (fVar_ex, fVar,
                                         (fVar - fVar_ex) / fVar_ex * 100.))
    print(writeUQ.printRepeated('-', 70))
    #(5) Plots
    # Plot convergence of the PCE coefficients
    convPlot(coefs=pceCoefs, distType=distType)
    #
    #(6) Evaluate the PCE at test samples
    # Test samples
    testSamps = sampling.testSample('unifSpaced',
                                    GQdistType=distType,
                                    qInfo=qInfo,
                                    qBound=qBound,
                                    nSamp=nTest)
    qTest = testSamps.q
    xiTest = testSamps.xi
    fTest = analyticTestFuncs.fEx1D(qTest, fType,
                                    qInfo).val  #exact response at test samples
    #Prediction by PCE at test samples
    pcePred_ = pceEval(coefs=pceCoefs, xi=[xiTest], distType=[distType])
    fPCE = pcePred_.pceVal
    #Exact and PCE response surface
    plt.figure(figsize=(12, 5))
    ax = plt.gca()
    plt.plot(qTest, fTest, '-k', lw=2, label=r'Exact $f(q)$')
    plt.plot(q, f, 'ob', label=sampleType + ' Training Samples')
    plt.plot(qTest, fPCE, '-r', lw=2, label='PCE')
    plt.plot(qTest,
             fMean * np.ones(len(qTest)),
             '-b',
             label=r'$\mathbb{E}[f(q)]$')
    ax.fill_between(qTest,
                    fMean + 1.96 * mt.sqrt(fVar) * np.ones(len(qTest)),
                    fMean - 1.96 * mt.sqrt(fVar) * np.ones(len(qTest)),
                    color='powderblue',
                    alpha=0.4)
    plt.plot(qTest,
             fMean + 1.96 * mt.sqrt(fVar) * np.ones(len(qTest)),
             '--b',
             label=r'$\mathbb{E}[f(q)]\pm 95\%CI$')
    plt.plot(qTest, fMean - 1.96 * mt.sqrt(fVar) * np.ones(len(qTest)), '--b')
    plt.title('Example of 1D PCE for random variable of type %s' % distType)
    plt.xlabel(r'$q$', fontsize=19)
    plt.ylabel(r'$f(q)$', fontsize=19)
    plt.xticks(fontsize=18)
    plt.yticks(fontsize=18)
    plt.grid(alpha=0.3)
    plt.legend(loc='best', fontsize=17)
    plt.show()
Ejemplo n.º 6
0
def pce_2d_test():
    """
    Test PCE for 2D uncertain parameter
    """
    #---- SETTINGS------------
    #Parameters specifications
    distType = ['Norm', 'Norm']  #distribution type of the parameters q1, q2
    qInfo = [
        [-2, 1],  #info on parameters
        [-2, 0.4]
    ]
    nQ = [7, 6]  #number of training samples of parameters
    nTest = [121,
             120]  #number of test points in parameter spaces to evaluate PCE
    #PCE Options
    truncMethod = 'TO'  #'TP'=Tensor Product
    #'TO'=Total Order
    sampleType = [
        'GQ', 'GQ'
    ]  #'GQ'=Gauss Quadrature nodes ('Projection' or 'Regression')
    #For other type of samples, see sampling.py, trainSample => only 'Regression' can be used
    #'LHS': Latin Hypercube Sampling (only when all distType='Unif')
    fType = 'type1'  #Type of the exact model response, 'type1', 'type2', 'type3', 'Rosenbrock'
    pceSolveMethod = 'Regression'  #'Regression': for any combination of sampling and truncation methods
    #'Projection': only for 'GQ'+'TP'
    if truncMethod == 'TO':
        LMax = 8  #max polynomial order in each parameter dimention
    #------------------------
    p = len(distType)
    #Assemble the pceDict
    pceDict = {
        'p': p,
        'truncMethod': truncMethod,
        'sampleType': sampleType,
        'pceSolveMethod': pceSolveMethod,
        'distType': distType
    }
    if truncMethod == 'TO':
        pceDict.update({'LMax': LMax, 'pceSolveMethod': 'Regression'})
    #Generate the training data
    xi = []
    q = []
    qBound = []
    if sampleType[0] == 'LHS' and sampleType[1] == 'LHS':
        if distType == ['Unif'] * p:
            qBound = qInfo
            xi = sampling.LHS_sampling(nQ[0] * nQ[1], [[-1, 1]] * p)
            for i in range(p):
                q.append(pce.mapFromUnit(xi[:, i], qBound[i]))
            fEx_ = analyticTestFuncs.fEx2D(q[0], q[1], fType, 'comp')
            xiGrid = xi
        else:
            raise ValueError(
                "LHS works only when all q have 'Unif' distribution.")
    else:
        for i in range(p):
            samps = sampling.trainSample(sampleType=sampleType[i],
                                         GQdistType=distType[i],
                                         qInfo=qInfo[i],
                                         nSamp=nQ[i])
            q.append(samps.q)
            xi.append(samps.xi)
            qBound.append(samps.qBound)
        fEx_ = analyticTestFuncs.fEx2D(q[0], q[1], fType, 'tensorProd')
        xiGrid = reshaper.vecs2grid(xi)
    fVal = fEx_.val
    #Construct the PCE
    pce_ = pce(fVal=fVal, xi=xiGrid, pceDict=pceDict, nQList=nQ)
    fMean = pce_.fMean
    fVar = pce_.fVar
    pceCoefs = pce_.coefs
    kSet = pce_.kSet
    #Plot the convergence indicator of the PCE
    convPlot(coefs=pceCoefs, distType=distType, kSet=kSet)
    #Generate test samples for the parameters and evaluate the exact response surface at them
    qTest = []
    xiTest = []
    for i in range(p):
        testSamps = sampling.testSample('unifSpaced',
                                        GQdistType=distType[i],
                                        qInfo=qInfo[i],
                                        qBound=qBound[i],
                                        nSamp=nTest[i])
        qTest_ = testSamps.q
        xiTest_ = testSamps.xi
        qTest.append(qTest_)
        xiTest.append(xiTest_)
    fTest = analyticTestFuncs.fEx2D(qTest[0], qTest[1], fType,
                                    'tensorProd').val
    #Evaluate PCE at the test samples
    pcePred_ = pceEval(coefs=pceCoefs, xi=xiTest, distType=distType, kSet=kSet)
    fPCE = pcePred_.pceVal
    #Use MC method to directly estimate reference values for the mean and varaiance of f(q)
    fEx_.moments(distType, qInfo)
    fMean_mc = fEx_.mean
    fVar_mc = fEx_.var

    #Compare the PCE estimates for moments of f(q) with the reference values from MC
    print(writeUQ.printRepeated('-', 70))
    print('------------ MC -------- PCE --------- Error % ')
    print('Mean of f(q) = %g\t%g\t%g' % (fMean_mc, fMean,
                                         (fMean - fMean_mc) / fMean_mc * 100.))
    print('Var  of f(q) = %g\t%g\t%g' % (fVar_mc, fVar,
                                         (fVar - fVar_mc) / fVar_mc * 100.))
    print(writeUQ.printRepeated('-', 70))
    #Plot the exact and PCE response surfaces as contours in the parameters space
    # Create 2D grid from the test samples and plot the contours of response surface over it
    fTestGrid = fTest.reshape(nTest, order='F')
    fErrorGrid = (abs(fTestGrid - fPCE))
    # 2D grid from the sampled parameters
    if sampleType[0] == 'LHS' and sampleType[1] == 'LHS':
        qGrid = reshaper.vecsGlue(q[0], q[1])
    else:
        qGrid = reshaper.vecs2grid(q)
    plt.figure(figsize=(21, 8))
    plt.subplot(1, 3, 1)
    ax = plt.gca()
    CS1 = plt.contour(qTest[0], qTest[1], fTestGrid.T, 40)
    plt.clabel(CS1,
               inline=True,
               fontsize=13,
               colors='k',
               fmt='%0.2f',
               rightside_up=True,
               manual=False)
    plt.plot(qGrid[:, 0], qGrid[:, 1], 'o', color='r', markersize=7)
    plt.xlabel(r'$q_1$')
    plt.ylabel(r'$q_2$')
    plt.title('Exact Response')
    plt.subplot(1, 3, 2)
    ax = plt.gca()
    CS2 = plt.contour(qTest[0], qTest[1], fPCE.T, 40)
    plt.clabel(CS2,
               inline=True,
               fontsize=13,
               colors='k',
               fmt='%0.2f',
               rightside_up=True,
               manual=False)
    plt.plot(qGrid[:, 0], qGrid[:, 1], 'o', color='r', markersize=7)
    plt.xlabel(r'$q_1$')
    plt.ylabel(r'$q_2$')
    plt.title('PCE Response')
    plt.subplot(1, 3, 3)
    ax = plt.gca()
    CS3 = plt.contour(qTest[0], qTest[1], fErrorGrid.T, 40)
    plt.clabel(CS3,
               inline=True,
               fontsize=13,
               colors='k',
               fmt='%0.2f',
               rightside_up=True,
               manual=False)
    plt.xlabel(r'$q_1$')
    plt.ylabel(r'$q_2$')
    plt.plot(qGrid[:, 0], qGrid[:, 1], 'o', color='r', markersize=7)
    plt.title('|Exact-Surrogate|')
    plt.show()