# MetaModelUnStructuredComp#

`MetaModelUnStructuredComp`

lets you quickly create a component with surrogate models
used to compute the outputs based on unstructured training data. Generally, this is
used to construct a low-computational-cost replacement for computationally
expensive components.

You can define `MetaModelUnStructuredComp`

with as many inputs and outputs as you like,
and you can also use a different surrogate model for each output.

Note

What’s the difference between `MetaModelUnStructuredComp`

and a surrogate model? In
OpenMDAO, “surrogate model” refers to the model for a single response, and
`MetaModelUnStructuredComp`

represents a collection of surrogate models trained at the
same locations in the design space.

## MetaModelUnStructuredComp Options#

Option | Default | Acceptable Values | Acceptable Types | Description |
---|---|---|---|---|

always_opt | False | [True, False] | ['bool'] | If True, force nonlinear operations on this component to be included in the optimization loop even if this component is not relevant to the design variables and responses. |

default_surrogate | N/A | N/A | ['SurrogateModel', 'NoneType'] | Surrogate that will be used for all outputs that don't have a specific surrogate assigned to them. |

distributed | False | [True, False] | ['bool'] | If True, set all variables in this component as distributed across multiple processes |

run_root_only | False | [True, False] | ['bool'] | If True, call compute, compute_partials, linearize, apply_linear, apply_nonlinear, and compute_jacvec_product only on rank 0 and broadcast the results to the other ranks. |

vec_size | 1 | N/A | ['int'] | Number of points that will be simultaneously predicted by the surrogate. |

## MetaModelUnStructuredComp Constructor#

The call signature for the `MetaModelUnStructuredComp`

constructor is:

- MetaModelUnStructuredComp.__init__(
**kwargs)[source]Initialize all attributes.

## Simple Example#

The following example demonstrates a simple `Problem`

in which a
`MetaModelUnStructuredComp`

uses surrogates to mimic the sine and cosine functions.

In this example, the `MetaModelUnStructuredComp`

`trig`

has a single input,
`x`

, and two outputs, `sin_x`

and `cos_x`

.

`KrigingSurrogate`

is given as the surrogate for the `sin_x`

output.
Although no surrogate has been given for the `cos_x`

output, a
`default_surrogate`

is specified for the component. Any output which has
not had a surrogate assigned will use one of the default type.
If `default_surrogate`

is not specified, then a surrogate must be
given for all outputs.

The first time a `MetaModelUnStructuredComp`

runs, it will train the surrogates using the
training data that has been provided, and then it will predict the output
values. This training step only occurs on the first run.

```
# create a MetaModelUnStructuredComp, specifying surrogates for the outputs
import numpy as np
import openmdao.api as om
trig = om.MetaModelUnStructuredComp()
x_train = np.linspace(0,10,20)
trig.add_input('x', 0., training_data=x_train)
trig.add_output('sin_x', 0.,
training_data=.5*np.sin(x_train),
surrogate=om.KrigingSurrogate())
trig.add_output('cos_x', 0.,
training_data=.5*np.cos(x_train))
trig.options['default_surrogate'] = om.KrigingSurrogate()
# add it to a Problem, run and check the predicted values
prob = om.Problem()
prob.model.add_subsystem('trig', trig)
prob.setup()
prob.set_val('trig.x', 2.1)
prob.run_model()
print(prob.get_val('trig.sin_x'))
print(prob.get_val('trig.cos_x'))
```

```
[0.4316104]
[-0.25241565]
```

## Available Surrogates#

The following surrogates are available to use with `MetaModelUnStructuredComp`

.

**Derivatives**: Yes

**Description**: Based on Kriging interpolation; prediction returns mean predicted value, optionally returns RMSE.

**Derivatives**: Yes

**Description**: Based on the N-Dimensional Interpolation library by Stephen Marone.

**Derivatives**: Yes

**Description**: Based on second order response surface equations.

## Advanced usage#

You can specify the training data after instantiation if you like, by setting the component’s
options. Training data is provided in the options to the `trig`

component using the variable names prefixed with `train_`

. This can be done anytime before
the `MetaModelUnStructuredComp`

runs for the first time.

The inputs and outputs of a `MetaModelUnStructuredComp`

are not limited to scalar values. The
following modified version of the example uses an array to predict sine and
cosine as a single output array of two values. You will also note that the default
surrogate can be passed as an argument to the `MetaModelUnStructuredComp`

constructor, as an
alternative to specifying it later.

```
# create a MetaModelUnStructuredComp that predicts sine and cosine as an array
trig = om.MetaModelUnStructuredComp(default_surrogate=om.KrigingSurrogate())
trig.add_input('x', 0)
trig.add_output('y', np.zeros(2))
# add it to a Problem
prob = om.Problem()
prob.model.add_subsystem('trig', trig)
prob.setup()
# provide training data
trig.options['train_x'] = np.linspace(0, 10, 20)
trig.options['train_y'] = np.column_stack((
.5*np.sin(trig.options['train_x']),
.5*np.cos(trig.options['train_x'])
))
# train the surrogate and check predicted value
prob.set_val('trig.x', 2.1)
prob.run_model()
print(prob.get_val('trig.y'))
```

```
[ 0.43161089 -0.25241615]
```

In addition, it’s possible to vectorize the input and output variables so that you can
make multiple predictions for the inputs and outputs in a single execution of the
`MetaModelUnStructuredComp`

component. This is done by setting the `vec_size`

argument when
constructing the `MetaModelUnStructuredComp`

component and giving it the number of predictions to make. The following example vectorizes the `trig`

component so that it makes three predictions at a time. In this case, the input is
three independent values of `x`

and the output is the corresponding predicted values
for the sine and cosine functions at those three points. Note that a vectorized
`MetaModelUnStructuredComp`

component requires the first dimension of all input and output variables
to be the same size as specified in the `vec_size`

argument.

```
size = 3
# create a vectorized MetaModelUnStructuredComp for sine and cosine
trig = om.MetaModelUnStructuredComp(vec_size=size, default_surrogate=om.KrigingSurrogate())
trig.add_input('x', np.zeros(size))
trig.add_output('y', np.zeros((size, 2)))
# add it to a Problem
prob = om.Problem()
prob.model.add_subsystem('trig', trig)
prob.setup()
# provide training data
trig.options['train_x'] = np.linspace(0, 10, 20)
trig.options['train_y'] = np.column_stack((
.5*np.sin(trig.options['train_x']),
.5*np.cos(trig.options['train_x'])
))
# train the surrogate and check predicted value
prob.set_val('trig.x', np.array([2.1, 3.2, 4.3]))
prob.run_model()
print(prob.get_val('trig.y'))
```

```
[[ 0.43161089 -0.25241615]
[-0.02918421 -0.49914071]
[-0.45808581 -0.20039903]]
```

## Using Surrogates That Do Not Define Linearize Method#

In some cases, you might define surrogates but not define a `linearize`

method. In this case, the
`MetaModelUnStructuredComp`

derivatives will be computed using finite differences for the output variables that use that
surrogate. By default, the default options for the finite differencing method will be used.

If you would like to specify finite differencing options, you can do so by calling the `declare_partials`

method in the component’s `setup_partials`

or in a parent group’s configure method.
This example, which uses a surrogate with no
`linearize`

method and no training for simplicity, shows `declare_partials`

called in `setup_partials`

.

```
from math import sin
class SinSurrogate(om.SurrogateModel):
def train(self, x, y):
pass
def predict(self, x):
return sin(x)
class TrigWithFdInSetup(om.MetaModelUnStructuredComp):
def setup(self):
surrogate = SinSurrogate()
self.add_input('x', 0.)
self.add_output('sin_x', 0., surrogate=surrogate)
def setup_partials(self):
self.declare_partials('sin_x', 'x', method='fd',
form='backward', step=1e-7, step_calc='rel')
# Testing explicitly setting fd inside of setup
prob = om.Problem()
trig = TrigWithFdInSetup()
prob.model.add_subsystem('trig', trig, promotes_inputs=['x'])
prob.setup(check=True)
prob.set_val('x', 5.)
trig.train = False
prob.run_model()
J = prob.compute_totals(of=['trig.sin_x'], wrt=['x'])
deriv_using_fd = J[('trig.sin_x', 'x')]
```

```
INFO: checking out_of_order
```

```
INFO: checking system
```

```
INFO: checking solvers
```

```
INFO: checking dup_inputs
```

```
INFO: checking missing_recorders
```

```
WARNING: The Problem has no recorder of any kind attached
```

```
INFO: checking unserializable_options
```

```
INFO: checking comp_has_no_outputs
```

```
INFO: checking auto_ivc_warnings
```

```
/tmp/ipykernel_18454/959289868.py:8: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
return sin(x)
```

```
print(deriv_using_fd[0])
```

```
[0.28366195]
```

Complex step has not been tested with `MetaModelUnStructuredComp`

and will result in an exception if used.