# OpenGoddard

*module*

Pseudospectral optimal control with NumPy and SciPy.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/__init__.py#L1-L1)

## OpenGoddard.Condition

*class*

```python
class Condition
```

Re-exported from: `OpenGoddard._helpers`

Accumulate dimensionless equality or inequality residuals.

Equality residuals must be zero; inequality residuals must be nonnegative.
Scalar and one-dimensional inputs follow NumPy broadcasting rules. A
positive reference unit scales each residual. Prefer problem.condition()
inside callbacks so automatic differentiation selects the correct backend.

**Parameters**

- `length` (`int`) (default: `0`) — Number of initial zero residuals, normally zero.
- `backend` (`module`) (default: `np`) — NumPy-compatible module, supplied by the callback view.

**Examples**

```pycon
>>> result = Condition()
>>> result.equal(5, 5)
>>> result()
array([0.])
```

For physical bounds 0 <= x <= 100 in an inequality callback, call
result.lower_bound(x, 0) and result.upper_bound(x, 100).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L116-L190)

### OpenGoddard.Condition.add

*method*

```python
def add(arg, unit=1.0)
```

Append scalar or one-dimensional residuals using a positive scale.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L142-L148)

### OpenGoddard.Condition.change_value

*method*

```python
def change_value(index, value)
```

Replace an existing dimensionless residual by its flattened index.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L183-L185)

### OpenGoddard.Condition.equal

*method*

```python
def equal(arg1, arg2, unit=1.0)
```

Append (arg1 - arg2)/unit; enforces arg1 = arg2 in an equality callback.

**Parameters**

- `arg1` (`float or array_like`) — Left side of the equation.
- `arg2` (`float or array_like`) — Right side of the equation.
- `unit` (`float`) (default: `1.0`) — Positive reference unit for the residual.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L150-L159)

### OpenGoddard.Condition.lower_bound

*method*

```python
def lower_bound(arg1, arg2, unit=1.0)
```

Append (arg1 - arg2)/unit; enforces arg1 >= arg2 in inequalities.

**Parameters**

- `arg1` (`float or array_like`) — Physical values to constrain.
- `arg2` (`float or array_like`) — Physical lower bounds.
- `unit` (`float`) (default: `1.0`) — Positive reference unit for the residual.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L161-L170)

### OpenGoddard.Condition.upper_bound

*method*

```python
def upper_bound(arg1, arg2, unit=1.0)
```

Append (arg2 - arg1)/unit; enforces arg1 <= arg2 in inequalities.

**Parameters**

- `arg1` (`float or array_like`) — Physical values to constrain.
- `arg2` (`float or array_like`) — Physical upper bounds.
- `unit` (`float`) (default: `1.0`) — Positive reference unit for the residual.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L172-L181)

## OpenGoddard.Dynamics

*class*

```python
class Dynamics
```

Re-exported from: `OpenGoddard._helpers`

Scaled state derivatives at a section's collocation nodes.

Assign physical dx/dt values with dx[state] = values. Calling dx() converts
them to d(x/unit_states)/d(t/unit_time), flattened in state order for the
LGL residual. Scalars are broadcast to every node. Unassigned states have
zero derivative. For pointwise models that also support independent-grid
error checks and structured derivatives, use DynamicsModel.

**Examples**

Dynamics class must be used in dynamics function.
It is an example of the equation of motion of thrust and free fall.
Thrust is controllable.

$$
\dot{x} = v, \qquad \dot{v} = T/m - g
$$

```pycon
>>> def dynamics(prob, obj, section):
>>>     x = prob.states(0, section)
>>>     v = prob.states(1, section)
>>>     T = prob.controls(0, section)
>>>     g = 9.8
>>>     m = 1.0
>>>     dx = Dynamics(prob, section)
>>>     dx[0] = v
>>>     dx[1] = T / m - g
>>>     return dx()
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L193-L243)

### OpenGoddard.Dynamics.number_of_state

*attribute* · *instance attribute*

```python
number_of_state = prob.number_of_states[self.section]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L225-L225)

### OpenGoddard.Dynamics.section

*attribute* · *instance attribute*

```python
section = index(section, prob.number_of_section, 'section')
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L224-L224)

### OpenGoddard.Dynamics.unit_states

*attribute* · *instance attribute*

```python
unit_states = prob.unit_states
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L226-L226)

### OpenGoddard.Dynamics.unit_time

*attribute* · *instance attribute*

```python
unit_time = prob.unit_time
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L227-L227)

## OpenGoddard.DynamicsModel

*class*

```python
class DynamicsModel
```

Re-exported from: `OpenGoddard._models`

Pointwise physical dynamics ``function(x, u, t, obj, section, xp)``.

``x`` has shape (states, nodes), ``u`` (controls, nodes), and ``t`` (nodes,).
Return an array with shape (states, nodes). Each output column must depend
ONLY on the corresponding input column. Use ``xp`` for array operations;
it is NumPy for values and autograd.numpy for automatic differentiation.
Reductions or interpolation across nodes violate this contract.

Instances are callable with the legacy ``(problem, obj, section)`` signature.
Local derivatives use simultaneous central differences, or reverse-mode AD
of each state's sum over independent nodes. No full dense dynamics Jacobian
is formed. Non-smooth expressions require the user's choice of formulation.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L41-L133)

### OpenGoddard.DynamicsModel.function

*attribute* · *instance attribute*

```python
function = function
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L59-L59)

### OpenGoddard.DynamicsModel.inputs

*method* · *staticmethod*

```python
def inputs(problem, section)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L81-L96)

### OpenGoddard.DynamicsModel.linearize

*method*

```python
def linearize(problem, obj, section, mode)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L98-L133)

### OpenGoddard.DynamicsModel.physical

*method*

```python
def physical(x, u, time, obj, section)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L61-L67)

## OpenGoddard.Guess

*class*

```python
class Guess
```

Re-exported from: `OpenGoddard._helpers`

Construct physical initial guesses on a supplied time grid.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L20-L113)

### OpenGoddard.Guess.constant

*method* · *classmethod*

```python
def constant(time, const: float) -> NDArray[np.float64]
```

Return one constant physical value per time node.

**Parameters**

- `time` (`array_like`) — Time nodes; only their count is used.
- `const` (`float`) — Constant physical value.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Values of shape (N,).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L35-L46)

### OpenGoddard.Guess.cubic

*method* · *classmethod*

```python
def cubic(time, y0: float, yprime0: float, yf: float, yprimef: float) -> NDArray[np.float64]
```

Interpolate endpoint values and physical-time slopes with a cubic.

**Parameters**

- `time` (`array_like`) — Finite, nondecreasing physical times with a positive span. Repeated interface times are supported.
- `y0` (`float`) — Physical value at the first time.
- `yprime0` (`float`) — Physical dy/dt at the first time.
- `yf` (`float`) — Physical value at the last time.
- `yprimef` (`float`) — Physical dy/dt at the last time.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Values of shape (N,).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L65-L92)

### OpenGoddard.Guess.linear

*method* · *classmethod*

```python
def linear(time, y0: float, yf: float) -> NDArray[np.float64]
```

Interpolate physical endpoint values linearly in time.

**Parameters**

- `time` (`array_like`) — Finite, nondecreasing physical times with a positive span. Repeated interface times are supported.
- `y0` (`float`) — Physical value at the first time.
- `yf` (`float`) — Physical value at the last time.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Values of shape (N,).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L48-L63)

### OpenGoddard.Guess.plot

*method* · *classmethod*

```python
def plot(x, y, title='', xlabel='', ylabel='')
```

Plot physical initial-guess values against time.

**Parameters**

- `x` (`array_like`) — array on the horizontal axis of the plot
- `y` (`array_like`) — array on the vertical axis of the plot
- `title` (`str`) (default: `''`) — title
- `xlabel` (`str`) (default: `''`) — xlabel
- `ylabel` (`str`) (default: `''`) — ylabel

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L94-L113)

### OpenGoddard.Guess.zeros

*method* · *classmethod*

```python
def zeros(time) -> NDArray[np.float64]
```

Return one zero per time node.

**Parameters**

- `time` (`array_like`) — Time nodes; only their count is used.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Values of shape (N,).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_helpers.py#L23-L33)

## OpenGoddard.LinearCallback

*class*

```python
class LinearCallback
```

Re-exported from: `OpenGoddard._models`

Declare a cost/boundary/path callback affine in the scaled vector p.

Its Jacobian is computed once per solve and cached. This is an explicit
mathematical contract, not a heuristic: nonlinear expressions must not be
wrapped. Coefficients, units and obj must remain constant during a solve.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L24-L38)

### OpenGoddard.LinearCallback.function

*attribute* · *instance attribute*

```python
function = function
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/_models.py#L35-L35)

## OpenGoddard.Problem

*class*

```python
class Problem
```

Re-exported from: `OpenGoddard.optimize`

Define a physical optimal-control problem and solve its LGL discretization.

**Parameters**

- `time_init` (`sequence of float`) — Strictly increasing physical phase times.
- `nodes` (`sequence of int`) — LGL node counts, at least two per phase.
- `number_of_states` (`sequence of int`) — Positive state counts per phase.
- `number_of_controls` (`sequence of int`) — Nonnegative control counts per phase.
- `maxIterator` (`int`) (default: `100`) — Maximum solver attempts, including the first attempt. Another attempt is made only after an iteration-limit status. ``solve(maxiter=...)`` limits iterations within each attempt.
- `method` (`str`) (default: `'LGL'`) — Only ``"LGL"`` is supported for optimal control.
- `mesh` (`optional`) (default: `None`) — Per-section lists of ``(left, right, nodes)`` elements partitioning the phase coordinate [-1, 1]. Logical section numbers do not change. Node counts include both sides of internal interfaces.

All state, control and time getters and setters use physical units. Only
``p`` and ``bounds`` use scaled units. Setters for units preserve physical
guesses and bounds. Node, state, control and section indices follow Python's
negative indexing convention and raise IndexError outside their range.

**Attributes**

- `nodes` (`list[int]`) — Node counts per phase, including duplicated interfaces.
- `number_of_states` (`list[int]`) — State counts per phase.
- `number_of_controls` (`list[int]`) — Control counts per phase.
- `number_of_section` (`int`) — Number of logical phases.
- `number_of_param` (`ndarray`) — State plus control counts per phase.
- `number_of_variables` (`int`) — Length of p, including phase end times.
- `div` (`list[list[int]]`) — Exclusive ends of state/control blocks in p.
- `tau` (`list[ndarray]`) — LGL phase coordinates in [-1, 1].
- `w` (`list[ndarray]`) — Quadrature weights in phase coordinates.
- `D` (`list[ndarray]`) — Differentiation matrices in phase coordinates.
- `time` (`list[ndarray]`) — Physical node times, derived from current p.
- `time_all_section` (`ndarray`) — Times concatenated in phase order.
- `unit_states` (`list[list[float]]`) — State reference units per phase.
- `unit_controls` (`list[list[float]]`) — Control reference units per phase.
- `unit_time` (`float`) — Time reference unit.
- `p` (`ndarray`) — Scaled states, controls and phase end times, shape (N,).
- `bounds` (`list[tuple]`) — Scaled lower/upper bounds for every entry of p.
- `dynamics` (`list[Callable]`) — One scaled-derivative callback per phase, called as ``dynamics(problem, obj, section)``. Use Dynamics to assemble physical derivatives, or DynamicsModel for a pointwise physical model supporting derivatives and error estimation.
- `knot_states_smooth` (`list[bool]`) — Enforce continuity at phase knots with equal state counts. Disable it when supplying jump conditions.
- `cost` (`Callable | None`) — Terminal cost, called as ``cost(problem, obj)``.
- `running_cost` (`Callable | None`) — Physical-time integrand, shape (sum(nodes),), called as ``running_cost(problem, obj)``.
- `cost_derivative` (`function`) — Complete objective gradient in ``p``.
- `equality` (`Callable | None`) — One-dimensional residuals equal to zero.
- `inequality` (`Callable | None`) — One-dimensional residuals >= 0.
- `array_module` — NumPy; differentiable callback views supply autograd.numpy.
- `metadata` (`dict`) — User metadata, shallow-copied on refine/remesh.
- `result` (`OptimizeResult | None`) — Latest solver result, or None before solve.
- `result_history` (`list[OptimizeResult]`) — Attempts of the latest solve.

Callback views share states/controls (including all-section getters),
time_start/time_final, time_knots, time/time_all_section, dimensions, units,
array_module and condition(). Use this reading interface for portable
callbacks; mutations and direct p indices do not support path sampling.
Use unit setters and refine/remesh rather than editing configuration lists.
Construct a new Problem to change state/control counts. Refine/remesh create
a new mesh and reset solver results.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L53-L948)

### OpenGoddard.Problem.D

*attribute* · *instance attribute*

```python
D = [rule[2] for rule in rules]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L174-L174)

### OpenGoddard.Problem.array_module

*attribute* · *class attribute* · *instance attribute*

```python
array_module = np
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L118-L118)

### OpenGoddard.Problem.bounds

*attribute* · *instance attribute*

```python
bounds = [(None, None)] * self.number_of_variables
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L180-L180)

### OpenGoddard.Problem.cost

*attribute* · *instance attribute*

```python
cost: Callable[[Problem, Any], float] | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L185-L185)

### OpenGoddard.Problem.cost_derivative

*attribute* · *instance attribute*

```python
cost_derivative: Callable[[Problem, Any], NDArray[np.float64]] | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L187-L189)

### OpenGoddard.Problem.div

*attribute* · *instance attribute*

```python
div = [list(phase) for phase in self._layout.divisions]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L167-L167)

### OpenGoddard.Problem.dynamics

*attribute* · *instance attribute*

```python
dynamics: list[Callable[[Problem, Any, int], NDArray[np.float64]] | None] = [None] * self.number_of_section
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L181-L183)

### OpenGoddard.Problem.equality

*attribute* · *instance attribute*

```python
equality: Callable[[Problem, Any], NDArray[np.float64]] | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L190-L190)

### OpenGoddard.Problem.inequality

*attribute* · *instance attribute*

```python
inequality: Callable[[Problem, Any], NDArray[np.float64]] | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L191-L191)

### OpenGoddard.Problem.iterator

*attribute* · *instance attribute*

```python
iterator = 0
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L162-L162)

### OpenGoddard.Problem.knot_states_smooth

*attribute* · *instance attribute*

```python
knot_states_smooth = [True] * self.number_of_section - 1
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L184-L184)

### OpenGoddard.Problem.maxIterator

*attribute* · *instance attribute*

```python
maxIterator = integer(maxIterator, 'maxIterator', 1)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L161-L161)

### OpenGoddard.Problem.mesh

*attribute* · *instance attribute*

```python
mesh = normalize_mesh(self.nodes, mesh)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L170-L170)

### OpenGoddard.Problem.metadata

*attribute* · *instance attribute*

```python
metadata: dict[str, Any] = {}
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L194-L194)

### OpenGoddard.Problem.method

*attribute* · *instance attribute*

```python
method = method
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L160-L160)

### OpenGoddard.Problem.nodes

*attribute* · *instance attribute*

```python
nodes = [integer(n, 'nodes', 2) for n in nodes]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L138-L138)

### OpenGoddard.Problem.number_of_controls

*attribute* · *instance attribute*

```python
number_of_controls = [integer(n, 'number_of_controls') for n in number_of_controls]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L142-L144)

### OpenGoddard.Problem.number_of_param

*attribute* · *instance attribute*

```python
number_of_param = np.array(self.number_of_states) + self.number_of_controls
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L168-L168)

### OpenGoddard.Problem.number_of_section

*attribute* · *instance attribute*

```python
number_of_section = len(self.nodes)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L145-L145)

### OpenGoddard.Problem.number_of_states

*attribute* · *instance attribute*

```python
number_of_states = [integer(n, 'number_of_states', 1) for n in number_of_states]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L139-L141)

### OpenGoddard.Problem.number_of_variables

*attribute* · *instance attribute*

```python
number_of_variables = self._layout.size
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L169-L169)

### OpenGoddard.Problem.p

*attribute* · *instance attribute*

```python
p = np.zeros(self.number_of_variables)
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L178-L178)

### OpenGoddard.Problem.result

*attribute* · *instance attribute*

```python
result: optimize.OptimizeResult | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L192-L192)

### OpenGoddard.Problem.result_history

*attribute* · *instance attribute*

```python
result_history: list[optimize.OptimizeResult] = []
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L193-L193)

### OpenGoddard.Problem.running_cost

*attribute* · *instance attribute*

```python
running_cost: Callable[[Problem, Any], NDArray[np.float64]] | None = None
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L186-L186)

### OpenGoddard.Problem.t0

*attribute* · *instance attribute*

```python
t0 = float(times[0])
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L159-L159)

### OpenGoddard.Problem.tau

*attribute* · *instance attribute*

```python
tau = [rule[0] for rule in rules]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L172-L172)

### OpenGoddard.Problem.time_init

*attribute* · *instance attribute*

```python
time_init = times.tolist()
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L158-L158)

### OpenGoddard.Problem.unit_controls

*attribute* · *instance attribute*

```python
unit_controls = [[1.0] * n for n in self.number_of_controls]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L176-L176)

### OpenGoddard.Problem.unit_states

*attribute* · *instance attribute*

```python
unit_states = [[1.0] * n for n in self.number_of_states]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L175-L175)

### OpenGoddard.Problem.unit_time

*attribute* · *instance attribute*

```python
unit_time = 1.0
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L177-L177)

### OpenGoddard.Problem.w

*attribute* · *instance attribute*

```python
w = [rule[1] for rule in rules]
```

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L173-L173)

### OpenGoddard.Problem.time

*property*

```python
time: list[NDArray[np.float64]]
```

Physical node times per phase, derived from the current p.

Returned arrays are independent values. Change phase end times with
set_time_final(); editing these arrays does not change the problem.
Both sides of phase and element interfaces are included.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L458-L465)

### OpenGoddard.Problem.time_all_section

*property*

```python
time_all_section: NDArray[np.float64]
```

Physical node times concatenated in phase order, including interfaces.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L468-L470)

### OpenGoddard.Problem.condition

*method*

```python
def condition(length: int = 0) -> Condition
```

Build equality or inequality residuals in this view's array backend.

**Parameters**

- `length` (`int`) (default: `0`) — Number of initial zero residuals, normally zero.

**Returns**

- `Condition` (`Condition`) — A residual builder. Use equal() for equality callbacks; lower_bound()/upper_bound() produce nonnegative feasible residuals.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L662-L672)

### OpenGoddard.Problem.controls

*method*

```python
def controls(control: int, section: int) -> NDArray[np.float64]
```

Return one control's physical values in a phase.

**Parameters**

- `control` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Independent array of shape (nodes[section],). Both sides of internal element interfaces are present. Use set_controls() to edit.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L235-L247)

### OpenGoddard.Problem.controls_all_section

*method*

```python
def controls_all_section(control: int) -> NDArray[np.float64]
```

Return a control's physical values concatenated in phase order.

**Parameters**

- `control` (`int`) — Variable index, which must exist in every phase.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Shape (sum(nodes),), including duplicated interface nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L249-L263)

### OpenGoddard.Problem.estimate_error

*method*

```python
def estimate_error(obj: Any = None, check_factor: int = 2) -> dict[str, Any]
```

Estimate dimensionless residuals between the LGL nodes.

**Parameters**

- `obj` (`Any`) (default: `None`) — User data passed to the model and inequality callback.
- `check_factor` (`int`) (default: `2`) — Integer >= 2. Check each element at check_factor * element.nodes + 1 Gauss points.

**Returns**

- `dict` (`dict[str, Any]`) — section_errors (per-phase ODE indicators), max_error (their maximum), path_violation (scaled inequality/box-bound violation), and elements (per-element error, smoothness, overshoot and split point). Indicators are residual estimates, not rigorous state-error bounds. Nonlinear path constraints are checked by sampling, not certified.

**Raises**

- `ValueError` — A phase lacks DynamicsModel, has nonpositive duration,
or uses varying nodal box bounds.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L717-L738)

### OpenGoddard.Problem.index_controls

*method*

```python
def index_controls(control: int, section: int, index: int | None = None) -> int
```

Return the index of a control node in the scaled vector p.

**Parameters**

- `control` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `index` (`int | None`) (default: `None`) — Local node index, supporting negative indices; None selects the first node.

**Returns**

- `int` (`int`) — Index into p, whose values use reference-unit scaling.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L501-L518)

### OpenGoddard.Problem.index_states

*method*

```python
def index_states(state: int, section: int, index: int | None = None) -> int
```

Return the index of a state node in the scaled vector p.

**Parameters**

- `state` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `index` (`int | None`) (default: `None`) — Local node index, supporting negative indices; None selects the first node.

**Returns**

- `int` (`int`) — Index into p, whose values use reference-unit scaling.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L484-L499)

### OpenGoddard.Problem.index_time_final

*method*

```python
def index_time_final(section: int) -> int
```

Return the index of a phase end time in the scaled vector p.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L520-L522)

### OpenGoddard.Problem.method_LG

*method*

```python
def method_LG(n) -> tuple[NDArray[np.float64], ...]
```

Legendre-Gauss Pseudospectral method
Gauss nodes are roots of $P_n(x)$.

**Parameters**

- `n` (`int`) — number of nodes

**Returns**

- (`tuple[NDArray[np.float64], ...]`) — tuple[ndarray, ndarray, ndarray]: Nodes (n,), weights (n,), and D (n, n).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L887-L898)

### OpenGoddard.Problem.method_LGL

*method*

```python
def method_LGL(n) -> tuple[NDArray[np.float64], ...]
```

Legendre-Gauss-Lobatto Pseudospectral method
Gauss-Lobatto nodes are roots of $P'_{n-1}(x)$, plus -1 and 1.

**Parameters**

- `n` (`int`) — number of nodes

**Returns**

- (`tuple[NDArray[np.float64], ...]`) — tuple[ndarray, ndarray, ndarray]: Nodes (n,), weights (n,), and D (n, n).

> **References**
>
> Fariba Fahroo and I. Michael Ross. "Advances in Pseudospectral Methods
> for Optimal Control", AIAA Guidance, Navigation and Control Conference
> and Exhibit, Guidance, Navigation, and Control and Co-located Conferences
> http://dx.doi.org/10.2514/6.2008-7309

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L931-L948)

### OpenGoddard.Problem.method_LGR

*method*

```python
def method_LGR(n) -> tuple[NDArray[np.float64], ...]
```

Legendre-Gauss-Radau Pseudospectral method
Gauss-Radau nodes are roots of $P_n(x) + P_{n-1}(x)$.

**Parameters**

- `n` (`int`) — number of nodes

**Returns**

- (`tuple[NDArray[np.float64], ...]`) — tuple[ndarray, ndarray, ndarray]: Nodes (n,), weights (n,), and D (n, n).

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L909-L920)

### OpenGoddard.Problem.plot

*method*

```python
def plot(title_comment='')
```

plot inner variables that to be optimized

**Parameters**

- `title_comment` (`str`) (default: `''`) — string for title

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L851-L868)

### OpenGoddard.Problem.refine

*method*

```python
def refine(nodes) -> Problem
```

Return a new problem with interpolated guesses and new node counts.

**Parameters**

- `nodes` (`sequence of int`) — Total node counts per phase, including duplicated interfaces. At least two nodes per element are required.

**Returns**

- `Problem` (`Problem`) — A new problem preserving element boundaries, physical units, constant box bounds and callbacks. Solver results are reset. Metadata containers are shallow-copied; nested objects remain shared.

**Raises**

- `ValueError` — Counts are invalid or box bounds vary between nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L674-L691)

### OpenGoddard.Problem.remesh

*method*

```python
def remesh(mesh) -> Problem
```

Return a warm start on per-phase lists of (left, right, nodes) elements.

Element endpoints are phase coordinates in [-1, 1]. Logical section
indices remain unchanged. States are continuous at internal interfaces;
controls have independent left and right limits.

**Parameters**

- `mesh` (`sequence`) — Per-phase lists of (left, right, nodes) elements partitioning [-1, 1]. Each element includes both endpoints.

**Returns**

- `Problem` (`Problem`) — A new problem with interpolated guesses, preserved physical units, constant bounds and callbacks, and reset solver results. Metadata containers are shallow-copied. Private extension caches are not copied.

**Raises**

- `ValueError` — The mesh is invalid or box bounds vary between nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L693-L715)

### OpenGoddard.Problem.set_controls

*method*

```python
def set_controls(control: int, section: int, value: ArrayLike) -> None
```

Set one control's initial guess in physical units.

**Parameters**

- `control` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `value` (`ArrayLike`) — Finite one-dimensional values of shape (nodes[section],).

**Raises**

- `ValueError` — Values have the wrong shape or are not finite.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L323-L336)

### OpenGoddard.Problem.set_controls_all_section

*method*

```python
def set_controls_all_section(control: int, value_all_section: ArrayLike) -> None
```

Set a control's physical initial guess across all phases.

**Parameters**

- `control` (`int`) — Variable index, which must exist in every phase.
- `value_all_section` (`ArrayLike`) — Finite values of shape (sum(nodes),), in phase order and including duplicated interface nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L338-L353)

### OpenGoddard.Problem.set_controls_bounds

*method*

```python
def set_controls_bounds(control: int, section: int, lb: float | None, ub: float | None) -> None
```

Set constant physical box bounds at every node of a phase.

**Parameters**

- `control` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `lb` (`float | None`) — Physical lower bound, or None for no lower bound.
- `ub` (`float | None`) — Physical upper bound, or None for no upper bound.

> **Notes**
>
> Bounds constrain mesh nodes. Use solve_adaptive() with a supported
> model to check for violations between nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L403-L420)

### OpenGoddard.Problem.set_controls_bounds_all_section

*method*

```python
def set_controls_bounds_all_section(control: int, lb: float | None, ub: float | None) -> None
```

set value to bounds of control at all sections

**Parameters**

- `control` (`int`) — control
- `lb` (`float or None`) — lower bound
- `ub` (`float or None`) — upper bound

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L422-L434)

### OpenGoddard.Problem.set_states

*method*

```python
def set_states(state: int, section: int, value: ArrayLike) -> None
```

Set one state's initial guess in physical units.

**Parameters**

- `state` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `value` (`ArrayLike`) — Finite one-dimensional values of shape (nodes[section],).

**Raises**

- `ValueError` — Values have the wrong shape or are not finite.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L293-L306)

### OpenGoddard.Problem.set_states_all_section

*method*

```python
def set_states_all_section(state: int, value_all_section: ArrayLike) -> None
```

Set a state's physical initial guess across all phases.

**Parameters**

- `state` (`int`) — Variable index, which must exist in every phase.
- `value_all_section` (`ArrayLike`) — Finite values of shape (sum(nodes),), in phase order and including duplicated interface nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L308-L321)

### OpenGoddard.Problem.set_states_bounds

*method*

```python
def set_states_bounds(state: int, section: int, lb: float | None, ub: float | None) -> None
```

Set constant physical box bounds at every node of a phase.

**Parameters**

- `state` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `lb` (`float | None`) — Physical lower bound, or None for no lower bound.
- `ub` (`float | None`) — Physical upper bound, or None for no upper bound.

> **Notes**
>
> Bounds constrain mesh nodes. Use solve_adaptive() with a supported
> model to check for violations between nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L370-L387)

### OpenGoddard.Problem.set_states_bounds_all_section

*method*

```python
def set_states_bounds_all_section(state: int, lb: float | None, ub: float | None) -> None
```

set value to bounds of state at all sections

**Parameters**

- `state` (`int`) — state
- `lb` (`float or None`) — lower bound
- `ub` (`float or None`) — upper bound

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L389-L401)

### OpenGoddard.Problem.set_time_final

*method*

```python
def set_time_final(section: int, value: float) -> None
```

Set a phase's end-time guess in physical units.

**Parameters**

- `section` (`int`) — Phase index, supporting negative indices.
- `value` (`float`) — Finite physical end time. Times are immediately reflected in time and time_all_section. Forward ordering is enforced at solve.

**Raises**

- `ValueError` — The end time is not finite.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L355-L368)

### OpenGoddard.Problem.set_time_final_bounds

*method*

```python
def set_time_final_bounds(section: int, lb: float | None, ub: float | None) -> None
```

set value to bounds of time_final at specific section

**Parameters**

- `section` (`int`) — section
- `lb` (`float or None`) — lower bound
- `ub` (`float or None`) — upper bound

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L436-L448)

### OpenGoddard.Problem.set_unit_controls

*method*

```python
def set_unit_controls(control: int, section: int, value: float) -> None
```

Change a control's reference unit, preserving physical values and bounds.

**Parameters**

- `control` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `value` (`float`) — Finite, strictly positive reference unit.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L548-L559)

### OpenGoddard.Problem.set_unit_controls_all_section

*method*

```python
def set_unit_controls_all_section(control: int, value: float) -> None
```

set a canonical unit value to the control at all sections

**Parameters**

- `control` (`int`) — control
- `value` (`float`) — value

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L561-L570)

### OpenGoddard.Problem.set_unit_states

*method*

```python
def set_unit_states(state: int, section: int, value: float) -> None
```

Change a state's reference unit, preserving physical values and bounds.

**Parameters**

- `state` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.
- `value` (`float`) — Finite, strictly positive reference unit.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L524-L535)

### OpenGoddard.Problem.set_unit_states_all_section

*method*

```python
def set_unit_states_all_section(state: int, value: float) -> None
```

set a canonical unit value to the state at all sections

**Parameters**

- `state` (`int`) — state
- `value` (`float`) — value

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L537-L546)

### OpenGoddard.Problem.set_unit_time

*method*

```python
def set_unit_time(value: float) -> None
```

set a canonical unit value to the time

**Parameters**

- `value` (`float`) — value

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L572-L580)

### OpenGoddard.Problem.solve

*method*

```python
def solve(obj: Any = None, display_func: Callable[[], None] = _dummy_func, *, solver: str = 'SLSQP', derivatives: str = 'finite-difference', **options: Any) -> optimize.OptimizeResult
```

Solve the LGL transcription and return a SciPy OptimizeResult.

``solver`` selects SLSQP (default) or sparse ``trust-constr``.
``derivatives='finite-difference'`` preserves arbitrary legacy callbacks.
``'structured'`` assembles exact spectral blocks and local central
differences, and ``'autograd'`` uses optional automatic differentiation.
Both structured modes require DynamicsModel in every section. AD
callbacks use ``view.array_module`` and ``view.condition()``; they must
not mutate arrays or coerce traced values to Python floats. With
trust-constr, AD also supplies matrix-free Hessian-vector products.

``dynamics`` must contain a callable for each section; ``equality`` and
``inequality`` may be None. ``running_cost`` returns one integrand value
per node, concatenated in section order, in physical time. The solver
applies each section's ``(tf - ti) / 2`` quadrature factor.

``cost_derivative``, when set, must differentiate the *complete*
objective (including running cost) with respect to the scaled vector
``p``. All SLSQP options, including ``ftol``, ``maxiter``, ``eps`` and
``disp``, are forwarded. Concurrent ``workers`` are unsupported because
callbacks share this mutable Problem instance.

Solver-specific options are forwarded: SLSQP accepts ``ftol``/``eps``;
trust-constr accepts ``gtol``/``xtol``/``barrier_tol``. They are not
interchangeable. ``cost_derivative`` is used in finite-difference and
structured modes; autograd differentiates the complete objective itself.

``maxIterator`` limits total attempts, including the first. A restart
occurs only after an iteration limit (SLSQP status 9, trust-constr status 0).
Other failures stop immediately and emit RuntimeWarning. Each call
resets the restart counter. The final result is also saved in
``result`` and every attempt in ``result_history``. ``display_func``
is called without arguments after each attempt, as in the legacy API.
``time`` and ``time_all_section`` always reflect the current parameters.

**Parameters**

- `obj` (`Any`) (default: `None`) — User data passed unchanged to every model/cost/constraint callback.
- `display_func` (`Callable[[], None]`) (default: `_dummy_func`) — Called without arguments after each solver attempt.
- `solver` (`str`) (default: `'SLSQP'`) — "SLSQP" or "trust-constr".
- `derivatives` (`str`) (default: `'finite-difference'`) — "finite-difference", "structured", or "autograd".
- `**options` (`Any`) (default: `{}`) — SciPy solver options, e.g. maxiter, ftol (SLSQP) or gtol (trust-constr).

**Returns**

- `OptimizeResult` (`optimize.OptimizeResult`) — SciPy result with solver, derivatives and scaled equality_violation/inequality_violation diagnostics. The solution also replaces this problem's p. Failure returns success=False and emits RuntimeWarning; it does not raise a convergence exception.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L598-L660)

### OpenGoddard.Problem.solve_adaptive

*method*

```python
def solve_adaptive(obj: Any = None, *, tolerance: float = 1e-05, max_refinements: int = 4, max_nodes: int = 100, growth: float = 1.5, strategy: str = 'p', max_elements: int = 24, min_element_nodes: int = 6, max_order: int = 14, path_check_factor: int = 4, **solve_options: Any) -> optimize.OptimizeResult
```

Solve and adapt the mesh, updating this problem to the final mesh.

Requires DynamicsModel in every phase. Callbacks must use physical
getters and work with changing node counts. For h/hp path sampling,
avoid direct p indices and mesh-dependent global reductions.

**Parameters**

- `obj` (`Any`) (default: `None`) — User data passed to all callbacks.
- `tolerance` (`float`) (default: `1e-05`) — Positive tolerance for ODE and scaled path residuals.
- `max_refinements` (`int`) (default: `4`) — Maximum changes after the initial solve.
- `max_nodes` (`int`) (default: `100`) — Maximum total nodes per phase, including interfaces.
- `growth` (`float`) (default: `1.5`) — Node growth factor > 1 for p refinement.
- `strategy` (`str`) (default: `'p'`) — "p" increases orders; "h" splits elements; "hp" chooses between increasing orders and splitting using error indicators.
- `max_elements` (`int`) (default: `24`) — Maximum elements per phase for h/hp.
- `min_element_nodes` (`int`) (default: `6`) — Minimum child node count for hp, at least four.
- `max_order` (`int`) (default: `14`) — Node threshold for choosing h instead of p in hp.
- `path_check_factor` (`int`) (default: `4`) — Sampling density for h/hp path constraints, at least two. Not used by the p strategy.
- `**solve_options` (`Any`) (default: `{}`) — Options forwarded to solve(), including solver, derivatives and SciPy tolerances.

**Returns**

- `OptimizeResult` (`optimize.OptimizeResult`) — Final solver result. success reports optimizer convergence; mesh_converged separately reports meeting the mesh tolerance. mesh_history records every solve and residual estimate. h/hp also supply mesh_strategy and mesh_stop_reason. Stopping at a limit emits RuntimeWarning when the mesh has not converged.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L740-L799)

### OpenGoddard.Problem.states

*method*

```python
def states(state: int, section: int) -> NDArray[np.float64]
```

Return one state's physical values in a phase.

**Parameters**

- `state` (`int`) — Variable index, supporting negative indices.
- `section` (`int`) — Phase index, supporting negative indices.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Independent array of shape (nodes[section],). Both sides of internal element interfaces are present. Use set_states() to edit.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L208-L220)

### OpenGoddard.Problem.states_all_section

*method*

```python
def states_all_section(state: int) -> NDArray[np.float64]
```

Return a state's physical values concatenated in phase order.

**Parameters**

- `state` (`int`) — Variable index, which must exist in every phase.

**Returns**

- `ndarray` (`NDArray[np.float64]`) — Shape (sum(nodes),), including duplicated interface nodes.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L222-L233)

### OpenGoddard.Problem.time_final

*method*

```python
def time_final(section: int) -> float
```

Return a phase's physical end time from the current scaled p.

**Parameters**

- `section` (`int`) — Phase index; negative indices count from the last phase.

**Returns**

- (`float`) — Physical time, equal to p[index_time_final(section)] * unit_time.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L278-L287)

### OpenGoddard.Problem.time_final_all_section

*method*

```python
def time_final_all_section() -> list[float]
```

Return physical phase end times in phase order.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L289-L291)

### OpenGoddard.Problem.time_knots

*method*

```python
def time_knots() -> list[float]
```

Return physical phase boundaries [t0, tf0, tf1, ...].

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L480-L482)

### OpenGoddard.Problem.time_start

*method*

```python
def time_start(section: int) -> float
```

Return a phase's physical start time.

**Parameters**

- `section` (`int`) — Phase index; negative indices count from the last phase.

**Returns**

- (`float`) — Physical time. The first phase starts at the fixed t0; later phases start at the preceding phase's current end time.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L265-L276)

### OpenGoddard.Problem.time_to_tau

*method*

```python
def time_to_tau(time)
```

Map a finite, nonconstant time vector to [-1, 1].

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L450-L455)

### OpenGoddard.Problem.time_update

*method*

```python
def time_update() -> NDArray[np.float64]
```

Return current physical node times concatenated in phase order.

Kept for compatibility. Times are derived from p on access, so explicit
refreshes are unnecessary even after direct changes to p.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L472-L478)

### OpenGoddard.Problem.to_csv

*method*

```python
def to_csv(filename='OpenGoddard_output.csv', delimiter: str = ',') -> None
```

Write physical times, states and controls in phase/node order.

**Parameters**

- `filename` (`str or PathLike`) (default: `'OpenGoddard_output.csv'`) — Output path. Missing components in phases with fewer states or controls are written as NaN.
- `delimiter` (`str`) (default: `','`) — Column separator; a comma by default.

[View source](https://github.com/istellartech/OpenGoddard/blob/master/src/OpenGoddard/optimize.py#L821-L849)

**Modules**

- `OpenGoddard.derivatives`
- `OpenGoddard.hp`
- `OpenGoddard.mesh`
- `OpenGoddard.optimize`
