PCE METAMODELING: TRUSS DATA SET¶

This example showcases how to perform PCE metamodeling using existing data sets. The data sets come from a finite element model of a truss structure and are retrieved from different MAT-files. The files consist of an experimental design of size $200$ and a validation set of size $10^4$.

Package imports¶

In [1]:
from uqpylab import sessions, display_util
import numpy as np
import matplotlib.pyplot as plt
import scipy.io

Initialize common plotting parameters¶

In [2]:
display_util.load_plt_defaults()
uq_colors = display_util.get_uq_color_order()

Start a remote UQCloud session¶

In [3]:
# Start the session
mySession = sessions.cloud()
# (Optional) Get a convenient handle to the command line interface
uq = mySession.cli
# Reset the session
mySession.reset()
Processing .
.
 done!

 uqpylab.sessions :: INFO     :: This is UQ[py]Lab, version 1.00, running on https://uqcloud.ethz.ch. 
                                 UQ[py]Lab is free software, published under the open source BSD 3-clause license.
                                 To request special permissions, please contact:
                                  - Stefano Marelli (marelli@ibk.baug.ethz.ch).
                                 A new session (e4618fb37d8b4001a177959b6428165e) started.
 uqpylab.sessions :: INFO     :: Reset successful.

Set random seed for reproducibility¶

In [4]:
uq.rng(0,'twister');

Retrieve data sets¶

The experimental design and the validation basis are stored in two separate files

In [5]:
# Read the binary files (stored in .mat format)
mat = scipy.io.loadmat('Truss_Experimental_Design.mat')
X = mat['X']
Y = mat['Y']

# Also read the validation basis data set file and store the contents in matrices:
mat = scipy.io.loadmat('Truss_Validation_Basis.mat')
X_val = mat['Xval']
Y_val = mat['Yval']

Probabilistic input model¶

Because PCE requires a choice of polynomial basis, a probabilistic input model needs to be defined.

Specify the marginals of the probabilistic input model:

In [6]:
InputOpts = {
    "Marginals": [
        # Young's modulus of the cross-sections
        {"Name" : "E1",
         "Type": "Lognormal",
         "Moments": [2.1e11, 2.1e10]
        },
        {"Name" : "E2",
         "Type": "Lognormal",
         "Moments": [2.1e11, 2.1e10]
        },
        # Cross-section of horizontal elements
        {"Name" : "A1",
         "Type": "Lognormal",
         "Moments": [2.0e-3, 2.0e-4]
        },
        # Cross-section of diagonal elements
        {"Name" : "A2",
         "Type": "Lognormal",
         "Moments": [1.0e-3, 1.0e-4]
        },
        # Loads
        {"Name" : "p1",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        },
        {"Name" : "p2",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        },
        {"Name" : "p3",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        },
        {"Name" : "p4",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        },
        {"Name" : "p5",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        },
        {"Name" : "p6",
         "Type": "Gumbel",
         "Moments": [5.0e4, 7.5e3]
        }
    ]
}

Create an INPUT object based on the specified marginals:

In [7]:
myInput = uq.createInput(InputOpts)

PCE metamodel¶

Select PCE as the metamodeling tool:

In [8]:
MetaOpts = {
    'Type': 'Metamodel',
    'MetaType': 'PCE'
}

Use experimental design loaded from the data files:

In [9]:
MetaOpts['ExpDesign'] = {
    'X': X.tolist(),
    'Y': Y.tolist()
}

Set the maximum polynomial degree to 5:

In [10]:
MetaOpts["Degree"] = np.arange(1,5).tolist()

Provide the validation data set to get the validation error:

In [11]:
MetaOpts['ValidationSet'] = {
    'X': X_val.tolist(),
    'Y': Y_val.tolist()
}

Create the PCE metamodel:

In [12]:
myPCE = uq.createModel(MetaOpts)

Print a summary of the resulting PCE metamodel:

In [13]:
uq.print(myPCE)
%------------ Polynomial chaos output ------------%
   Number of input variables:    10
   Maximal degree:               3
   q-norm:                       1.00
   Size of full basis:           286
   Size of sparse basis:         88
   Full model evaluations:       200
   Leave-one-out error:          2.0613877e-05
   Modified leave-one-out error: 9.1429970e-05
   Validation error:             5.7079071e-05
   Mean value:                  -0.0794
   Standard deviation:           0.0111
   Coef. of variation:            13.949%
%--------------------------------------------------%

Validation¶

Evaluate the PCE metamodel at the validation set:

In [14]:
Y_PCE = uq.evalModel(myPCE, X_val)

Plot histograms of the true output and the PCE prediction:

In [15]:
plt.hist(Y_val, 20, color=uq_colors[0], alpha = 0.8)
plt.hist(Y_PCE, 20, color=uq_colors[1], alpha = 0.8)
legend_text = ['True model response', 'PCE prediction']
plt.legend(legend_text, frameon=False, loc="best")
plt.xlabel('$\\mathrm{Y}$')
plt.ylabel('Counts')
plt.show()
No description has been provided for this image

Plot the true vs. predicted values:

In [16]:
fig = plt.figure(figsize=(6, 6))
plt.scatter(Y_val, Y_PCE, marker='o', s=3)
plt.plot([np.min(Y_val), np.max(Y_val)], [np.min(Y_val), np.max(Y_val)], 'k')
plt.axis([np.min(Y_val), np.max(Y_val), np.min(Y_val), np.max(Y_val)])
plt.axis('equal')
plt.grid(True)
plt.xlabel('$\\mathrm{Y_{true}}$')
plt.ylabel('$\\mathrm{Y_{PCE}}$')
plt.show()
No description has been provided for this image

Print the validation and leave-one-out (LOO) cross-validation errors:

In [17]:
print('PCE metamodel validation error: {:5.4e}'.format(myPCE['Error']['Val']))
print('PCE metamodel LOO error:        {:5.4e}'.format(myPCE['Error']['LOO']))
PCE metamodel validation error: 5.7079e-05
PCE metamodel LOO error:        2.0614e-05

Terminate the remote UQCloud session¶

In [18]:
mySession.quit()
 uqpylab.sessions :: INFO     :: Session e4618fb37d8b4001a177959b6428165e terminated.
Out[18]:
True