Skip to main content

coxmunk

Simple sunglint computation based on Cox & Munk model. The sunglint, sunlight reflected by the waves, induces different patterns at different spatial (or temporal) scales, as in these examples:

  • (a) sea surface under gust wind conditions (reflex digital camera);
  • (b) aerial photograph of the sea surface with visible surfactant filaments;
  • (c) Sentinel-2A image (4 July 2015) in the 2190-nm channel, where sunglint is the most intense signal over water; the glint highlights eddies, ship wakes and wave packets;
  • (d) Sentinel-3 RGB image (10 May 2016) over the eastern Mediterranean Sea, with high sunglint on the right side.

Sunglint patterns at different spatial scales

Credits: Neukermans, Harmel, Galí et al. (2018). Harnessing remote sensing to address critical science questions on ocean-atmosphere interactions. Elementa, 6, 71, doi:10.1525/elementa.331 (Fig. 11, CC BY 4.0).

For more details on the statistics of the wave slopes (i.e., Probability Distribution Function), please refer to Munk 2009.

image_output

Installation

coxmunk requires Python >= 3.9. Its dependencies (numpy, scipy, pandas, xarray, netCDF4, matplotlib, cmocean, docopt) are installed automatically by pip.

It is best installed in a virtual environment:

python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
python -m pip install --upgrade pip

or in a conda environment:

conda create -n coxmunk python=3.12
conda activate coxmunk

From PyPI

python -m pip install coxmunk

Development version from GitHub

The develop branch contains the latest changes not yet released:

python -m pip install "git+https://github.com/Tristanovsk/coxmunk.git@develop"

From source, for development

Clone the repository and install it in editable mode (code changes are picked up without reinstalling):

git clone https://github.com/Tristanovsk/coxmunk.git
cd coxmunk
python -m pip install -e .

Run the tests with:

python -m pip install pytest
python -m pytest tests

and build the documentation with:

python -m pip install -r docs/requirements.txt
make -C docs html                  # output in docs/build/html

Check the installation

The installation provides the coxmunk command:

$ coxmunk --version
coxmunk 1.2.1
$ coxmunk
Usage:
  coxmunk <sza> <wind_speed> [--stats <stats>] [--wind_azi <wind_azi>] [--shadow] [--slope] [--figname <figname>]
  coxmunk -h | --help
  coxmunk -v | --version

The model can also be used from Python:

from coxmunk import sunglint

# geometry in degrees: solar zenith, viewing zenith, relative azimuth (180° = Sun and sensor in opposition)
I, Q, U, V = sunglint(sza=30, vza=30, azi=180).sunglint(ws=5, wazi=0, stats='bh2006', shadow=True)

The full documentation, with the API reference and tutorials, is on Read the Docs.

Model description

The sea surface is described as a collection of plane facets whose slopes follow the statistics of Cox & Munk (1954). The glint observed in a given direction comes from the facets tilted so that the Sun is specularly reflected toward the sensor.

Reflecting facet

With the solar and viewing zenith angles $\theta_s$, $\theta_v$ ($\mu = \cos\theta$) and the relative azimuth $\phi$ (180° when Sun and sensor are in opposition), the scattering angle $\Theta$, the angle of incidence on the facet $\omega$ and the facet tilt $\theta_n$ are

\cos\Theta = -\mu_s\mu_v - \sin\theta_s\sin\theta_v\cos\phi, \qquad
\omega = \frac{\pi - \Theta}{2}, \qquad
\cos\theta_n = \frac{\mu_s + \mu_v}{2\cos\omega}

The facet slopes are computed in the Sun frame and rotated into the wind frame, with $\phi_w$ the downwind direction counted counterclockwise from the Sun:

z_x = -\frac{\sin\theta_v \cos\phi + \sin\theta_s}{\mu_s + \mu_v}, \quad
z_y = -\frac{\sin\theta_v \sin\phi}{\mu_s + \mu_v}, \quad
z_{up} = \cos\phi_w \, z_x + \sin\phi_w \, z_y, \quad
z_{cr} = -\sin\phi_w \, z_x + \cos\phi_w \, z_y

Wave slope statistics

For the isotropic statistics (cm_iso), with the wind speed $U$ in m/s:

\sigma^2 = 0.003 + 5.12\times10^{-3}\,U, \qquad
P = \frac{1}{\pi\sigma^2} \exp\left(-\frac{\tan^2\theta_n}{\sigma^2}\right)

For the anisotropic statistics (cm_dir, bh2006), the Gram-Charlier expansion is written with the convention of Munk (2009), with $\xi = z_{up}/\sigma_{up}$ and $\eta = z_{cr}/\sigma_{cr}$:

P(\xi, \eta) = \frac{e^{-(\xi^2 + \eta^2)/2}}{2\pi\,\sigma_{up}\,\sigma_{cr}}
\Big[ 1
+ \tfrac{c_{12}}{2}\,\xi\,(1 - \eta^2)
- \tfrac{c_{30}}{6}\,\xi\,(3 - \xi^2)
+ \tfrac{c_{40}}{24}\,(3 - 6\xi^2 + \xi^4)
+ \tfrac{c_{22}}{4}\,(1 - \xi^2)(1 - \eta^2)
+ \tfrac{c_{04}}{24}\,(3 - 6\eta^2 + \eta^4)
\Big]

where $c_{12} = -c_{21}$ and $c_{30} = -c_{03}$, with the coefficients:

Parameter cm_dir (Cox & Munk, 1954) bh2006 (Bréon & Henriot, 2006)
$\sigma_{cr}^2$ $0.003 + 1.92\times10^{-3},U$ $0.003 + 1.85\times10^{-3},U$
$\sigma_{up}^2$ $3.16\times10^{-3},U$ $0.001 + 3.16\times10^{-3},U$
$c_{21}$ $0.01 - 8.6\times10^{-3},U$ $-9\times10^{-4},U^2$
$c_{03}$ $0.04 - 0.033,U$ $-0.45 / (1 + e^{7 - U})$
$c_{40}$ 0.40 0.30
$c_{22}$ 0.12 0.12
$c_{04}$ 0.23 0.40

Fresnel reflection

With the refractive index of water $m$ (default 1.334), the reflection coefficients parallel and perpendicular to the plane of incidence are

r_l = \frac{\sqrt{m^2 - \sin^2\omega} - m^2\cos\omega}{\sqrt{m^2 - \sin^2\omega} + m^2\cos\omega},
\qquad
r_r = \frac{\cos\omega - \sqrt{m^2 - \sin^2\omega}}{\cos\omega + \sqrt{m^2 - \sin^2\omega}}

giving the Mueller reflection matrix

\mathbf{R}_F(\omega) = \frac{1}{2}
\begin{pmatrix}
r_l^2 + r_r^2 & r_l^2 - r_r^2 & 0 & 0 \\
r_l^2 - r_r^2 & r_l^2 + r_r^2 & 0 & 0 \\
0 & 0 & 2 r_l r_r & 0 \\
0 & 0 & 0 & 2 r_l r_r
\end{pmatrix}

which is rotated from the meridian planes into the scattering plane, $\mathbf{R} = \mathbf{L}(\pi - \sigma_2),\mathbf{R}_F,\mathbf{L}(-\sigma_1)$.

Shadowing and hiding

With --shadow (shadow=True in Python), the facets hidden by the waves are removed with the Smith function (Ross & Dion, 2005, 2007):

\Lambda(\theta, \varphi) = \frac{e^{-\nu^2} - \nu\sqrt{\pi}\,\mathrm{erfc}(\nu)}{2\,\nu\sqrt{\pi}},
\qquad
\nu = \frac{1}{\sqrt{2}\,\sigma(\varphi)\tan\theta},
\qquad
\sigma^2(\varphi) = \sigma_{up}^2\cos^2\varphi + \sigma_{cr}^2\sin^2\varphi
SH = \frac{1}{1 + \Lambda(\theta_s, -\phi_w) + \Lambda(\theta_v, \phi - \phi_w)}

where $\varphi$ is the azimuth of the direction relative to the upwind axis.

Sunglint Stokes vector

The sunglint, in reflectance units, is finally

\begin{pmatrix} I \\ Q \\ U \\ V \end{pmatrix}
= \frac{\pi \, P \, SH}{4 \, \mu_s \, \mu_v \cos^4\theta_n}
\begin{pmatrix} R_{11} \\ R_{21} \\ R_{31} \\ R_{41} \end{pmatrix}

References

  • Cox, C. and Munk, W. (1954). Measurement of the roughness of the sea surface from photographs of the Sun's glitter. J. Opt. Soc. Am., 44(11), 838-850.
  • Bréon, F.-M. and Henriot, N. (2006). Spaceborne observations of ocean glint reflectance and modeling of wave slope distributions. J. Geophys. Res., 111, C06005.
  • Munk, W. (2009). An inconvenient sea truth: spread, steepness, and skewness of surface slopes. Annu. Rev. Mar. Sci., 1, 377-415.
  • Ross, V., Dion, D. and Potvin, G. (2005). Detailed analytical approach to the Gaussian surface bidirectional reflectance distribution function specular component applied to the sea surface. J. Opt. Soc. Am. A, 22(11), 2442-2453.
  • Harmel, T. and Chami, M. (2012). Determination of sea surface wind speed using the polarimetric and multidirectional properties of satellite measurements in visible bands. Geophys. Res. Lett., 39, L19611, doi:10.1029/2012GL053508.
  • Harmel, T. and Chami, M. (2013). Estimation of the sunglint radiance field from optical satellite imagery over open ocean: multidirectional approach and polarization aspects. J. Geophys. Res. Oceans, 118, doi:10.1029/2012JC008221.
  • Ross, V. and Dion, D. (2007). Sea surface slope statistics derived from Sun glint radiance measurements and their apparent dependence on sensor elevation. J. Geophys. Res., 112, C09015.

Polarization and wind speed retrieval

Since the polarization of the glint only depends on the geometry while its amount depends on the sea state, multidirectional and polarized measurements (e.g., POLDER/PARASOL) can be used to retrieve the sunglint Stokes vector (Harmel & Chami, 2013) and the sea surface wind speed (Harmel & Chami, 2012). The coxmunk.wind module implements the forward model (sunglint plus whitecaps) and the Levenberg-Marquardt inversion of Harmel & Chami (2012):

import numpy as np
from coxmunk.wind import glint_whitecap, retrieve_wind_speed

# 14 viewing directions along a satellite track: (sza, vza, azi) in degrees
geometries = np.array([(30, abs(v), 150 if v >= 0 else 330) for v in np.linspace(-55, 55, 14)])
observed = glint_whitecap(geometries, ws=8)          # synthetic I, Q, U measurements
res = retrieve_wind_speed(observed, geometries)       # -> res.ws, res.sigma, res.flag

See the polarization and wind speed chapters of the documentation.

Kumatage: from noise to signal

Spooner 1822

In 1822, Spooner named Kumatage (from the Greek κυμάτων, of the waves, and αὐγή, splendour) "this remarkable appearance of light" of the Sun reflected by the waves, and established its first equations. Navigators filtered it out as a glare, painters made it a subject, Cox & Munk turned it into a measurement of the sea surface slopes, ocean color remote sensing removed it as a noise, and it is now exploited as a signal on winds, waves, currents and slicks. The History section of the documentation retraces this history (adapted from Harmel, Bary, Gernez & Morin, OCEANEXT 2019), with paintings, Cox & Munk and Sentinel-2 images.

Examples

Examples for Cox & Munk model with Bréon & Henriot statistics for:

  • solar zenith angle = 39°
  • wind azimuth from Sun = 75°
  • wind speed = 0.2, 7.2, 14.2 m.s-1
$ coxmunk 39 0.2 --stats bh2006 --wind_azi 75 --figname illustration/coxmunk_fig_39_0.2_bh2006_75.png

image_output

$ coxmunk 39 7.2 --stats bh2006 --wind_azi 75

image_output

$ coxmunk 39 14.2 --stats bh2006 --wind_azi 75

image_output

With the option --slope you can also check the values of wave slopes upwind and crosswind, the first term of the Fresnel matrix and the probability distribution function:

$ coxmunk 20 5 --stats bh2006 --wind_azi 60 --slope

image_output

Metadata

Release files for coxmunk 1.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for coxmunk 1.2.1
File Size Uploaded Provenance
coxmunk-1.2.1.tar.gz 28.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for coxmunk 1.2.1
File Interpreter ABI Platform
coxmunk-1.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 53.6 kB

Release files / coxmunk-1.2.1.tar.gz

Download URL coxmunk-1.2.1.tar.gz
Size 28.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1b45538c8e6ab376be6aa70c8bd4a26a4bbda1d0b2426d0426a9741df74c0e9c
BLAKE2b-256 checksum
How to use checksums
f1759ca9061c9efa532fae592b83c6b4cc1ff21f2b7ade6431272427de6e0368
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / coxmunk-1.2.1-py3-none-any.whl

Download URL coxmunk-1.2.1-py3-none-any.whl
Size 25.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bfd7078efb088f26d50a1d80f25a03fbdfdf3ef114b6fc4589b43f343a05437e
BLAKE2b-256 checksum
How to use checksums
6823f7546ad951358299196e5ded06a40ebe168ea9000f4498b3ffa4bdb33bef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for coxmunk 1.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for coxmunk-1.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.2.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page