Skip to content

laser.core.migration

laser.core.migration

This module provides various functions to calculate migration networks based on different models, including the gravity model, competing destinations model, Stouffer's model, and the radiation model.

Additionally, it includes a utility function to calculate the great-circle distance between two points on the Earth's surface using the Haversine formula.

Functions:

Name Description
gravity

np.ndarray, distances: np.ndarray, k: float, a: float, b: float, c: float, max_frac: Union[float, None]=None, kwargs) -> np.ndarray: Compute a gravity-model migration network based on origin and destination populations and pairwise distances.

row_normalizer

np.ndarray, max_rowsum: float) -> np.ndarray: Normalize the rows of a given network matrix such that no row sum exceeds a specified maximum value.

competing_destinations

np.ndarray, distances: np.ndarray, b: float, c: float, delta: float, params) -> np.ndarray: Compute a migration network using the competing-destinations model, incorporating the influence of alternative destination nodes.

stouffer

np.ndarray, distances: np.ndarray, k: float, a: float, b: float, include_home: bool, params) -> np.ndarray: Compute a migration network using a modified Stouffer's model.

radiation

np.ndarray, distances: np.ndarray, k: float, include_home: bool, params) -> np.ndarray: Compute a migration network using the radiation model, which models flows based on intervening population rather than physical distance.

distance

float, lon1: float, lat2: float, lon2: float) -> float: Calculate the great-circle distance between two points on the Earth's surface using the Haversine formula.

laser.core.migration.competing_destinations(pops, distances, k, a, b, c, delta, **params)

Calculate the competing destinations model for a given set of populations and distances. (Fotheringham AS. Spatial flows and spatial patterns. Environment and planning A. 1984;16(4):529-543)

This function computes a network matrix based on the gravity model and then adjusts it using the competing destinations model. The adjustment is done by considering the interference from other destinations.

Mathematical formula

Element-by-element: $$ network_{i,j} = k \times p_i^a \times p_j^b / distance_{i,j}^c \times \sum_k {(p_k^b / distance_{j,k}^c \text {\small for k not in [i,j]})^{delta} } $$

As-implemented numpy math:

  • Compute all terms up to the sum_k using the gravity model
  • Construct the matrix inside the sum: p**b * distances**(1-c)
  • Sum on the second axis (k), and subtract off the diagonal (j=k terms): row_sums = np.sum(competition_matrix, axis=1) - np.diag(competition_matrix)
  • Now element-by-element, subtract k=i terms off the sum, exponentiate, and multiply the original network term: network[i][j] = network[i][j] * (row_sums[i] - competition_matrix[i][j]) ** delta

Parameters:

Name Type Description Default
pops ndarray

Array of populations.

required
distances ndarray

Array of distances between locations.

required
k float

Scaling constant.

required
a float

Exponent for the population of the origin.

required
b float

Exponent parameter for populations in the gravity model.

required
c float

Exponent parameter for distances in the gravity model.

required
delta float

Exponent parameter for the competing destinations adjustment.

required
params dict

Additional parameters to be passed to the gravity model.

{}

Returns:

Name Type Description
network ndarray

Adjusted network matrix based on the competing destinations model.

laser.core.migration.distance(lat1, lon1, lat2=None, lon2=None)

Calculate the great-circle distance between two points on the Earth's surface. This function uses the Haversine formula to compute the distance between two points specified by their latitude and longitude in decimal degrees.

  • If lat2 and lon2 are not provided, they default to lat1 and lon1, respectively. This supports the default case of calculating the NxN matrix of distances between all pairs of points in (lat1, lon1).
  • If all arguments are scalars, will return a single scalar distance, (lat1, lon1) to (lat2, lon2).
  • If lat2, lon2 are vectors, will return a vector of distances, (lat1, lon1) to each lat/lon in lat2, lon2.
  • If lat1, lon1 and lat2, lon2 are vectors, will return a matrix with shape (N, M) of distances where N is the length of lat1/lon1 and M is the length of lat2/lon2.

Parameters:

Name Type Description Default
lat1 float

Latitude of the first point(s) in decimal degrees [-90, 90].

required
lon1 float

Longitude of the first point(s) in decimal degrees [-180, 180].

required
lat2 float

Latitude of the second point(s) in decimal degrees [-90, 90].

None
lon2 float

Longitude of the second point(s) in decimal degrees [-180, 180].

None

Returns:

Name Type Description
distance float

The distance between the points in kilometers.

laser.core.migration.gravity(pops, distances, k, a, b, c, **kwargs)

Calculate a gravity model network.

This function computes a gravity model network based on the provided populations and distances. The gravity model estimates migration or interaction flows between populations using a mathematical formula that incorporates scaling, population sizes, and distances.

Mathematical formula:: $$ network_{i,j} = k \cdot \frac{p_i^a \cdot p_j^b}{distance_{i,j}^c} $$

As implemented in NumPy::

1
network = k * (pops[:, np.newaxis] ** a) * (pops ** b) * (distances ** (-1 * c))

Parameters:

Name Type Description Default
pops ndarray

1D array of population sizes for each node.

required
distances ndarray

2D array of distances between nodes. Must be symmetric, with self-distances (diagonal) handled.

required
k float

Scaling constant to adjust the overall magnitude of interaction flows.

required
a float

Exponent for the population size of the origin node.

required
b float

Exponent for the population size of the destination node.

required
c float

Exponent for the distance between nodes, controlling how distance impacts flows.

required
kwargs dict

Additional keyword arguments (not used in the current implementation).

{}

Returns:

Name Type Description
network ndarray

A 2D matrix representing the interaction network, where each element network[i, j] corresponds to the flow from node i to node j.

Example usage::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import numpy as np
from gravity_model import gravity

populations = np.array([1000, 500, 200])
distances = np.array([
    [0, 2, 3],
    [2, 0, 1],
    [3, 1, 0]
])

k = 0.5
a = 1.0
b = 1.0
c = 2.0

migration_network = gravity(populations, distances, k, a, b, c)

print("Migration Network:")
print(migration_network)
Notes
  • The diagonal of the distances matrix is set to 1 internally to avoid division by zero.
  • The diagonal of the output network is set to 0 to represent no self-loops.
  • Ensure the distances matrix is symmetric and non-negative.

laser.core.migration.radiation(pops, distances, k, include_home, **params)

Calculate the migration network using the radiation model.

(Simini F, González MC, Maritan A, Barabási AL. A universal model for mobility and migration patterns. Nature. 2012;484(7392):96-100.)

Mathematical formula

Element-by-element: $$ network_{i,j} = k \times p_i^a \times (p_j / \sum_k {p_k} )^b, $$ where the sum proceeds over all \(k\) such that \(distances_{i,k} \leq distances_{i,j}\) the parameter include_home determines whether \(p_i\) is included or excluded from the sum.

As-implemented numpy math:

  • Sort each row of the distance matrix (we'll use \' below to indicate distance-sorted vectors)
  • Loop over "source nodes" i

    • Cumulative sum the sorted populations, ensuring appropriate handling when there are multiple destinations equidistant from the source
    • Subtract the source node population if include_home is False
    • Construct the row of the network matrix as $$ k \times p_i \times p_{j'} / (p_i + \sum_{k'} {p_{k'}}) / (p_i + p_{j'} + \sum_{k'} {p_{k'}}) $$
  • Unsort the rows of the network

Parameters:

Name Type Description Default
pops ndarray

Array of population sizes for each node.

required
distances ndarray

2D array of distances between nodes.

required
k float

Scaling factor for the migration rates.

required
include_home bool

Whether to include the home population in the calculations.

required
params dict

Additional parameters (currently not used).

{}

Returns:

Name Type Description
network ndarray

2D array representing the migration network.

laser.core.migration.row_normalizer(network, max_rowsum)

Normalizes the rows of a given network matrix such that no row sum exceeds a specified maximum value.

Parameters:

Name Type Description Default
network ndarray

A 2D array representing the network matrix.

required
max_rowsum float

The maximum allowable sum for any row in the network matrix.

required

Returns:

Name Type Description
network ndarray

The normalized network matrix where no row sum exceeds the specified maximum value.

laser.core.migration.stouffer(pops, distances, k, a, b, include_home, **params)

Computes a migration network using a modified Stouffer's model.

(Stouffer SA. Intervening opportunities: a theory relating mobility and distance. American sociological review. 1940;5(6):845-867)

Mathematical formula

Element-by-element: $$ network_{i,j} = k \times p_i \times p_j / ( (p_i + \sum_k {p_k}) (p_i + p_j + \sum_k {p_k}) ) $$ the parameter include_home determines whether \(p_i\) is included or excluded from the sum

As-implemented numpy math:

  • Sort each row of the distance matrix (we'll use \' below to indicate distance-sorted vectors)
  • Loop over "source nodes" i:

    • Cumulative sum the sorted populations, ensuring appropriate handling when there are multiple destinations equidistant from the source
    • Subtract the source node population if include_home is False
    • Construct the row of the network matrix as \(k \times p_i^a \times (p_{j'} / \sum_{k'} {p_{k'}})^b\)
  • Unsort the rows of the network

Parameters:

1
2
3
4
5
6
7
pops (numpy.ndarray): An array of population sizes.
distances (numpy.ndarray): A 2D array where `distances[i][j]` is the distance from location i to location j.
k (float): A scaling factor for the migration rates.
a (float): Exponent applied to the population size of the origin.
b (float): Exponent applied to the ratio of destination population to the sum of all populations at equal or lesser distances.
include_home (bool): If True, includes the home population in the cumulative sum; otherwise, excludes it.
**params: Additional parameters (not used in the current implementation).

Returns:

Name Type Description
network ndarray

A 2D array representing the migration network, where network[i][j] is the migration rate from location i to location j.