Running UQPCE#
Installation#
To install the UQPCE package and its prerequisites, run the below line in your command line in the cloned repository.
pip install -e .
License#
The software license is available here.
Sample UQPCE Script#
%%capture --no-stdout
from uqpce import PCE
samp_count = 100
aleat_cnt = 500000
epist_cnt = 1
pce = PCE(
order=2, verbose=True, outputs=False, plot=False, aleat_samp_size=aleat_cnt,
epist_samp_size=epist_cnt
)
# Add two normal variables
pce.add_variable(distribution='normal', mean=1, stdev=3, name='uncerta')
pce.add_variable(distribution='normal', mean=1, stdev=7, name='uncertb')
# Generate samples that correspond to the input variables
Xt = pce.sample(count=samp_count)
# Generate responses from equation; the user's analytical tool will replace this
eq = 'x0**2 + x0*x1 - x1'
yt = pce.generate_responses(Xt, equation=eq)
pce.fit(Xt, yt) # Fit the PCE model
pce.check_variables(Xt) # Check if the samples correspond to the distributions
pce.sobols() # Calculate the Sobol indices
cil, cih = pce.confidence_interval() # Calculate the confidence interval
[runnervmyg876:02556] mca_base_component_repository_open: unable to open mca_btl_openib: librdmacm.so.1: cannot open shared object file: No such file or directory (ignored)
Adding variable number 1
Adding variable number 2
Generating the results from function x0**2 + x0*x1 - x1
Constructing surrogate model
Building norm-squared matrix
Assembling psi matrix
17% Complete
33% Complete
50% Complete
67% Complete
83% Complete
100% Complete
Psi matrix assembled
Evaluating psi matrix
Surrogate model construction complete
Generating aleatory resampling values
Sample Robust Design#
For an example of robust design using UQPCE and OpenMDAO, we will walk through an example that is based on the OpenMDAO paraboloid example
To start, we will define a Paraboloid class that looks similar to the OpenMDAO example but includes vectorized inputs for the two uncertain inputs, uncerta and uncertb.
import openmdao.api as om
import numpy as np
class Paraboloid(om.ExplicitComponent):
"""
Evaluates the equation f(a,b,x,y) = (a*x-3)**2 + a*b*x*y + (b*y+4)**2 - 3
"""
def initialize(self):
self.options.declare('vec_size', types=int)
def setup(self):
n = self.options['vec_size']
# Add two uncertain variables of length n
self.add_input('uncerta', shape=(n,))
self.add_input('uncertb', shape=(n,))
# Add two design variables
self.add_input('desx')
self.add_input('desy')
# Add output of length n
self.add_output('f_abxy', shape=(n,))
def setup_partials(self):
n = self.options['vec_size']
incr = np.linspace(0, n-1, n)
self.declare_partials(of='f_abxy', wrt=['desx', 'desy'])
self.declare_partials(
of='f_abxy', wrt=['uncerta', 'uncertb'], rows=incr, cols=incr
)
def compute_partials(self, inputs, partials, discrete_inputs=None):
a = inputs['uncerta']
b = inputs['uncertb']
x = inputs['desx']
y = inputs['desy']
partials['f_abxy', 'desx'] = 2*a**2*x + a*(-6 + b*y)
partials['f_abxy', 'desy'] = 8*b + a*b*x + 2*b**2*y
partials['f_abxy', 'uncerta'] = -6*x + 2*a*x**2 + b*x*y
partials['f_abxy', 'uncertb'] = 8*y + a*x*y + 2*b*y**2
def compute(self, inputs, outputs):
a = inputs['uncerta']
b = inputs['uncertb']
x = inputs['desx']
y = inputs['desy']
outputs['f_abxy'] = (a*x-3)**2 + a*b*x*y + (b*y+4)**2 - 3
Now we will create an OpenMDAO problem with the UQPCEGroup as a subsystem. As show below, the Paraboloid class and UQPCEGroup class are both instantiated as subsystems. The Paraboloid class creates a vector of responses of the required length from the PCE samples, and the Paraboloid output is taken into the UQPCEGroup.
The input uncert_list is a list of the string names of all of the uncertain outputs for which the user wants to build PCE models.
All of the UQPCEGroup inputs come from the PCE model, except for the uncert_list and tanh_omega parameters.
from uqpce import PCE, UQPCEGroup, interface
samp_count = 100
aleat_cnt = 500000
epist_cnt = 1
pce = PCE(
order=2, verbose=True, outputs=False, plot=False, aleat_samp_size=aleat_cnt,
epist_samp_size=epist_cnt
)
# Add two normal variables
pce.add_variable(distribution='normal', mean=1, stdev=3, name='uncerta')
pce.add_variable(distribution='normal', mean=1, stdev=7, name='uncertb')
# Generate samples that correspond to the input variables
Xt = pce.sample(count=samp_count)
pce.set_samples(Xt)
pce.build_basis(order=2)
pce.resample_surrogate()
prob = om.Problem()
prob.model.add_subsystem(
'parab',
Paraboloid(vec_size=samp_count),
promotes_inputs=['uncerta', 'uncertb', 'desx', 'desy'],
promotes_outputs=['f_abxy']
)
prob.model.add_subsystem(
'uq',
UQPCEGroup(
significance=pce.significance, var_basis=pce.var_basis,
norm_sq=pce.norm_sq, resampled_var_basis=pce.resampled_var_basis,
tail='both', epistemic_cnt=epist_cnt, aleatory_cnt=aleat_cnt,
uncert_list=['f_abxy'], tanh_omega=0.01
),
promotes_inputs=['f_abxy'],
promotes_outputs=[
'f_abxy:ci_lower', 'f_abxy:ci_upper', 'f_abxy:variance', 'f_abxy:mean'
]
)
# Set up the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.model.add_design_var('desx', lower=-10, upper=10)
prob.model.add_design_var('desy', lower=-10, upper=10)
prob.model.add_objective('f_abxy:ci_upper')
prob.setup()
prob.set_val('desx', 1)
prob.set_val('desy', 0.4)
interface.set_vals(prob, pce.variables, Xt)
Adding variable number 1
Adding variable number 2
Constructing surrogate model
Building norm-squared matrix
Assembling psi matrix
17% Complete
33% Complete
50% Complete
67% Complete
83% Complete
100% Complete
Psi matrix assembled
Evaluating psi matrix
Generating aleatory resampling values
prob.run_driver()
print('Design variable `desx` is: ', prob.get_val('desx')[0])
print('Design variable `desy` is: ', prob.get_val('desy')[0])
Design variable `desx` is: 9.674723310373773e-05
Design variable `desy` is: -1.3157340630728381e-05
Note
More variables, the presence of epistemic variables, and a higher order all increase the time required by UQPCE.