Skip to main content

Variables

Amigo components work with several types of variables, each serving a distinct purpose in defining optimization problems. Understanding these variable types is essential for building Amigo models.

Inputs

Inputs are design variables that the optimizer can modify during the optimization process. They represent the degrees of freedom in your problem.

Scalar Inputs

self.add_input("x", value=1.0, lower=-10.0, upper=10.0)

Vector Inputs

# Define a 3-element vector
self.add_input("forces", shape=(3,), value=0.0, lower=-100.0, upper=100.0)

# Access individual elements
def compute(self):
forces = self.inputs["forces"]
fx = forces[0]
fy = forces[1]
fz = forces[2]

Matrix Inputs

# Define a 3x3 matrix
self.add_input("K", shape=(3, 3))

With Units and Labels

self.add_input("velocity", value=10.0, units="m/s", label="state")
self.add_input("force", value=100.0, units="N", label="control")

The label parameter is useful for grouping related variables, especially in optimal control problems where you might label certain inputs as "state" or "control".

Outputs

Outputs are computed quantities that can be linked to inputs of other components. They enable component coupling in multidisciplinary systems.

# Scalar output
self.add_output("lift", units="N")

# Vector output
self.add_output("stress", shape=(3,))

Outputs are computed in the compute() method:

def compute(self):
velocity = self.inputs["velocity"]
self.outputs["lift"] = 0.5 * 1.225 * velocity**2 * 10.0 # Simplified
tip

Outputs can be linked to inputs of other components using model.link(), enabling data flow between disciplines.

Constants

Constants are compile-time values that do not change during optimization. They are compiled as constexpr in the generated C++ code for maximum performance.

self.add_constant("pi", value=3.14159)
self.add_constant("g", value=9.81, units="m/s^2")
self.add_constant("E", value=200e9, units="Pa")

Constants are accessed in compute() just like inputs:

def compute(self):
g = self.constants["g"]
mass = self.inputs["mass"]
self.outputs["weight"] = mass * g

Data

Data variables allow you to pass external information into the problem that is not optimized but may change between solves.

self.add_data("temperature_field", shape=(100, 100))
self.add_data("boundary_conditions", shape=(10,))

Data is useful for:

  • External loads or boundary conditions
  • Mesh data or geometry information
  • Parameters for sensitivity studies

Intermediate Variables

The self.vars dictionary stores intermediate computation results. These variables are symbolic and participate in automatic differentiation.

def compute(self):
q = self.inputs["q"]

# Compute and store intermediate values
self.vars["sint"] = am.sin(q[1])
self.vars["cost"] = am.cos(q[1])

# Use intermediate variables
sint = self.vars["sint"]
cost = self.vars["cost"]

self.outputs["rotation"] = [cost, sint]

Intermediate variables help:

  • Organize complex computations
  • Avoid repeating calculations
  • Improve code readability
note

Intermediate variables in self.vars are automatically included in the automatic differentiation process.