Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Project 1 — Python and the Transit Model

COMP 521 | Fall 2026

Due Tuesday, September 8, 11:59 pm PT · pairs allowed, own code and own write-up · GitHub repository check due Fri Aug 28 at 11:59 pm PT


First milestone — Project 1 GitHub Repository Check

Due Friday, August 28 at 11:59 pm PT. Complete this individual, completion-only checkpoint in the same Project 1 repository you will submit on September 8. It is not a separate Project 0 and does not count in the project average.

  1. Use the Project 1 GitHub repository assigned through Classroom50 or the individual repository you will link in the Canvas Project 1 assignment. Clone that repository to your computer. If you are new to GitHub, use Git, GitHub, and Classroom50 before guessing at a command.

  2. Change the repository-check box in README.md from [ ] to [x].

  3. Commit that README change locally and push it to GitHub.

  4. Open the repository on GitHub and confirm that the commit is visible.

Your Project 1 repository contains the supplied analysis.ipynb scaffold and matching README.md. The visible setup commit records completion; no separate upload or automated readiness test is needed. The check assesses only a working GitHub path—not effort, code quality, Python setup, or progress on P1.


What you are building

What does a planet crossing a star actually look like? You will answer it from first principles — no data, no library that does it for you — and write the model the rest of this course spends thirteen weeks making real.

PartYou buildIt is right when
1luminosity(radius, teff, solar=False)it reproduces the Sun
2Theoretical HR diagram, 15 real stars on itthe Sun sits on the R=1 R⊙R=1\,R_\odot line
3flux(p, z) — the transit, four casesbranches agree at the boundaries
4transit_curve(...) — loop and vectorizedboth agree; depth =p2= p^2

Deliverable: one repository containing analysis.ipynb (that filename), both figures saved as files, and README.md.


Before you start

Read Markdown for Analysis Notebooks before drafting your first written answer. Its heading, mathematics, figure, narrative, and clean-execution conventions apply to this submission. For cloning, committing, pushing, and checking the visible result, use Git, GitHub, and Classroom50.

Constants — all CGS

QuantityValue
σ\sigma5.670374419×10−55.670374419\times10^{-5} erg cm⁻² s⁻¹ K⁻⁴
R⊙R_\odot6.957×10106.957\times10^{10} cm
L⊙L_\odot3.828×10333.828\times10^{33} erg s⁻¹
Teff,⊙T_{{\rm eff},\odot}5772 K
R⊕R_\oplus6.371×1086.371\times10^{8} cm
RJR_{\rm J}7.1492×1097.1492\times10^{9} cm

Part 1 — A function you can trust

L=4πR2σTeff4L = 4\pi R^2 \sigma T_{\rm eff}^4

Build luminosity(radius, teff, solar=False) in three passes, each working before the next. Its contract is:

  1. Compute it. Radius in cm, returns erg s⁻¹.

  2. Add solar=True — radius in R⊙R_\odot, returns L⊙L_\odot.

  3. Add validation. A non-positive radius or temperature raises ValueError with a message saying what was wrong.


Part 2 — Broadcasting, and your first figure

Build a theoretical HR diagram: LL against TeffT_{\rm eff}, with lines of constant radius. Use five lines, at R=0.01, 0.1, 1, 10, 100 R⊙R = 0.01,\ 0.1,\ 1,\ 10,\ 100\,R_\odot, over temperatures from 2,000 to 45,000 K.

Requirements:

Spectral classes

Stars are classified by the letters O B A F G K M, hottest to coolest. The boundaries are conventional rather than physical, so use these:

ClassTeffT_{\rm eff} range [K]
O30000 – 45000
B10000 – 30000
A7500 – 10000
F6000 – 7500
G5200 – 6000
K3700 – 5200
M2000 – 3700

Check that each star lands in the band its Class column claims. Sirius A is class A, so it should fall in the A band; the Sun is G and should fall in G.


Part 3 — The transit, as four cases

Star as a uniform disk (it isn’t — that’s Project 2). With p=Rp/R⋆p = R_p/R_\star and z=d/R⋆z = d/R_\star, write flux(p, z):

CaseConditionFlux
No overlapz≥1+pz \ge 1+p1
Fully on the diskz≤1−pz \le 1-p1−p21 - p^2
Planet covers the starz≤p−1z \le p-10
Partial overlap∣1−p∣<z<1+p\lvert 1-p \rvert < z < 1+pformula below
F=1−1π[ p2κ0+κ1−14(4z2−(1+z2−p2)2) ]F = 1 - \frac{1}{\pi}\left[\, p^2 \kappa_0 + \kappa_1 - \sqrt{\tfrac{1}{4}\left(4z^2 - (1+z^2-p^2)^2\right)} \,\right]
κ0=arccos⁡ ⁣(p2+z2−12pz),κ1=arccos⁡ ⁣(1−p2+z22z)\kappa_0 = \arccos\!\left(\frac{p^2+z^2-1}{2pz}\right), \qquad \kappa_1 = \arccos\!\left(\frac{1-p^2+z^2}{2z}\right)

Write three functions, not one

def kappa0(p, z): ...      # arccos((p^2 + z^2 - 1) / (2*p*z))
def kappa1(p, z): ...      # arccos((1 - p^2 + z^2) / (2*z))
def flux(p, z):   ...      # the four cases; calls kappa0 and kappa1

Each with a docstring. flux handles the case logic and calls the other two — it should not contain an arccos itself.

For this part, p is a positive finite scalar and z is a non-negative finite scalar. flux(p, z) returns one scalar normalized flux. Part 4 is where you extend the same physical model to arrays; do not quietly accept invalid scalar inputs or change their meaning.

Write the cases in flux as if/elif with the partial-overlap formula last, and note which comparison operators you used (< vs <= at each boundary). One sentence. You will need it in Part 4.


Part 4 — The light curve, twice

For a circular edge-on orbit, mid-transit at t=0t=0:

z(t)=aR⋆ ∣sin⁡ ⁣(2πtP)∣z(t) = \frac{a}{R_\star}\,\left| \sin\!\left(\frac{2\pi t}{P}\right) \right|

Write it twice, with these two names:

def transit_curve_loop(times, p, a_over_rstar, period): ...   # Version A
def transit_curve_vec(times, p, a_over_rstar, period):  ...   # Version B

Use period = 3.0 and a_over_rstar = 10 throughout. For the figure use times = np.linspace(-0.25, 0.25, 2001); for the timing comparison use 105 points.

Version B will not work the first time

Build the obvious version — compute the formula over the whole z array, then np.where to pick each case. Run it. You will get a RuntimeWarning: invalid value encountered in arccos. Your loop, running the same formula, was silent.

  1. Count the invalid calls. Apply arccos to the whole argument array and count the nan it produces — that is how many times your code asked for something undefined. Then count the nan in your final output. The two numbers will not match, and the gap is the interesting part. isnan + count_nonzero counts either in one line. Depending on how you wrote your np.where, your output may contain no nan at all — that is a legitimate result, not a failure to reproduce the bug. Say which you got and why

  2. Explain why the loop was safe and the array version is not — one sentence about what if does that an array expression does not. Your Part 3 note is the hint

  3. Fix it, and say why the fix is right rather than merely quiet

  4. There is a second hazard at exactly z=0z = 0 — mid-transit, a point you plot on purpose. Find it and say what causes it

Then confirm the two versions agree — allclose compares whole arrays at once — and time both on 105 points with %timeit. Report the speedup.

Your second figure

Light curves for p=0.05, 0.10, 0.15, 0.20, 0.25p = 0.05,\ 0.10,\ 0.15,\ 0.20,\ 0.25 on one set of axes, a/R⋆=10a/R_\star = 10. Label everything.


One last question

Add a short markdown cell at the very end, under the heading Looking back:

Which single number in this notebook do you trust least, and why?

Two or three sentences. Any honest answer earns full credit; there is no answer I am fishing for. Some of you will name the Betelgeuse radius, some the 10-17 in the depth check, some your own arccos fix.


What you turn in

Pairs are fine. You each write your own code and your own answers, and you each have to explain every line of what you submit.

References
  1. Mandel, K., & Agol, E. (2002). Analytic Light Curves for Planetary Transit Searches. The Astrophysical Journal, 580(2), L171–L175. 10.1086/345520