↑ ↓ to move · enter to open

W14 · Physics · Seasonal heating, moisture, the ITCZ

monsoons

Every year the wind over the Arabian Sea reverses. For half the year dry air blows from India out to sea, and for the other half wet air blows from the sea onto India and drops most of the country's rain. A monsoon is a sea breeze the size of a continent that turns around once a year. Three labs follow it: why the land wins the heating contest, how the wind bends as it crosses the equator, and why the rain lands on one side of the mountains.

LAB 1

land heats fast, the sea heats slow

The same sunshine falls on a patch of land and a patch of ocean at the same latitude. Land stores heat only in a thin layer, so it warms and cools within weeks. The sea mixes heat through a layer of water about deep and barely moves. When the land is warmer, air over it expands, a low forms, and the surface wind blows in from the sea. In winter the contrast flips and so does the wind. It's the W12 · Sea breeze on a yearly cycle.

south · ocean → land · north
landsealand warmer: onshore wind
Jul 15
20°N 164 ft

How to read this: the top picture is a slice from the sea (left) to India (right). The big arrow near the ground is the surface wind: blue means moist sea air blowing onto land (the rainy monsoon), amber means dry air blowing out to sea. Gold H and L mark higher and lower air pressure, and the surface wind blows from H toward L. The graph below tracks land and sea temperature over the year; the green-shaded stretches are when the land is warmer and the wind blows in from the sea.

  • moist wind from the sea
  • dry wind from the land
  • dotted loop: air rising over the warm side and returning high up

Try this: press Play year and watch the arrow flip color and direction twice a year.

—
Land temperature
—
Sea temperature
—
Surface pressure, land − sea
—
Surface wind
—
Wind turns onshore
—
Wind turns offshore

Two-box energy balancetoy model

Cland·dTL/dt = (1−α)Q(t) − (A + B·TL) − k(TL−TS)
Csea·dTS/dt = (1−α)Q(t) − (A + B·TS) + k(TL−TS)
Δpsurface = −g·ΔT/T̄ · ∫0h ρ dz

Q is the daily-mean sunshine at the chosen latitude, α = 0.33, A + B·T is outgoing infrared (A = 203.3 W/m², B = 2.09 W/m²/K, T in °C), and k = 3 W/m²/K stands in for air carrying heat between the two. Cland = 1.0×10⁷ J/m²/K, about the heat capacity of the air column itself. Csea = ρc·(mixed-layer depth), 2×10⁸ J/m²/K for .

The pressure line assumes the warm column's extra thickness has already pushed air out aloft, so pressure is level at height h and the surface pressure differs by the lost weight.

Now

Why it's a feedback

The moist air that flows in rises over the land and its vapor condenses. Condensation releases latent heat, about 2.5 million joules per kilogram of rain, right in the middle of the column. That heat deepens the low, which pulls in more moist air. The real monsoon is stronger and steadier than this dry model because of that loop. The Tibetan Plateau adds to it: it sits up and heats the middle of the atmosphere directly, so the warm layer is much deeper than over lowland.

Rain clouds also shade the ground, so real Indian temperatures peak in May, before the rains, and fall once the monsoon arrives. This model has no clouds, so its land keeps warming into summer. For the global pattern these winds sit inside, see W04 · Global circulation.

CodePython

from math import sin, cos, tan, acos, pi, radians, exp

S0, A, B, k, albedo = 1361.0, 203.3, 2.09, 3.0, 0.33
C_land = 1.0e7                    # J/m^2/K, about one air column
C_sea = 1025 * 3990 * 50          # J/m^2/K, 50 m mixed layer

def insolation(lat, day):        # daily-mean W/m^2, circular orbit
    phi = radians(lat)
    dec = radians(23.44) * sin(2*pi*(day - 80)/365)
    x = max(-1.0, min(1.0, -tan(phi)*tan(dec)))
    h0 = acos(x)                  # sunset hour angle
    return S0/pi * (h0*sin(phi)*sin(dec) + cos(phi)*cos(dec)*sin(h0))

def seasons(lat=20, years=12):   # daily steps; keep the last year
    TL = TS = 27.0
    out = []
    for y in range(years):
        for day in range(1, 366):
            if y == years - 1:
                out.append((day, TL, TS))
            q = (1 - albedo) * insolation(lat, day)
            dTL = (q - (A + B*TL) - k*(TL - TS)) / C_land
            dTS = (q - (A + B*TS) + k*(TL - TS)) / C_sea
            TL += 86400 * dTL
            TS += 86400 * dTS
    return out

def surface_dp(TL, TS, h=1500.0):  # Pa, land minus sea
    Tm = 273.15 + (TL + TS)/2
    Hs = 287*Tm/9.81              # scale height, m
    mass = 101325/(287*Tm) * Hs * (1 - exp(-h/Hs))  # kg/m^2
    return -9.81 * mass * (TL - TS) / Tm
LAB 2

the wind bends at the equator

Air flows toward the low-pressure trough where the trade winds meet, the Intertropical Convergence Zone (ITCZ). In July the trough sits over northern India, so air from the southern Indian Ocean has to cross the equator to reach it. Earth's rotation pushes moving air left in the Southern Hemisphere and right in the Northern. The southeast trade wind therefore turns into a southwest wind once it crosses, which is the wind that brings the rain.

stylized map · Indian Ocean
air north of the equatorair south of the equatorsteady wind at each latitudeITCZ / pressure trough
Jul 15
0.44 inHg

How to read this: each dot is a bit of air, and its green tail shows where it has been. Follow one across the equator (the solid line): it turns from heading northwest to heading northeast. That bend makes the southwest monsoon.

Try this: switch to Without Coriolis and the bend disappears, so the air runs straight toward the trough.

—
ITCZ latitude
—
Wind at 15°S
—
Wind at the equator
—
Wind at 15°N

Momentum with rotation and dragidealized

du/dt = f·v − r·u
dv/dt = −f·u − r·v + F(φ)
f = 2Ω sin φ, Ω = 7.292×10⁻⁵ s⁻¹, r = 1/(12 h)

F(φ) = −(1/ρ)·∂p/∂y is the push toward the trough from a pressure field p = pITCZ + Δp·(1 − e−s²), s = (y − yITCZ)/. The pressure depends only on latitude and the map's coastlines are drawn for orientation, so the model ignores mountains and coasts. Parcels are stepped every 10 minutes with a midpoint (RK2) scheme.

Now

Why the turn flips

f changes sign at the equator. South of it f is negative, so northward motion (v > 0) makes du/dt negative and the air gains an east-to-west component: a southeasterly. North of the equator f is positive and the same northward motion builds a west-to-east component: a southwesterly. At the equator itself f = 0 and the air runs straight down the pressure gradient.

In the real ocean the East African highlands squeeze the crossing into a fast low-level jet off Somalia, which this flat model can't make. In January the trough moves south of the equator and the whole picture runs backward: dry northeasterlies over India, turning northwesterly over northern Australia.

CodePython

from math import sin, exp, cos, pi, radians, degrees

OMEGA, R_E, RHO = 7.292e-5, 6.371e6, 1.15
r = 1/(12*3600)                   # linear drag, 1/s
W = 4.0e6                         # width of the trough, m

def itcz_lat(day):               # prescribed, about -10 to 25 deg
    return 7.5 - 17.5*cos(2*pi*(day - 20)/365)

def push(y, y_itcz, dp=1500.0):  # F = -(1/rho) dp/dy, m/s^2
    s = (y - y_itcz) / W
    return -(dp/RHO) * exp(-s*s) * 2*s / W

def steady_wind(lat, day, dp=1500.0, coriolis=True):
    f = 2*OMEGA*sin(radians(lat)) if coriolis else 0.0
    y, yi = radians(lat)*R_E, radians(itcz_lat(day))*R_E
    F = push(y, yi, dp)
    u = f*F / (r*r + f*f)         # east-west, m/s
    v = r*F / (r*r + f*f)         # north-south, m/s
    return u, v

def parcel(lat, u, v, day, hours=96, dt=600.0):
    y, yi = radians(lat)*R_E, radians(itcz_lat(day))*R_E
    path = []
    def rate(y, u, v):
        f = 2*OMEGA*sin(y/R_E)
        return f*v - r*u, -f*u - r*v + push(y, yi), v
    for _ in range(int(hours*3600/dt)):   # midpoint RK2
        du, dv, dy = rate(y, u, v)
        du, dv, dy = rate(y + dy*dt/2, u + du*dt/2, v + dv*dt/2)
        u, v, y = u + du*dt, v + dv*dt, y + dy*dt
        path.append((degrees(y/R_E), u, v))
    return path
LAB 3

mountains wring out the rain

When monsoon air meets a mountain range it has to climb. Rising air expands and cools, and once it reaches its condensation level the vapor turns to cloud and rain. The windward slope gets drenched. The air that comes down the far side has lost much of its water and warms as it sinks, so the land behind the range sits in a rain shadow. The Western Ghats catch the monsoon off the Arabian Sea this way, and the Himalaya wall off the Tibetan Plateau.

cross-section · wind from the left
22 mph 85%
3,937 ft

How to read this: wind blows from the left up and over the mountain. The faint lines are the paths the air takes. Once the air is pushed above the green dashed line it makes cloud and rain (blue streaks). Past the top, the air sinks and dries out. Heights are stretched so the mountain is visible. The strip below shows how hard it rains at each spot along the same slice.

  • the air's path
  • air that is raining out
  • height where clouds start
  • strip: rain rate along the slice

Try this: click Himalaya, then drop Humidity to 50% and watch the gold hump shrink.

—
Peak rain rate
—
Fastest upslope lift
—
Condensation level
—
Vapor left past the crest

Upslope condensationtoy model

w = U·dh/dx P = ε·(W/Hw)·w dW/dx = −P/U
W0 = ρv·Hw, ρv = RH·es(T)/(RvT), Hw = 2.5 km, ε = 0.5

W is the water vapor in the column (kg/m², which equals millimeters of liquid). Lifting a saturated column by a small height δ condenses about ρv·δ of it. Half of that, ε, reaches the ground and the rest drifts on as cloud. Rain starts only where the ground has lifted the air past its condensation level, 125 m per °C of dew-point depression. Surface air is held at , Rv = 461.5 J/(kg·K).

Integrating gives W after the crest = W0·exp(−ε·(H − zLCL)/Hw). The model drops rain where it forms. Real drops drift downwind and real air can flow around a ridge, so treat the numbers as an order of magnitude.

Now

CodePython

from math import exp, log

RV, H_W, EFF = 461.5, 2500.0, 0.5

def e_sat(Tc):                    # Pa, Bolton (1980)
    return 611.2 * exp(17.67*Tc/(Tc + 243.5))

def lcl(Tc, RH):                   # m, 125 m per deg C
    g = log(RH) + 17.67*Tc/(Tc + 243.5)
    Td = 243.5*g/(17.67 - g)
    return 125*(Tc - Td)

def ridge(x, H, a_wind, a_lee):   # m, two half-Gaussians
    a = a_wind if x < 0 else a_lee
    return H*exp(-(x/a)**2)

def rain_profile(U, RH, H, a_wind, a_lee, Tc=27.0, n=600):
    rho_v = RH*e_sat(Tc) / (RV*(Tc + 273.15))  # kg/m^3
    W = rho_v * H_W                         # kg/m^2 = mm
    z_lcl = lcl(Tc, RH)
    x0, x1 = -3.2*a_wind, 2.5*a_lee
    dx = (x1 - x0) / n
    out, h_prev = [], ridge(x0, H, a_wind, a_lee)
    for i in range(1, n + 1):
        x = x0 + i*dx
        h = ridge(x, H, a_wind, a_lee)
        lift = h - max(h_prev, z_lcl)       # saturated lift
        P = 0.0
        if h > h_prev and lift > 0:
            W_new = W * exp(-EFF*lift/H_W)
            P = (W - W_new) * U / dx        # kg/m^2/s
            W = W_new
        out.append((x, h, P*86400, W))     # rain in mm/day
        h_prev = h
    return out