Portugal, 2019, five endemic origins. Reproduced from the model’s own
inputs by LCD_mobility/worked_example_v1_v2.py, which
reimplements distanceMatrix → getsMatrix →
travelProbMat → travelRateMat →
constrain_travel_matrix in Python.
Status of the numbers. The constrained side
(A_obs, φ, the constrained pair totals) is exact: it comes
from UN Tourism and arithmetic, and needs no kernel. The kernel side is
a faithful reimplementation, not a bit-identical copy of a MATLAB run —
the reconstructed 2019 panel holds 1,667 rows (170 countries + 1,497
NUTS3) against MATLAB’s 1,634, so kernel figures should be read to two
significant figures, and the ratios rather than the last digits are the
point.
v1 carries one number per origin per year —
TravProp, total outbound trips per head, with no
destination dimension. Where those trips land is decided entirely by the
radiation kernel.
v2 carries the same TravProp
plus the observed bilateral total A_obs(O,J,y)
from UN Tourism, and rescales the kernel’s pair total onto it.
| origin | tProp (trips/head) | population | A_obs → Portugal | T_ker (kernel pair total) | φ = A_obs/T_ker |
|---|---|---|---|---|---|
| Brazil | 0.0523 | 211,782,878 | 1,298,714 | 2,967.0 | 437.7 |
| Thailand | 0.1728 | 71,307,763 | 15,683 | 184.4 | 85.0 |
| India | 0.0144 | 1,383,112,050 | 73,123 | 16,494.2 | 4.4 |
| Mexico | 0.1805 | 125,085,311 | 47,926 | 1,245.9 | 38.5 |
| Philippines | 0.0719 | 110,380,804 | 15,832 | 165.4 | 95.7 |
The first column is identical in v1 and v2. Everything to the right of it exists only in v2.
Read the last column as the size of the error the submitted model was carrying. The kernel put 2,967 Brazilians into Portugal in 2019; UN Tourism counts 1.3 million. The kernel is not wrong by a percentage, it is wrong by a factor of 438 on this pair — and by only 4.4 on India, which is the more damaging fact, because it means the error is not a constant the incidence term could absorb. It is a reallocation between origins. The radiation model has no colonial history, no language, no diaspora; Brazil→Portugal is exactly the pair it cannot see.
travelRateMat returns rates, not probabilities: r(a,b) =
tp(b)·N(b) · p(a,b), where b is the column and the
origin. Rates into Portugal’s NUTS3 regions, six largest by
population:
| NUTS3 | region | v1 (kernel) | v2 (constrained) | within-country share |
|---|---|---|---|---|
| PT170 | Área Metropolitana de Lisboa | 812.0 | 355,410 | 0.2737 |
| PT11A | Área Metropolitana do Porto | 395.8 | 173,235 | 0.1334 |
| PT150 | Algarve | 139.2 | 60,925 | 0.0469 |
| PT16E | Região de Coimbra | 124.0 | 54,282 | 0.0418 |
| PT11C | Tâmega e Sousa | 96.0 | 42,003 | 0.0323 |
| PT119 | Ave | 94.9 | 41,540 | 0.0320 |
(Brazil column. The full five-origin table is
worked_example_v1_v2_nuts3.csv.)
Every v2 entry is its v1 entry times the single scalar φ(BRA,PRT) = 437.7. The share column is therefore identical in v1 and v2, and sums to 1 in both. The constraint takes the allocation between countries away from the kernel and leaves the allocation within a country entirely to it.
Pair totals, as a check on the whole operation:
| origin | v1 kernel total | v2 constrained total | A_obs | difference |
|---|---|---|---|---|
| BRA | 2,967.006 | 1,298,714.000 | 1,298,714 | 0.0000 |
| THA | 184.433 | 15,683.000 | 15,683 | 0.0000 |
| IND | 16,494.213 | 73,123.000 | 73,123 | 0.0000 |
| MEX | 1,245.887 | 47,926.000 | 47,926 | 0.0000 |
| PHL | 165.398 | 15,832.000 | 15,832 | 0.0000 |
Binding to machine precision, by construction, on every observed pair.
travelProbMat — p(a,b) = (nᵢnⱼ)/((nᵢ+s)(nᵢ+nⱼ+s)) — is
unchanged between v1 and v2. The constraint multiplies
the rate matrix, never the probability kernel:
| NUTS3 | region | BRA | THA | IND | MEX | PHL |
|---|---|---|---|---|---|---|
| PT170 | A. M. de Lisboa | 7.333e-05 | 4.131e-06 | 2.268e-04 | 1.379e-05 | 5.773e-06 |
| PT11A | A. M. do Porto | 3.574e-05 | 2.514e-06 | 1.395e-04 | 8.529e-06 | 3.494e-06 |
| PT150 | Algarve | 1.257e-05 | 6.469e-07 | 3.500e-05 | 2.106e-06 | 8.906e-07 |
| PT16E | Região de Coimbra | 1.120e-05 | 6.338e-07 | 3.547e-05 | 2.140e-06 | 8.809e-07 |
| PT11C | Tâmega e Sousa | 8.666e-06 | 6.093e-07 | 3.410e-05 | 2.067e-06 | 8.469e-07 |
This is the sentence to give a referee: the radiation model is retained in full and unmodified; what changed is that its country-pair totals are now anchored to observed bilateral arrivals rather than left to a kernel calibrated on U.S. county commuting.
Three points worth carrying into the Methods.
LCD_mobility/worked_example_v1_v2.pyLCD_mobility/worked_example_v1_v2_summary.csv — the φ
tableLCD_mobility/worked_example_v1_v2_nuts3.csv —
per-NUTS3, all five originsLCD_mobility/worked_example_v1_v2_pmatrix.csv — the
unchanged p matrixWritten 26 August 2026.