Assignment 4#

Due: Wednesday Sep 30th at 11:59 pm ET

An extended assignment

This assignment spans two weeks and is worth double the weight of a regular assignment. Plan accordingly, commit your work incrementally, and do not leave it to the last day.

The goal of this assignment is to carry out a reproducible climate data analysis with Xarray in JupyterLab, and to do it the way a professional would: with your analysis logic written as reusable functions in a Python module, your notebook reserved for calling those functions and visualizing results, and an AI coding agent used to accelerate the harder half with your review and ownership.

You will analyze sea surface temperature (SST) to characterize the El Niño–Southern Oscillation (ENSO) signal, building on the Advanced Xarray Operations lecture.

Background: what is ENSO, and why these functions?#

The El Niño–Southern Oscillation (ENSO) is the largest source of year-to-year climate variability on Earth. Every few years the equatorial Pacific swings between a warm phase (El Niño) and a cool phase (La Niña), and because the tropical Pacific is so vast, those temperature swings reorganize rainfall, droughts, and storm tracks around the globe. Climatologists summarize the whole phenomenon with a single number: the average sea surface temperature anomaly in the Niño-3.4 region (5°S–5°N, 170°W–120°W). When that index stays above +0.5 °C for several months, it’s an El Niño event; below −0.5 °C, a La Niña.

Every function you build in this assignment is a step toward computing and interpreting that index from raw SST. By the end, you will have rebuilt, from scratch, the core of how operational centers actually monitor ENSO.

What you are practicing

  • Xarray: the data model, selection, groupby climatologies, anomalies, weighted means, rolling indices, composites, coarsen vs. interp, and trends.

  • Reproducible environments: a pixi project and a notebook anyone can rerun.

  • Software structure: analysis functions in a module, notebooks for visualization only.

  • Agentic coding: using GitHub Copilot in Agent mode, guided by an AGENTS.md.

  • Judgment & QA: tests for your functions, and catching analysis the agent gets subtly wrong.

Notebook discipline

As covered in the class, your notebook should not contain your analysis functions. Notebooks are for visualization and investigating the results. Every function you write (or the agent writes) should live in src/utils.py, and your notebook imports them and uses them to explore and plot.

All deliverables from this assignment should live in a new directory named assignment-4/ in your geog313-assignments repository. Follow the same git discipline as previous assignments: stage explicitly by name (never git add .), commit in small focused steps with clear messages, and push as you go. Read the whole assignment before you start, so you can take notes as you implement the code.


Project layout#

Your assignment-4/ directory must follow this layout:

assignment-4/
  pixi.toml            environment, dependencies, and tasks
  pixi.lock            locked versions (managed by pixi)
  .gitignore
  src/
    __init__.py        makes src an importable package
    utils.py           ALL analysis functions
  notebooks/
    analysis.ipynb     imports from src.utils; explores and plots ONLY
  tests/
    test_utils.py      tests for the functions in src/utils.py as needed
  results/             exported CSV / NetCDF / figures
  AGENTS.md            guidance for the agent
  README.md            what this is and how to reproduce it
  reflection.md        your written reflection (no AI)

Tip

Run JupyterLab from the assignment-4/ directory (pixi run jupyter lab). With src/__init__.py in place you can then write from src.utils import ... in your notebook.


Part 1: Reproducible environment (10 pts)#

  1. From the root of your geog313-assignments repository, create the project assignment-4 and initialize with pixi.

  2. Set the platforms in pixi.toml to ["osx-arm64", "osx-64", "linux-64"].

  3. Add the following packages: xarray=2026.7.*, pooch, netcdf4, matplotlib, jupyterlab

  4. Create the src/, notebooks/, tests/, and results/ structure above, add src/__init__.py, and write a README.md that says what the project does and gives the command(s) for reproduction.

  5. Commit the scaffolding.


Part 2: The core functionality (60 pts)#

Do not use the agent for this part. You are strictly prohibited to use agentic coding for this part of the assignment. Writing the core by hand is how you build the Xarray fluency you will need to judge the agent’s work in Part 2.

In src/utils.py, write and document the following pure functions, then import and use them in notebooks/analysis.ipynb:

  1. load_sst(): retrieve the NOAA ERSST v6 monthly SST file reproducibly with pooch (pinned known_hash), open it with xarray dropping time_bnds, and return the Dataset. Use the source shown in Lecture 7:

    url = "https://raw.githubusercontent.com/HamedAlemo/advanced-geo-python/main/files/noaa.ersst.v6/sst.mnmean.nc"
    
  2. subset_region(ds, lat_bounds, lon_bounds): subset Dataset ds to a range of given lat/lon.

  3. monthly_climatology(da, baseline=("1991", "2020")): calculate the mean seasonal cycle for DataArray da over a baseline period, using groupby.

  4. anomalies(da, clim): calculate monthly anomalies for DataArray da with respect to mean seasonal cycle clim

  5. area_weighted_mean(da): calculate da’s spatial mean weighted by the cosine of the latitude of the center of each pixel.

In the notebook, use these to:

  • Print a concise summary of the NOAA ERSST v6 monthly SST Dataset and the sst variable, and in 3–5 sentences explain how dims, coords, and attrs reflect the Xarray data model, and confirm the SST units / relevant CF attributes.

  • Produce two separate plots for the Niño-3.4 region (5°S–5°N, 170°W–120°W): the area-weighted monthly mean SST, and the area-weighted monthly SST anomaly time series.

Commit src/utils.py and the current version of the notebook.


Part 3: The agentic extension (80 pts)#

Now use GitHub Copilot in Agent mode, guided by an AGENTS.md you write, to add the more advanced analysis. The agent adds functions to src/utils.py; your notebook imports them and visualizes the results. Review every change before accepting it; you own this code and this science.

3.1 Write your AGENTS.md#

Before prompting the agent, write AGENTS.md. It must, at minimum, tell the agent: this is a pixi-only project; all analysis functions go in src/utils.py; the notebook is for visualization only; do not create new files or edit reflection.md; the domain rules (ERSST v6 via pooch, cosine-latitude weighting, 1991–2020 climatology baseline, units °C); run tests with pixi run test; and a definition of done. Commit it.

3.2 Functions for the agent to add#

  • rolling_index(anom_series, window=3): calculate centered rolling mean of the area-averaged anomalies (an ENSO-style index).

  • detect_events(index, threshold=0.5, min_months=3): detect contiguous warm events (index ≥ +0.5 °C for ≥ 3 consecutive months) and cold events (index ≤ −0.5 °C for ≥ 3 consecutive months); return their start/end dates and peak magnitudes.

  • composite(anom_field, event_months): build spatial composite maps by taking the mean of an anomaly field (warm or cold events) over a set of event months.

  • coarsen_to_4deg(field) and interp_to_4deg(field): create coarser (4°) anomaly maps from 2° anomalies using (coarsen(...).mean() and .interp()).

  • linear_trend(anom_field): calculate a per-pixel linear trend (°C per decade) via polyfit(dim='time', deg=1).

3.3 In the notebook, visualize and export#

  • Plot the ENSO index time series with warm/cold events marked, and export the area-averaged monthly anomaly and 3-month index to results/enso_index.csv (columns time, anomaly, rolling_anomaly). Report the top three El Niño and three La Niña events by peak magnitude with start/end dates.

  • Plot the warm and cold composite anomaly maps on the same color scale, and save them to results/composite_warm.nc and results/composite_cold.nc. Interpret the patterns in 3–4 sentences.

  • Plot the 4° coarsen vs. interp fields side-by-side for one representative month and discuss the differences.

  • Plot the trend map (°C per decade) as your headline figure, and comment on the pattern and its caveats.


Part 4: Tests and quality assurance (30 pts)#

Because your logic lives in src/utils.py, it can be tested.

  1. Add pytest to the project and define a test task so the suite runs with pixi run test.

  2. Write tests in tests/test_utils.py that check the functions on small synthetic inputs where you know the answer, for example: area_weighted_mean on a constant field returns that constant; anomalies over the baseline have (near) zero mean; coarsen_to_4deg returns the expected shape; detect_events finds a known event in a hand made series.

  3. The agent may help write tests, but verify each test is meaningful. It must actually fail if the function were wrong. Iterate until pixi run test passes.


Part 5: Reflection (20 pts)#

Write reflection.md yourself, without AI assistance (400–600 words):

  • Manual vs. agentic for data analysis: How did writing the Part 1 functions by hand compare to having the agent write the Part 2 functions? What did the agent do well, and what did you have to fix?

  • Catching bad science: Describe the incorrect or misleading analysis the agent produced and how your own understanding let you catch it. Would you have caught it if you had not written Part 1 by hand?

  • Context engineering: How did your AGENTS.md shape the agent’s behavior, and what would you tighten next time?


Deliverables#

Committed to your private geog313-assignments repository under assignment-4/, following the project layout above:

  • pixi.toml, pixi.lock, .gitignore.

  • src/utils.py with all analysis functions; src/__init__.py.

  • notebooks/analysis.ipynb: executed, with all figures rendered on GitHub, importing from src.utils and containing visualization/analysis only.

  • tests/test_utils.py; pixi run test passes.

  • results/enso_index.csv, results/composite_warm.nc, and results/composite_cold.nc.

  • AGENTS.md, README.md, and reflection.md (written without AI).

  • A commit history showing incremental, reviewed development.