Modeling Multiple OutputsΒΆ

This tutorial is a short demonstration of how to construct a MetaModel of a component with multiple outputs. This tutorial builds off of the single-output tutorial, with modifications for multiple outputs in a component.

We created a new component called Trig(). This component has one input and two outputs, both of which will be mimicked by the MetaModel.

from openmdao.main.api import Assembly, Component, SequentialWorkflow, set_as_top
from math import sin, cos

from openmdao.lib.datatypes.api import Float
from openmdao.lib.drivers.api import DOEdriver
from openmdao.lib.doegenerators.api import FullFactorial, Uniform
from openmdao.lib.components.api import MetaModel
from openmdao.lib.casehandlers.api import DBCaseRecorder
from openmdao.lib.surrogatemodels.api import LogisticRegression, FloatKrigingSurrogate


class Trig(Component):

    x = Float(0,iotype="in",units="rad")

    f_x_sin = Float(0.0,iotype="out")
    f_x_cos = Float(0.0,iotype="out")

    def execute(self):
        self.f_x_sin = .5*sin(self.x)
        self.f_x_cos = .5*cos(self.x)

This next section differs from the the previous example in that there are two surrogate models, one specified for each of the outputs. Note that each of the outputs had been assigned a specific surrogate model, a logistic regression for sin, and a Kriging Surrogate for cos. In this case, no default was set at all.

The parameter x still needs to be added only once in this case, since the same input is being evaluated for both outputs.

class Simulation(Assembly):

    def configure(self):

        # Our component to be meta-modeled
        self.add("trig_calc", Trig())

       # Create meta_model for two responsese
        self.add("trig_meta_model", MetaModel(params = ('x', ),
                                              responses = ('f_x_sin', 'f_x_cos')))

        # Use Kriging for the f_x output
        self.trig_meta_model.surrogates['f_x_sin'] = LogisticRegression()
        self.trig_meta_model.surrogates['f_x_cos'] = FloatKrigingSurrogate()

        # Training the MetaModel
        self.add("DOE_Trainer", DOEdriver())
        self.DOE_Trainer.DOEgenerator = FullFactorial()
        self.DOE_Trainer.DOEgenerator.num_levels = 20
        self.DOE_Trainer.add_parameter("trig_calc.x", low=0, high=20)
        self.DOE_Trainer.add_response('trig_calc.f_x_sin')
        self.DOE_Trainer.add_response('trig_calc.f_x_cos')

        # Pass training data to the meta model.
        self.connect('DOE_Trainer.case_inputs.trig_calc.x', 'trig_meta_model.params.x')
        self.connect('DOE_Trainer.case_outputs.trig_calc.f_x_sin', 'trig_meta_model.responses.f_x_sin')
        self.connect('DOE_Trainer.case_outputs.trig_calc.f_x_cos', 'trig_meta_model.responses.f_x_cos')

        #MetaModel Validation
        self.add("DOE_Validate", DOEdriver())
        self.DOE_Validate.DOEgenerator = Uniform()
        self.DOE_Validate.DOEgenerator.num_samples = 20
        self.DOE_Validate.add_parameter(("trig_meta_model.x", "trig_calc.x"),
                                        low=0, high=20)
        self.DOE_Validate.add_response("trig_calc.f_x_sin")
        self.DOE_Validate.add_response("trig_calc.f_x_cos")
        self.DOE_Validate.add_response("trig_meta_model.f_x_sin")
        self.DOE_Validate.add_response("trig_meta_model.f_x_cos")

        #Iteration Hierarchy
        self.driver.workflow.add(['DOE_Trainer', 'DOE_Validate'])
        self.DOE_Trainer.workflow.add('trig_calc')
        self.DOE_Validate.workflow.add(['trig_calc', 'trig_meta_model'])

The iteration hierarchy is structurally the same as it would be with one output. Even though there are multiple surrogate models for multiple outputs, they are still contained within only one MetaModel component. So once again there is the trig_calc MetaModel component separately added to each workflow and the MetaModel component being added to the validation stage so that comparative values may be generated.

In printing the information we have now included all four of the outputs. For a Kriging Surrogate model, the answer is normally returned as a normal distribution (Kriging Surrogate predicts both a mean and a standard deviation for a given input). However, here we have slotted the FloatKrigingSurrogate, which just returns the mean (or mu).

if __name__ == "__main__":

    sim = set_as_top(Simulation())
    sim.run()

    #This is how you can access any of the data
    train_inputs = sim.DOE_Trainer.case_inputs.trig_calc.x
    train_actual_sin = sim.DOE_Trainer.case_outputs.trig_calc.f_x_sin
    train_actual_cos = sim.DOE_Trainer.case_outputs.trig_calc.f_x_cos
    inputs = sim.DOE_Validate.case_inputs.trig_meta_model.x
    actual_sin = sim.DOE_Validate.case_outputs.trig_calc.f_x_sin
    actual_cos = sim.DOE_Validate.case_outputs.trig_calc.f_x_cos
    predicted_sin = sim.DOE_Validate.case_outputs.trig_meta_model.f_x_sin
    predicted_cos = sim.DOE_Validate.case_outputs.trig_meta_model.f_x_cos

    for a,b,c,d in zip(actual_sin, predicted_sin, actual_cos, predicted_cos):
        print "%1.3f, %1.3f, %1.3f, %1.3f"%(a, b, c, d)

To view this example, and try running and modifying the code for yourself, you can download it here: multi_outs.py.

OpenMDAO Home

Previous topic

Using a MetaModel Component

Next topic

MDAO Architectures

This Page