Mission

The initial conditions a run starts from, and the ladder that converges the hard ones.

This module is the direct counterpart of set_values(prob, num_nodes) in OpenConcept’s B738.py and of set_mission_profile(prob) in its B738_sizing.py. Both are functions that write a list of values into a problem before running it:

prob.set_val("climb.fltcond|vs", np.linspace(2300.0, 600.0, num_nodes), units="ft/min")
prob.set_val("climb.fltcond|Ueas", np.linspace(230, 220, num_nodes), units="kn")
prob.set_val("cruise|h0", 33000.0, units="ft")
prob.set_val("mission_range", 2050, units="NM")

InitialConditions is that list written as data instead of as statements, with the same names. A value may be a single number, a pair of endpoints to interpolate across the phase exactly as np.linspace does above, or one number per analysis node.

ContinuationStep and ContinuationLadder are the second half of set_mission_profile: the part that converges an easy mission first and steps up to the design one, because a Newton solver started cold on a 2800 nmi mission at 35,000 ft does not reach it. OpenConcept writes that as two run_model() calls between blocks of assignments; here it is a list of rungs, so it travels with the case it converges.

Nothing here imports OpenConcept or OpenMDAO. Conditions are written into anything that accepts set(name, value, units), run() and shape_of(name).

class cdadt.mission.ContinuationLadder(steps=())[source]

Bases: object

The rungs walked before the design mission, and the walk itself.

Parameters:

steps (sequence of ContinuationStep, optional) – Progressively harder missions, converged in order. Empty attempts the design mission directly, which for a long-range mission generally fails.

property steps: tuple[ContinuationStep, ...]

The rungs, in the order they are walked.

converge(box, conditions, verbose=False)[source]

Walk every rung, then converge the design conditions.

Each rung is written on top of the design conditions and converged, so the solver enters the next rung from a converged neighbour. The final run is the design mission itself.

Parameters:
Return type:

None

class cdadt.mission.ContinuationStep(description, conditions=None)[source]

Bases: object

One rung of the ladder up to the design mission.

Parameters:
  • description (str) – What this rung relaxes, for the run log.

  • conditions (mapping, optional) – Initial-condition overrides for this rung, as name -> (value, units). A rung states only what it changes; everything else is the design condition.

property description: str

What this rung relaxes.

property conditions: dict[str, tuple[Any, str | None]]

The overrides this rung applies.

class cdadt.mission.InitialConditions(values, mission_path='mission')[source]

Bases: object

The values a run starts from, by name.

Parameters:
  • values (mapping) – name -> (value, units). The value may be a float, a two-element sequence of endpoints, or one value per analysis node.

  • mission_path (str, optional) –

    Subsystem the mission lives under inside the black box. Default "mission".

    Names are written exactly as OpenConcept’s own run scripts write them – cruise|h0, climb.fltcond|vs – because in those scripts the mission is promoted to the top of the model. In the sizing analysis it is a subsystem, so a name that is not settable on its own is retried under this path. A name that resolves either way resolves the same way every time, and resolve() is what a message quotes when it does not resolve at all.

Examples

>>> conditions = InitialConditions({"cruise|h0": (35000.0, "ft")})
>>> conditions.resolve("cruise|h0", box)
'mission.cruise|h0'
property mission_path: str

Subsystem the mission lives under inside the black box.

property values: dict[str, tuple[Any, str | None]]

Return the conditions as name -> (value, units).

merged_with(other)[source]

Return these conditions with other written on top.

How a continuation rung is applied: the design conditions first, then whatever the rung overrides, so a rung states only what it relaxes.

Parameters:

other (InitialConditions | Mapping[str, tuple[Any, str | None]])

Return type:

InitialConditions

resolve(name, box)[source]

Return the name the black box actually publishes this condition under.

Tries the name as written, then under the mission path. Raises naming both attempts, because “is it cruise|h0 or mission.cruise|h0” is the first question a failure here raises and the message should answer it.

Parameters:
  • name (str)

  • box (Any)

Return type:

str

resample(value, shape, name)[source]

Return value shaped to fit shape.

A float is left alone and broadcast by OpenMDAO. A two-element sequence is interpolated across the target, which is what np.linspace(2300.0, 600.0, num_nodes) does in OpenConcept’s own run script. A full-length sequence is used as given.

Raises:

MissionError – For any other length. Broadcasting a wrong-length schedule would quietly fly a different mission than the one the case file asks for.

Parameters:
  • value (Any)

  • shape (tuple[int, ...])

  • name (str)

Return type:

Any

apply(box)[source]

Write every condition into the box, without converging it.

Parameters:

box (SupportsConditions)

Return type:

None

check(box)[source]

Raise if any condition names something the box does not publish.

Parameters:

box (Any)

Return type:

None

exception cdadt.mission.MissionError[source]

Bases: Exception

Raised when an initial condition cannot be resampled onto the grid it is written to.

class cdadt.mission.SupportsConditions(*args, **kwargs)[source]

Bases: Protocol

Anything initial conditions can be written into.

Deliberately narrow: the profile needs to set a value, ask how big the target is so a pair of endpoints can be interpolated across it, and converge. That keeps this module free of any OpenMDAO import and testable without building a model.

set(name, value, units=None)[source]

Set name to value, interpreting it in units.

Parameters:
  • name (str)

  • value (Any)

  • units (str | None)

Return type:

None

shape_of(name)[source]

Return the shape the box declares for name.

Parameters:

name (str)

Return type:

tuple[int, …]

run()[source]

Converge the current state.

Return type:

None