Skip to main content
Glama

rocket_3dof_trajectory

Calculate 3DOF rocket trajectory using numerical integration for flight planning and aerospace analysis. Input rocket geometry and launch conditions to get trajectory results.

Instructions

Calculate 3DOF rocket trajectory using numerical integration.

Args: rocket_geometry: Rocket geometry parameters launch_conditions: Launch conditions (launch_angle_deg, launch_site, etc.) simulation_options: Optional simulation settings

Returns: Formatted string with trajectory analysis results

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
rocket_geometryYes
launch_conditionsYes
simulation_optionsNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • MCP tool handler function that processes input parameters (rocket_geometry dict, launch_conditions dict, simulation_options dict), creates RocketGeometry object, delegates to core trajectory analysis, and formats results into readable text with performance summary, key trajectory points, and JSON performance data.
    def rocket_3dof_trajectory(
        rocket_geometry: dict,
        launch_conditions: dict,
        simulation_options: dict | None = None,
    ) -> str:
        """Calculate 3DOF rocket trajectory using numerical integration.
    
        Args:
            rocket_geometry: Rocket geometry parameters
            launch_conditions: Launch conditions (launch_angle_deg, launch_site, etc.)
            simulation_options: Optional simulation settings
    
        Returns:
            Formatted string with trajectory analysis results
        """
        try:
            from ..integrations.rockets import (
                RocketGeometry,
            )
            from ..integrations.rockets import (
                rocket_3dof_trajectory as _trajectory_analysis,
            )
    
            # Create geometry object
            geometry = RocketGeometry(**rocket_geometry)
    
            # Run trajectory analysis
            result = _trajectory_analysis(geometry, launch_conditions, simulation_options)
    
            # Format response
            result_lines = [
                "3DOF Rocket Trajectory Analysis",
                "=" * 50,
                f"Rocket: {geometry.length_m:.1f}m long, {geometry.diameter_m:.2f}m dia",
                f"Mass: {geometry.dry_mass_kg:.1f} kg dry + {geometry.propellant_mass_kg:.1f} kg prop",
                f"Launch Angle: {launch_conditions.get('launch_angle_deg', 90):.1f}°",
                "",
                "Performance Summary:",
                f"  Max Altitude: {result.performance.max_altitude_m:.0f} m ({result.performance.max_altitude_m / 1000:.2f} km)",
                f"  Max Velocity: {result.performance.max_velocity_ms:.1f} m/s (Mach {result.performance.max_mach:.2f})",
                f"  Apogee Time: {result.performance.apogee_time_s:.1f} s",
                f"  Burnout Time: {result.performance.burnout_time_s:.1f} s",
                f"  Max Q: {result.performance.max_q_pa / 1000:.1f} kPa",
                f"  Total Impulse: {result.performance.total_impulse_ns:.0f} N⋅s",
                f"  Specific Impulse: {result.performance.specific_impulse_s:.1f} s",
            ]
    
            # Add trajectory points summary
            if hasattr(result, "trajectory") and result.trajectory:
                result_lines.extend(
                    [
                        "",
                        "Key Trajectory Points:",
                        f"{'Time (s)':>8} {'Alt (m)':>8} {'Vel (m/s)':>10} {'Accel (m/s²)':>12}",
                    ]
                )
                result_lines.append("-" * 45)
    
                # Sample key points
                trajectory = result.trajectory
                sample_indices = [
                    0,
                    len(trajectory) // 4,
                    len(trajectory) // 2,
                    3 * len(trajectory) // 4,
                    -1,
                ]
    
                for i in sample_indices:
                    if i < len(trajectory):
                        point = trajectory[i]
                        result_lines.append(
                            f"{point.time_s:8.1f} {point.altitude_m:8.0f} {point.velocity_ms:10.1f} "
                            f"{point.acceleration_ms2:12.1f}"
                        )
    
            # Add JSON data
            json_data = json.dumps(
                {
                    "performance": {
                        "max_altitude_m": result.performance.max_altitude_m,
                        "max_velocity_ms": result.performance.max_velocity_ms,
                        "apogee_time_s": result.performance.apogee_time_s,
                        "burnout_time_s": result.performance.burnout_time_s,
                        "max_q_pa": result.performance.max_q_pa,
                        "total_impulse_ns": result.performance.total_impulse_ns,
                        "specific_impulse_s": result.performance.specific_impulse_s,
                    }
                },
                indent=2,
            )
            result_lines.extend(["", "JSON Performance Data:", json_data])
    
            return "\n".join(result_lines)
    
        except ImportError:
            return "Rocket trajectory analysis not available - install rocketry packages"
        except Exception as e:
            logger.error(f"Rocket trajectory error: {str(e)}", exc_info=True)
            return f"Rocket trajectory error: {str(e)}"
  • Explicit schema definition for the rocket_3dof_trajectory tool as a ToolReference, including name, description, parameters (geometry dict, dt_s, max_time_s, launch_angle_deg), and examples.
    ToolReference(
        name="rocket_3dof_trajectory",
        description="Simulate 3DOF rocket trajectory with atmospheric effects",
        parameters={
            "geometry": "dict - Rocket geometry with mass_kg, thrust_n, burn_time_s, drag_coeff, reference_area_m2",
            "dt_s": "float - Time step in seconds (default 0.1)",
            "max_time_s": "float - Maximum simulation time in seconds (default 300)",
            "launch_angle_deg": "float - Launch angle in degrees from vertical (default 0)",
        },
        examples=[
            'rocket_3dof_trajectory({"mass_kg": 500, "thrust_n": 8000, "burn_time_s": 60, "drag_coeff": 0.3, "reference_area_m2": 0.5}, 0.1, 300, 15)'
        ],
    ),
  • Explicit registration of the rocket_3dof_trajectory tool with FastMCP server via mcp.tool(rocket_3dof_trajectory).
    mcp.tool(rocket_3dof_trajectory)
  • Core physics implementation: 3DOF rocket trajectory simulator using numerical Euler integration, handling thrust curves, atmospheric density, drag forces, gravity, propellant mass flow, and returning list of trajectory points.
    def rocket_3dof_trajectory(
        geometry: RocketGeometry,
        dt_s: float = 0.1,
        max_time_s: float = 300.0,
        launch_angle_deg: float = 90.0,
    ) -> list[RocketTrajectoryPoint]:
        """
        Calculate 3DOF rocket trajectory using numerical integration.
    
        Args:
            geometry: Rocket geometry and mass properties
            dt_s: Time step for integration (seconds)
            max_time_s: Maximum simulation time (seconds)
            launch_angle_deg: Launch angle from horizontal (degrees)
    
        Returns:
            List of trajectory points
        """
        # Initial conditions
        trajectory = []
        time = 0.0
        altitude = 0.0  # m above sea level
        velocity_vertical = 0.0  # m/s
        velocity_horizontal = 0.0  # m/s
        mass = geometry.dry_mass_kg + geometry.propellant_mass_kg
    
        # Launch angle in radians
        launch_angle_rad = math.radians(launch_angle_deg)
    
        # Constants
        g0 = 9.80665  # m/s² standard gravity
    
        # Get atmosphere profile for drag calculations
        max_alt_m = 50000  # 50km max altitude for atmosphere
        alt_points = list(range(0, max_alt_m + 1000, 1000))
        atm_profile = get_atmosphere_profile(alt_points, "ISA")
        atm_dict = {point.altitude_m: point for point in atm_profile}
    
        while time <= max_time_s and altitude >= 0:
            # Get current thrust
            thrust = (
                get_thrust_at_time(geometry.thrust_curve, time)
                if geometry.thrust_curve
                else 0.0
            )
    
            # Get atmospheric properties at current altitude
            atm_alt = min(max_alt_m, max(0, int(altitude // 1000) * 1000))
            if atm_alt in atm_dict:
                atm = atm_dict[atm_alt]
                rho = atm.density_kg_m3
                speed_of_sound = atm.speed_of_sound_mps
            else:
                # Fallback for extreme altitudes
                rho = 1.225 * math.exp(-altitude / 8400)  # Simple exponential model
                speed_of_sound = 343.0 * math.sqrt(
                    max(0.1, (288.15 - 0.0065 * altitude) / 288.15)
                )
    
            # Total velocity
            velocity_total = math.sqrt(velocity_vertical**2 + velocity_horizontal**2)
    
            # Mach number
            mach = velocity_total / speed_of_sound if speed_of_sound > 0 else 0.0
    
            # Dynamic pressure
            dynamic_pressure = 0.5 * rho * velocity_total**2
    
            # Drag force (opposing velocity direction)
            drag_area = math.pi * (geometry.diameter_m / 2) ** 2
            drag_force = geometry.cd * drag_area * dynamic_pressure
    
            # Drag acceleration components
            if velocity_total > 0:
                drag_accel_vertical = (
                    -drag_force * (velocity_vertical / velocity_total) / mass
                )
                drag_accel_horizontal = (
                    -drag_force * (velocity_horizontal / velocity_total) / mass
                )
            else:
                drag_accel_vertical = 0.0
                drag_accel_horizontal = 0.0
    
            # Thrust acceleration (in launch direction initially, then vertical)
            if time < 5.0:  # First 5 seconds follow launch angle
                thrust_accel_vertical = thrust * math.sin(launch_angle_rad) / mass
                thrust_accel_horizontal = thrust * math.cos(launch_angle_rad) / mass
            else:  # After 5 seconds, thrust is vertical only
                thrust_accel_vertical = thrust / mass
                thrust_accel_horizontal = 0.0
    
            # Total acceleration
            accel_vertical = thrust_accel_vertical - g0 + drag_accel_vertical
            accel_horizontal = thrust_accel_horizontal + drag_accel_horizontal
    
            # Record current state
            trajectory.append(
                RocketTrajectoryPoint(
                    time_s=time,
                    altitude_m=altitude,
                    velocity_ms=velocity_total,
                    acceleration_ms2=math.sqrt(accel_vertical**2 + accel_horizontal**2),
                    mass_kg=mass,
                    thrust_n=thrust,
                    drag_n=drag_force,
                    mach=mach,
                    dynamic_pressure_pa=dynamic_pressure,
                )
            )
    
            # Integration (Euler method)
            velocity_vertical += accel_vertical * dt_s
            velocity_horizontal += accel_horizontal * dt_s
            altitude += velocity_vertical * dt_s
    
            # Update mass (simple propellant consumption)
            if thrust > 0 and geometry.thrust_curve:
                # Estimate mass flow rate from thrust curve
                # For a simplified model, assume constant mass flow rate during burn
                burn_time_total = max(
                    (point[0] for point in geometry.thrust_curve if point[1] > 0),
                    default=1.0,
                )
                if burn_time_total > 0:
                    mass_flow_rate = geometry.propellant_mass_kg / burn_time_total
                    mass = max(geometry.dry_mass_kg, mass - mass_flow_rate * dt_s)
    
            time += dt_s
    
            # Stop if apogee reached and descending
            if altitude > 0 and velocity_vertical < -1.0:
                break
    
        return trajectory
  • Dataclass RocketGeometry defining structure for rocket parameters: dry_mass_kg, propellant_mass_kg, diameter_m, length_m, cd, thrust_curve.
    @dataclass
    class RocketGeometry:
        """Rocket geometry parameters."""
    
        dry_mass_kg: float  # Rocket dry mass
        propellant_mass_kg: float  # Initial propellant mass
        diameter_m: float  # Rocket diameter
        length_m: float  # Total rocket length
        cd: float = 0.3  # Drag coefficient
        thrust_curve: list[list[float]] = (
            None  # [[time_s, thrust_N], ...] or constant thrust
        )
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It mentions 'numerical integration' and 'formatted string' output, but lacks critical behavioral details: computational intensity, accuracy assumptions, error handling, or runtime characteristics. For a complex simulation tool with nested objects, this is a significant gap in transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise with a clear purpose statement followed by structured 'Args' and 'Returns' sections. Each sentence serves a purpose, though the parameter hints could be more informative. It's front-loaded with the core functionality, avoiding unnecessary verbosity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (3 parameters with nested objects, no annotations, but has output schema), the description is minimally adequate. The output schema existence means return values needn't be detailed, but the description lacks sufficient context on inputs, behavior, and usage relative to siblings. It meets a baseline but has clear gaps for effective agent use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the schema provides no parameter details. The description lists parameter names ('rocket_geometry', 'launch_conditions', 'simulation_options') with brief hints ('geometry parameters', 'launch_angle_deg, launch_site, etc.'), but doesn't explain what these mean, their expected formats, or required sub-properties. This insufficiently compensates for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Calculate 3DOF rocket trajectory using numerical integration.' It specifies the verb ('calculate'), resource ('3DOF rocket trajectory'), and method ('numerical integration'), which distinguishes it from siblings like 'optimize_launch_angle' or 'trajectory_sensitivity_analysis'. However, it doesn't explicitly differentiate from all trajectory-related siblings, keeping it at 4 instead of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'optimize_launch_angle', 'trajectory_sensitivity_analysis', and 'plan_flight', there's no indication of this tool's specific context or exclusions. The minimal 'Args' and 'Returns' sections don't address usage scenarios, leaving the agent without direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cheesejaguar/aerospace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server