Appendix C: Python and Scientific-Computing Setup

This book was written to be read without a computer. Every code listing in it carries its result inline, in an # Expected output: comment that the author computed by hand — so you can follow the reasoning on a train, in a chair, with a pencil, and never once open a terminal. Nothing in the mathematics or the physics depends on your running anything.

But the code is real. It is ordinary Python that any of the four scientific libraries below will execute, and if you would like to run the examples, change the numbers, watch an orbit close, or grow the astrotools package alongside your Mission Design Review, this appendix is the short, welcoming setup guide for doing so. Think of it as optional but rewarding: the fastest way to build intuition for the rocket equation is to feed it your own rocket and see the exponential bite.

A standing convention: in this book, code is never executed at build time. Every listing ends with a hand-traced # Expected output: comment, and every printed number was derived on paper and sanity-checked against reality — exactly as you would check a delta-v of $9{,}000\ \text{km/s}$ and conclude you must have slipped a unit. When you run these snippets yourself, tiny trailing digits may differ with your library versions; the shown precision is chosen to be robust to that.

Installing Python and the four libraries

The examples target Python 3.10 or newer. If you do not already have it, install it from python.org (or via your platform's package manager). Confirm the version from a terminal:

python --version
# -> Python 3.10.x  (or newer)

Work inside a virtual environment. A virtual environment is a private, throwaway sandbox for one project's packages, so this book's libraries never collide with anything else on your machine. Create and activate one in the folder where you keep your mission code:

python -m venv .venv

# Windows (PowerShell):
.venv\Scripts\Activate.ps1
# macOS / Linux:
source .venv/bin/activate

Install the four libraries. The repository ships a requirements.txt pinning the whole set; install it in one line:

pip install -r requirements.txt

That pulls in exactly four packages (and their own dependencies):

Package Minimum version What it gives you here
numpy 1.24 arrays, linear algebra, state vectors
scipy 1.10 ODE solvers, optimization, physical constants
matplotlib 3.7 plotting orbits, transfers, ascent profiles
astropy 5.3 physical constants, units, time systems, coordinate frames

If you prefer to install them by hand, pip install numpy scipy matplotlib astropy does the same thing.

Jupyter (optional, recommended). Much of this material is a joy to explore interactively — tweak a mass ratio, re-run a cell, watch the plot redraw. Install JupyterLab into the same environment and launch it with:

pip install jupyterlab
jupyter lab

Every code listing in the book pastes directly into a notebook cell. (Two further tools, listed as commented lines in requirements.txt, are needed only if you want to build the book itself: jupyter-book for the Jupyter Book edition, and the separate mdBook Rust binary for the mdBook edition. Neither is needed to run the examples.)

What each library is for in this book

The four libraries were not chosen at random; each maps onto a recurring task in spaceflight engineering.

numpy — the language of vectors. Orbital mechanics is done with state vectors: a position $\mathbf{r}$ and a velocity $\mathbf{v}$, three numbers each. NumPy arrays are those vectors, and its linear algebra (np.linalg.norm, dot and cross products, matrix multiplication) is the arithmetic of Chapter 8 and the attitude rotations of Chapter 14. Nearly every other library here speaks in NumPy arrays.

scipy — the numerical engine. Three of its sub-modules recur:

  • scipy.integrate.solve_ivp is the trajectory propagator. You hand it the equation of motion — the acceleration a spacecraft feels — and a starting state, and it integrates the orbit or ascent forward in time. It is the workhorse behind the interplanetary transfer simulation in Chapter 11.
  • scipy.optimize finds the number that makes an equation true — solving Kepler's equation for the eccentric anomaly, or searching for an optimal staging split (Chapter 22).
  • scipy.constants offers standard physical constants when you want them without units attached.

matplotlib — seeing the physics. A delta-v budget is a table; an orbit is a picture. Matplotlib draws the transfer ellipses, the ascent profiles (altitude and dynamic pressure versus time from Chapter 5), and the delta-v maps that make a mission legible at a glance.

astropy — the astronomer's toolbox. Astropy carries the things that are tedious and error-prone to get right by hand: high-precision physical constants (gravitational parameters, planetary radii), units that convert themselves and catch mistakes, time systems (UTC, TAI, TDB — which differ by seconds that matter for a launch window), and coordinate frames for pointing at a real target. Its units machinery alone is worth the install: it will refuse to add kilometers to seconds, which is exactly the class of error that sanity-checks in this book are trained to catch.

Two short examples (illustrative — do not run them to trust them)

Both snippets below are complete and runnable, but their # Expected output: values were computed by hand and checked against Appendix B. They are here to show the shape of the tools, not to be trusted only after execution.

Constants and units with astropy. Here we let astropy compute Earth's gravitational parameter $\mu = GM$ from fundamental constants, then use it to find the circular speed at a 400 km altitude — the kind of number you meet constantly from Chapter 8 onward.

from astropy.constants import G, M_earth, R_earth
from astropy import units as u
import numpy as np

mu = (G * M_earth).to(u.km**3 / u.s**2)   # Earth's GM, in km^3/s^2
r = R_earth.to(u.km) + 400 * u.km         # radius of a 400 km circular orbit
v = ((mu / r) ** 0.5).to(u.km / u.s)      # circular speed, v = sqrt(mu / r)

print(f"Earth GM = {mu.value:.4g} km^3/s^2")
print(f"v(400 km) = {v.value:.2f} km/s")
# Expected output:
# Earth GM = 3.986e+05 km^3/s^2
# v(400 km) = 7.67 km/s

Notice that we never wrote a conversion factor: astropy knew that $G$ is in $\text{m}^3\text{kg}^{-1} \text{s}^{-2}$ and $M_\oplus$ in kg, multiplied the units along with the numbers, and converted the result to $\text{km}^3/\text{s}^2$ on request. The $7.67\ \text{km/s}$ it reports is the low-Earth-orbit speed tabulated in Appendix B — a good sign we set it up right.

A two-body acceleration for solve_ivp. The heart of any orbit simulation is one short function: the acceleration Newton's gravity applies to a spacecraft, $\mathbf{a} = -\mu\,\mathbf{r}/|\mathbf{r}|^3$ (the inverse-square law of Chapter 2, in vector form). We hand that function to solve_ivp, start it on a circular orbit, and integrate for one period.

import numpy as np
from scipy.integrate import solve_ivp

MU = 3.986e5  # Earth's gravitational parameter, km^3/s^2

def two_body(t, state):
    r = state[:3]                            # position vector, km
    v = state[3:]                            # velocity vector, km/s
    a = -MU * r / np.linalg.norm(r) ** 3     # gravity: a = -mu r / |r|^3
    return np.concatenate((v, a))

r0 = 6778.0                                  # 400 km circular orbit radius, km
v0 = np.sqrt(MU / r0)                        # circular speed, km/s
state0 = [r0, 0.0, 0.0, 0.0, v0, 0.0]        # start on +x axis, moving +y
period = 2 * np.pi * np.sqrt(r0**3 / MU)     # one orbit, seconds (Kepler III)

sol = solve_ivp(two_body, [0.0, period], state0, rtol=1e-9, atol=1e-9)
print(sol.success)          # did the integration converge?
print(round(period))        # one orbital period, seconds
# Expected output:
# True
# 5554

The propagator returns sol.success == True for this well-behaved orbit, and the period we asked it to integrate over — $5{,}554\ \text{s}$, about $92.6$ minutes — is the low-orbit period from Appendix B, computed here straight from Kepler's third law. After a real run, sol.y would hold the full history of position and velocity, which is precisely the array you would pass to matplotlib to draw the orbit. We print only the two quantities we can verify by hand; the trajectory itself is a picture, not a number.

The astrotools package and the # Expected output: convention

If you follow the optional "ambitious reader" track of the Design Your Mission project, you will build a small Python package called astrotools, one module at a time, as the tools you need are introduced. It is not a monolith you install; it is your package, and by the capstone it computes your whole mission.

Module First built in Role
rocket.py Ch. 3, 16, 22 the rocket equation, $I_{sp}\leftrightarrow v_e$, staging
orbits.py Ch. 6, 8, 9 vis-viva, period, circular velocity, elements ↔ state vectors
maneuvers.py Ch. 10 Hohmann transfers, plane changes, delta-v budgets
interplanetary.py Ch. 11 interplanetary Hohmann, synodic period, $C_3$
propulsion.py Ch. 16–19 thrust, exit velocity, nozzle expansion ratio
attitude.py Ch. 14 quaternions, direction-cosine matrices
power.py / thermal.py / comms.py / structures.py Ch. 23–26 array sizing, equilibrium temperature, link budget, mass budget
mission.py Ch. 29, 40 roll up the delta-v budget, size the vehicle, build the timeline

The function signatures are fixed (for example, delta_v(ve, m0, mf) in rocket.py) so that the piece you write in one chapter composes cleanly with the piece from another. Whenever a chapter adds a module, its Mission Design Checkpoint shows the code — thirty lines or fewer — with the result already in an # Expected output: comment. The complete, assembled astrotools package is reproduced in full in Appendix I, so if you skip the build-it-yourself track you can still read the finished code, or copy it whole and start experimenting.

That # Expected output: comment is the quiet contract of this book. Every one was hand-derived and sanity-checked, never produced by running the code, because a rocket scientist who cannot predict what a calculation should say has no way to notice when it lies. Reproducing those numbers on your own machine is the best possible exercise: if your run disagrees, one of you has made an interesting mistake, and tracking down which is where the real learning lives.

A note on precision and honesty: the outputs shown here are teaching values at a deliberately modest precision. Library versions, constant definitions, and integrator tolerances shift the last digit or two; none of that changes the physics. For mission-grade work you would reach past these round numbers to a current ephemeris and the full-precision constants astropy provides — exactly as Appendix B advises. The symbols and units these snippets use are cataloged in Appendix A. Now go run something, break it, and fix it. That is how rockets get built.