Skip to content

← Back to calculate_responses0 documentation

calculate_responses0 - Source Code

File: userfiles/SSBJ/subsystem0/calculate_responses0.py

# Copyright (C) The DistributedDesignOptimizer Contributors
# Licensed under the GNU General Public License v3.0. See LICENSE file for details.
#
# This file contains code derived from the DMDO framework by Ahmed Bayoumy,
# originally published under the GNU General Public License v3.0.
# Source: https://github.com/Ahmed-Bayoumy/DMDO/blob/DEV/tests/SBJ/SSBJ_Aircraft.py
# Relevant original function: _calculate_range()
#
# Modifications from the original:
#   - Refactored from a class-based structure (SSBJ_Aircraft) to a standalone function.
#   - Inlined the _calculate_theta_r() helper logic directly into calculate_range().
#   - Parameters are passed as function arguments instead of class attributes.
#   - Removed auxiliary methods: SBJ_aircraft_analysis(), SBJ_aircraft_opt(),
#       get_results(), __str__(), __repr__().
#   - Added type hints to function signatures.
#   - Added Google-style docstrings.
#   - CORRECTED the Breguet range equation. The original DMDO code computes
#       np.sqrt(theta_r / SFC), which places the specific fuel consumption (SFC)
#       under the square root and makes range scale as SFC^(-0.5). The standard
#       Breguet range equation for jet aircraft (Anderson, Raymer, MIT 16.Unified)
#       is R = (a*M / (g*c_T)) * (L/D) * ln(W1/W2), where the thrust-specific fuel
#       consumption c_T enters linearly (R proportional to 1/SFC). The square root
#       applies only to the temperature ratio theta_r, because it originates from
#       the speed of sound a = a_0 * sqrt(theta_r) (a_0 = 661 kn at sea level).
#       We therefore use np.sqrt(theta_r) / SFC instead of np.sqrt(theta_r / SFC).
#       This also matches the NoHiMDO reference implementations
#       (bastientalgorn/NoHiMDO and khbalhandawi/NoHiMDO). Note: this is a
#       physics-fidelity change and alters the computed range (~1.4x at the
#       nominal point), which affects the range >= 2000 nmi constraint.
"""Response calculation module for SSBJ Subsystem 0 (Aircraft).

This module provides the range calculation for the aircraft subsystem
of the Supersonic Business Jet (SSBJ) problem.
"""

import numpy as np
import math


def calculate_range(specific_fuel_consumption: float, lift_to_drag_ratio: float, total_weight: float, fuel_weight: float, h: float, Mach: float) -> float:
        """Calculate the aircraft range using the Breguet range equation.

        Args:
            specific_fuel_consumption: Specific fuel consumption coefficient [1/hr].
            lift_to_drag_ratio: Lift-to-drag ratio [-].
            total_weight: Total aircraft weight [lb].
            fuel_weight: Fuel weight [lb].
            h: Altitude in feet [ft].
            Mach: Mach number [-].

        Returns:
            Range in nautical miles [nmi].
        """
        if h < 36089:
            theta_r = 1 - 0.000006875 * h  # temperature ratio [-]
        else:
            theta_r = 0.7519  # temperature ratio [-]

        # Breguet range: V = a*M with a = a_0 * sqrt(theta_r) (a_0 = 661 kn), and the
        # specific fuel consumption divides linearly (R ~ 1/SFC). The sqrt wraps only
        # theta_r. This corrects the original DMDO form np.sqrt(theta_r / SFC); see
        # the module header for the full rationale.
        return (Mach * lift_to_drag_ratio * 661.0 *
                np.sqrt(theta_r) / specific_fuel_consumption *
                math.log((total_weight) / (total_weight - fuel_weight)))