Off-site Compensation

When biodiversity gains cannot be achieved on-site, compensation can be delivered at off-site locations. Off-site compensation includes an additional spatial risk multiplier that accounts for the reduced ecological benefit of delivering gains further from the impact site.

Spatial Risk Categories

The spatial risk multiplier depends on the distance between the impact site and the compensation site:

Category

Multiplier

ID

Inside LPA/NCA boundary

1.00

0

Neighbouring LPA/NCA

0.75

1

Beyond neighbouring LPA/NCA

0.50

2

Where:

  • LPA: Local Planning Authority

  • NCA: National Character Area

Off-site Creation

import pandas as pd
from bngmetric.creation import calculate_offsite_creation_bng_from_dataframe

offsite_creation = pd.DataFrame({
    'Habitat': ['Grassland - Lowland meadows', 'Wetland - Reedbeds'],
    'Condition': ['Good', 'Moderate'],
    'Area': [3.0, 2.0],
    'Strategic_Significance': [1.15, 1.0],
    'Spatial_Risk': ['Inside LPA/NCA', 'Neighbouring LPA/NCA']
})

units = calculate_offsite_creation_bng_from_dataframe(offsite_creation)
print(f"Off-site creation units: {units:.2f}")

Comparing On-site vs Off-site

from bngmetric.creation import (
    calculate_creation_bng_from_dataframe,
    calculate_offsite_creation_bng_from_dataframe
)

# Same habitat, same conditions
habitat_data = {
    'Habitat': ['Grassland - Lowland meadows'],
    'Condition': ['Good'],
    'Area': [3.0],
    'Strategic_Significance': [1.15]
}

onsite = pd.DataFrame(habitat_data)
onsite_units = calculate_creation_bng_from_dataframe(onsite)

# Off-site in neighbouring LPA
offsite = pd.DataFrame({
    **habitat_data,
    'Spatial_Risk': ['Neighbouring LPA/NCA']
})
offsite_units = calculate_offsite_creation_bng_from_dataframe(offsite)

print(f"On-site units: {onsite_units:.2f}")
print(f"Off-site units: {offsite_units:.2f}")
print(f"Reduction: {(1 - offsite_units/onsite_units)*100:.0f}%")

Off-site Enhancement

import pandas as pd
from bngmetric.enhancement import (
    calculate_offsite_enhancement_bng_from_dataframe,
    calculate_offsite_enhancement_uplift_from_dataframe
)

offsite_enhancement = pd.DataFrame({
    'Habitat': ['Grassland - Lowland meadows'],
    'Start_Condition': ['Poor'],
    'Target_Condition': ['Good'],
    'Area': [2.0],
    'Strategic_Significance': [1.15],
    'Spatial_Risk': ['Neighbouring LPA/NCA']
})

units = calculate_offsite_enhancement_bng_from_dataframe(offsite_enhancement)
uplift = calculate_offsite_enhancement_uplift_from_dataframe(offsite_enhancement)

print(f"Post-enhancement units: {units:.2f}")
print(f"Net uplift: {uplift:.2f}")

Using JAX Arrays

For programmatic access with JAX:

import jax.numpy as jnp
from bngmetric.creation import (
    calculate_batched_offsite_creation_bng_units,
    get_spatial_risk_multiplier
)
from bngmetric.constants import (
    HABITAT_TYPE_TO_ID,
    CONDITION_CATEGORY_TO_ID,
    SPATIAL_RISK_CATEGORY_TO_ID
)

habitat_ids = jnp.array([HABITAT_TYPE_TO_ID['Grassland - Lowland meadows']])
condition_ids = jnp.array([CONDITION_CATEGORY_TO_ID['Good']])
areas = jnp.array([3.0])
strategic = jnp.array([1.15])
spatial_risk = jnp.array([SPATIAL_RISK_CATEGORY_TO_ID['Neighbouring LPA/NCA']])

units = calculate_batched_offsite_creation_bng_units(
    habitat_ids, condition_ids, areas, strategic, spatial_risk
)

Intertidal Habitats

For intertidal habitats, spatial risk is based on Marine Plan Areas rather than LPA/NCA boundaries, but the multipliers are the same:

  • Inside Marine Plan Area: 1.00

  • Neighbouring Marine Plan Area: 0.75

  • Beyond neighbouring Marine Plan Area: 0.50

Use the same Spatial_Risk column values; the multipliers are identical.