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.