|
fitpack
Modern Fortran library for curve and surface fitting with splines
|
This tutorial covers bivariate spline fitting on the unit sphere with FITPACK: constructing a bicubic spline \( r = s(\theta, \phi) \) from data in spherical coordinates, handling pole singularities, and evaluating the fitted surface.
Many physical problems produce data on the surface of a sphere — geophysical fields, satellite measurements, radiation patterns, or angular distributions. FITPACK provides two sphere-specific types, selected by input data structure:
| Type | Input | Core routine | Use case |
|---|---|---|---|
fitpack_sphere | Scattered \( (\theta_i, \phi_i, r_i) \) | sphere | Irregularly sampled observations |
fitpack_grid_sphere | Grid \( z(v_j, u_i) \) | spgrid | Latitude-longitude grids |
Always prefer fitpack_grid_sphere when data lies on a regular latitude-longitude grid — the spgrid algorithm exploits the grid structure and is significantly more efficient.
Points on the unit sphere are parameterized by colatitude \( \theta \in [0, \pi] \) (measured from the north pole) and longitude \( \phi \in [0, 2\pi) \). The Cartesian embedding is:
\[ x = \sin\theta \cos\phi, \quad y = \sin\theta \sin\phi, \quad z = \cos\theta \]
At the north pole ( \( \theta = 0 \)) and south pole ( \( \theta = \pi \)), all values of \( \phi \) correspond to the same geometric point. A naive tensor-product spline in \( (\theta, \phi) \) would not enforce this single-valuedness. FITPACK's sphere routines automatically impose pole constraints so that the fitted spline is smooth and well-defined at both poles.
The real spherical harmonics \( Y_l^m(\theta, \phi) \) form a natural basis for functions on the sphere. The first few are:
\[ Y_0^0 = 1, \quad Y_1^0 = \cos\theta, \quad Y_2^2 = \sin^2\!\theta \cos 2\phi \]
A smooth test function built from these harmonics provides a useful validation target, since the spline should reproduce low-order harmonics to high accuracy with only a moderate number of knots.
fitpack_sphereUse fitpack_sphere when data points are irregularly distributed over the sphere.
The new_fit method stores the data, allocates workspace, and performs a smoothing fit in one call. The smoothing parameter \( s \) controls the trade-off between fidelity and smoothness. A practical starting value is \( s = m \) (the number of data points).
The eval method returns values on a tensor-product grid:
After fitting, the knot counts are available from sph\knots:
The residual (weighted sum of squared errors) is returned by sph\mse().
The following test function combines three harmonics:
\[ f(\theta, \phi) = Y_0^0 + Y_1^0 + \frac{1}{2}\, Y_2^2 = 1 + \cos\theta + \frac{1}{2}\sin^2\!\theta\,\cos 2\phi \]
Tightening the smoothing parameter increases the number of knots and reduces the residual, allowing the spline to capture finer angular structure.
fitpack_grid_sphereUse fitpack_grid_sphere when data is sampled on a regular colatitude-longitude grid — the typical case for reanalysis products, climate model output, or any field stored on a lat-lon mesh.
Note the array layout: zg has shape (size(v), size(u)), with the longitude index first. The colatitude grid must satisfy \( 0 < u_1 < \cdots < u_{n_u} < \pi \) (strictly interior — the poles are not grid points). The longitude grid must satisfy \( 0 \leq v_1 < v_2 < \cdots < v_{n_v} < 2\pi \).
Because the grid excludes the poles, FITPACK allows you to supply pole values and control the smoothness there:
| Argument | Type | Effect |
|---|---|---|
z0 | real(FP_REAL) | Prescribe the function value at the pole |
exact | logical | .true.: spline passes exactly through z0; .false.: treated as data |
differentiable | logical | .true.: enforce \( C^1 \) continuity at the pole |
zero_grad | logical | .true.: enforce \( \nabla s = 0 \) at the pole |
When z0 is omitted, no function-value constraint is imposed at that pole.
A full working program demonstrating both scattered fitting with progressive refinement and gridded fitting with pole boundary conditions is provided in examples/example_sphere.f90. Build and run it with: