maptor.solution#
Classes for working with optimization results.
- class maptor.solution.Solution(raw_solution, problem, auto_summary=True)[source]#
Bases:
object
Optimal control solution with comprehensive data access and analysis capabilities.
Provides unified interface for accessing optimization results, trajectories, solver diagnostics, mesh information, and adaptive refinement data. Supports both single-phase and multiphase problems with automatic data concatenation.
Data Access Patterns:
Mission-wide access (concatenates all phases): - solution[“variable_name”] - Variable across all phases - solution[“time_states”] - State time points across all phases - solution[“time_controls”] - Control time points across all phases
Phase-specific access: - solution[(phase_id, “variable_name”)] - Variable in specific phase - solution[(phase_id, “time_states”)] - State times in specific phase - solution[(phase_id, “time_controls”)] - Control times in specific phase
Existence checking: - “variable_name” in solution - Check mission-wide variable - (phase_id, “variable”) in solution - Check phase-specific variable
- Examples:
Basic solution workflow:
>>> solution = mtor.solve_adaptive(problem) >>> if solution.status["success"]: ... print(f"Objective: {solution.status['objective']:.6f}") ... solution.plot()
Mission-wide data access:
>>> altitude_all = solution["altitude"] # All phases concatenated >>> velocity_all = solution["velocity"] # All phases concatenated >>> state_times_all = solution["time_states"] # All phase state times
Phase-specific data access:
>>> altitude_p1 = solution[(1, "altitude")] # Phase 1 only >>> velocity_p2 = solution[(2, "velocity")] # Phase 2 only >>> state_times_p1 = solution[(1, "time_states")]
Data extraction patterns:
>>> # Final/initial values >>> final_altitude = solution["altitude"][-1] >>> initial_velocity = solution["velocity"][0] >>> final_mass_p1 = solution[(1, "mass")][-1] >>> >>> # Extrema >>> max_altitude = max(solution["altitude"]) >>> min_thrust_p2 = min(solution[(2, "thrust")])
Variable existence checking:
>>> if "altitude" in solution: ... altitude_data = solution["altitude"] >>> if (2, "thrust") in solution: ... thrust_p2 = solution[(2, "thrust")]
Phase information access:
>>> for phase_id, phase_data in solution.phases.items(): ... duration = phase_data["times"]["duration"] ... state_names = phase_data["variables"]["state_names"]
Solution validation:
>>> status = solution.status >>> if status["success"]: ... objective = status["objective"] ... mission_time = status["total_mission_time"] ... else: ... print(f"Failed: {status['message']}")
- Parameters:
raw_solution (OptimalControlSolution | None)
problem (ProblemProtocol | None)
auto_summary (bool)
- __init__(raw_solution, problem, auto_summary=True)[source]#
Initialize solution wrapper from raw multiphase optimization results.
- Args:
raw_solution: Raw optimization results from solver problem: Problem protocol instance auto_summary: Whether to automatically display comprehensive summary (default: True)
- Parameters:
raw_solution (OptimalControlSolution | None)
problem (ProblemProtocol | None)
auto_summary (bool)
- Return type:
None
- property status: dict[str, Any]#
Complete solution status and optimization results.
Provides comprehensive optimization outcome information including success status, objective value, and mission timing. Essential for solution validation and performance assessment.
- Returns:
Dictionary containing complete status information:
success (bool): Optimization success status
message (str): Detailed solver status message
objective (float): Final objective function value
total_mission_time (float): Sum of all phase durations
- Examples:
Success checking:
>>> if solution.status["success"]: ... print("Optimization successful")
Objective extraction:
>>> objective = solution.status["objective"] >>> mission_time = solution.status["total_mission_time"]
Error handling:
>>> status = solution.status >>> if not status["success"]: ... print(f"Failed: {status['message']}") ... print(f"Objective: {status['objective']}") # May be NaN
Status inspection:
>>> print(f"Success: {solution.status['success']}") >>> print(f"Message: {solution.status['message']}") >>> print(f"Objective: {solution.status['objective']:.6e}") >>> print(f"Mission time: {solution.status['total_mission_time']:.3f}")
- property phases: dict[int, dict[str, Any]]#
Comprehensive phase information and data organization.
Provides detailed data for each phase including timing, variables, mesh configuration, and trajectory arrays. Essential for understanding multiphase structure and accessing phase-specific information.
- Returns:
Dictionary mapping phase IDs to phase data:
Phase data structure:
- times (dict): Phase timing
initial (float): Phase start time
final (float): Phase end time
duration (float): Phase duration
- variables (dict): Variable information
state_names (list): State variable names
control_names (list): Control variable names
num_states (int): Number of states
num_controls (int): Number of controls
- mesh (dict): Mesh configuration
polynomial_degrees (list): Polynomial degree per interval
mesh_nodes (FloatArray): Mesh node locations
num_intervals (int): Total intervals
- time_arrays (dict): Time coordinates
states (FloatArray): State time points
controls (FloatArray): Control time points
integrals (float | FloatArray | None): Integral values
- Examples:
Phase iteration:
>>> for phase_id, phase_data in solution.phases.items(): ... print(f"Phase {phase_id}")
Timing information:
>>> phase_1 = solution.phases[1] >>> duration = phase_1["times"]["duration"] >>> start_time = phase_1["times"]["initial"] >>> end_time = phase_1["times"]["final"]
Variable information:
>>> variables = solution.phases[1]["variables"] >>> state_names = variables["state_names"] # ["x", "y", "vx", "vy"] >>> control_names = variables["control_names"] # ["thrust_x", "thrust_y"] >>> num_states = variables["num_states"] # 4 >>> num_controls = variables["num_controls"] # 2
Mesh information:
>>> mesh = solution.phases[1]["mesh"] >>> degrees = mesh["polynomial_degrees"] # [6, 8, 6] >>> intervals = mesh["num_intervals"] # 3 >>> nodes = mesh["mesh_nodes"] # [-1, -0.5, 0.5, 1]
Time arrays:
>>> time_arrays = solution.phases[1]["time_arrays"] >>> state_times = time_arrays["states"] # State time coordinates >>> control_times = time_arrays["controls"] # Control time coordinates
Integral values:
>>> integrals = solution.phases[1]["integrals"] >>> if isinstance(integrals, float): ... single_integral = integrals # Single integral >>> else: ... multiple_integrals = integrals # Array of integrals
- property parameters: dict[str, Any] | None#
Static parameter optimization results and information.
Provides access to optimized static parameters with comprehensive parameter information. Returns None if no parameters were defined.
- Returns:
Parameter information dictionary or None:
values (FloatArray): Optimized parameter values
names (list[str] | None): Parameter names if available
count (int): Number of static parameters
- Examples:
Parameter existence check:
>>> if solution.parameters is not None: ... print("Problem has static parameters")
Parameter access:
>>> params = solution.parameters >>> if params: ... values = params["values"] # [500.0, 1500.0, 0.1] ... count = params["count"] # 3 ... names = params["names"] # ["mass", "thrust", "drag"] or None
Named parameter access:
>>> params = solution.parameters >>> if params and params["names"]: ... for name, value in zip(params["names"], params["values"]): ... print(f"{name}: {value:.6f}")
Unnamed parameter access:
>>> params = solution.parameters >>> if params: ... for i, value in enumerate(params["values"]): ... print(f"Parameter {i}: {value:.6f}")
No parameters case:
>>> if solution.parameters is None: ... print("No static parameters in problem")
- property adaptive: dict[str, Any] | None#
Adaptive mesh refinement algorithm results and convergence diagnostics.
Provides comprehensive adaptive algorithm performance data including convergence status, error estimates, and refinement statistics. Only available for adaptive solver solutions.
- Returns:
Adaptive algorithm data dictionary or None:
converged (bool): Algorithm convergence status
iterations (int): Refinement iterations performed
target_tolerance (float): Target error tolerance
phase_converged (dict): Per-phase convergence status
final_errors (dict): Final error estimates per phase
gamma_factors (dict): Normalization factors per phase
- Examples:
Adaptive solution check:
>>> if solution.adaptive: ... print("Adaptive solution available")
Convergence assessment:
>>> adaptive_info = solution.adaptive >>> if adaptive_info: ... converged = adaptive_info["converged"] ... iterations = adaptive_info["iterations"] ... tolerance = adaptive_info["target_tolerance"]
Per-phase convergence:
>>> if solution.adaptive: ... for phase_id, converged in solution.adaptive["phase_converged"].items(): ... status = "✓" if converged else "✗" ... print(f"Phase {phase_id}: {status}")
Error analysis:
>>> if solution.adaptive: ... for phase_id, errors in solution.adaptive["final_errors"].items(): ... max_error = max(errors) if errors else 0.0 ... print(f"Phase {phase_id} max error: {max_error:.2e}")
Algorithm statistics:
>>> adaptive = solution.adaptive >>> if adaptive: ... print(f"Converged: {adaptive['converged']}") ... print(f"Iterations: {adaptive['iterations']}") ... print(f"Target tolerance: {adaptive['target_tolerance']:.1e}")
Fixed mesh solution:
>>> if solution.adaptive is None: ... print("Fixed mesh solution - no adaptive data")
- plot(phase_id=None, *variable_names, figsize=(12.0, 8.0), show_phase_boundaries=True)[source]#
Plot solution trajectories with comprehensive customization options.
Creates trajectory plots with automatic formatting, phase boundaries, and flexible variable selection. Supports both single-phase and multiphase visualization with professional styling.
- Return type:
- Parameters:
- Args:
- phase_id: Phase selection:
None: Plot all phases (default)
int: Plot specific phase only
- variable_names: Variable selection:
Empty: Plot all variables
Specified: Plot only named variables
figsize: Figure size tuple (width, height)
show_phase_boundaries: Display vertical lines at phase transitions
- Examples:
Basic plotting:
>>> solution.plot() # All variables, all phases
Specific phase:
>>> solution.plot(phase_id=1) # Phase 1 only
Selected variables:
>>> solution.plot(phase_id=None, "altitude", "velocity", "thrust")
Custom formatting:
>>> solution.plot( ... figsize=(16, 10), ... show_phase_boundaries=True ... )
Phase-specific variables:
>>> solution.plot(1, "x_position", "y_position") # Phase 1 positions
No phase boundaries:
>>> solution.plot(show_phase_boundaries=False)
- summary(comprehensive=True)[source]#
Display solution summary with comprehensive details and diagnostics.
Prints detailed overview including solver status, phase information, mesh details, and adaptive algorithm results. Essential for solution validation and performance analysis.
- Args:
- comprehensive: Summary detail level:
True: Full detailed summary (default)
False: Concise key information only
- Examples:
Full summary:
>>> solution.summary() # Comprehensive details
Concise summary:
>>> solution.summary(comprehensive=False) # Key information only
Manual summary control:
>>> # Solve without automatic summary >>> solution = mtor.solve_adaptive(problem, show_summary=False) >>> # Display summary when needed >>> solution.summary()
Conditional summary:
>>> if solution.status["success"]: ... solution.summary() ... else: ... solution.summary(comprehensive=False) # Brief failure info