Saltar al contenido principal

Transportation GFMs

Los Gap Filling Modules de Transporte calculan las emisiones de gases de efecto invernadero del transporte de productos alimentarios desde el origen hasta el destino. Estos dos módulos trabajan juntos: transportation_mode_distance_gfm calcula distancias y opciones de ruta, mientras que transportation_decision_gfm selecciona el modo de transporte óptimo y genera flujos de emisiones.

Referencia Rápida

PropiedadTransportModeDistanceGFMTransportDecisionGFM
Se ejecuta enFoodProductFlowNode, FlowNodeNodos con atributo transport
DependenciasOriginGFM, MatchProductNameGFM, UnitWeightConversionGFM, ConservationGFMTransportModeDistanceGFM
Entrada claveUbicación de origen, ubicación de destinoDistancias de transporte, perecibilidad del producto
SalidaDistancias y valores de CO2 por modo de transporteModo de transporte óptimo, nodos de flujo de acarreo
API ExternaEcoTransitNinguna

Cuándo se Ejecutan

TransportModeDistanceGFM se activa cuando:

  1. Un FoodProductFlowNode tiene una ubicación de origen válida
  2. El nodo padre tiene una ubicación de destino válida
  3. El producto no está marcado como subdivisión
  4. No se ha especificado ya un modo de transporte

TransportDecisionGFM se activa cuando:

  1. Las distancias de transporte han sido calculadas por TransportModeDistanceGFM
  2. Existe al menos una distancia de transporte válida (no cero)
  3. El nodo tiene un nodo hijo para producto pre-transportado

Salida Clave

Los módulos añaden múltiples componentes al grafo de cálculo:

  • Pre-acarreo: Transporte por carretera desde el origen al puerto/aeropuerto de salida
  • Acarreo principal: Transporte primario por modo seleccionado (carretera, mar, aire, ferrocarril)
  • Post-acarreo: Transporte por carretera desde el puerto/aeropuerto de llegada al destino
  • Refrigeración/Congelación: Emisiones adicionales para transporte con temperatura controlada
  • Infraestructura: Emisiones de infraestructura de transporte por tonelada-kilómetro

Metodología Científica

El modelo de transporte calcula emisiones usando un enfoque de acarreo de tres etapas con EcoTransit para planificación de rutas y factores de emisión.

Opciones de Modo de Transporte

ModoCódigo EcoTransitVelocidad de ViajeTiempo de CargaPrecio por kmPrecio de Carga
Carreteraroad45 km/h3 horas$0,0497/km$84,62
Marsea26 km/h48 horas$0,0062/km$119,66
Aireair500 km/h6 horas$0,0062/km$2.085,00
Ferrocarrilrail40 km/h24 horas$0,0186/km$99,58

Metodología de Cálculo de Distancias

El modelo de transporte usa un enfoque jerárquico para calcular distancias:

Integración con EcoTransit

Para cada modo de transporte, el sistema consulta EcoTransit usando la metodología CCWG-Tradelane (Clean Cargo Working Group):

ECOTRANSIT_CALCULATION_METHOD = "ccwg-tradelane"
ECOTRANSIT_CALCULATION_YEAR = 2024

Parámetros de Solicitud:

  • Coordenadas de salida (centroide de origen o ubicación precisa)
  • Coordenadas de destino (centroide de destino o ubicación precisa)
  • Modo de transporte (carretera, mar, aire, ferrocarril)
  • Peso de carga: 1 tonelada (emisiones normalizadas por tonelada)

Resolución de Ubicación con GADM

Las ubicaciones se resuelven usando GADM (Base de Datos de Áreas Administrativas Globales):

  1. GADM Nivel 1-2 (País/Región): Usa coordenadas de centroide para consultas EcoTransit
  2. GADM Nivel 3+ (Detallado): Recurre al centroide de la región padre de nivel 2
  3. Estrategia de Caché: Los resultados región-a-región se cachean; país-a-país sirve como respaldo
# Formato de clave de caché
request_key = f"{start_location_gadm_term.xid}_{end_location_gadm_term.xid}_{mode.value}"

Estimación de Distancia de Pre/Post Acarreo

Para transporte marítimo y aéreo, las distancias de pre y post acarreo (transporte por carretera hacia/desde puertos) se estiman usando:

# Para transporte en la misma región (origen y destino en la misma región GADM)
estimated_distance = ribbon_factor * direct_distance

# Para diferentes regiones
estimated_distance = max(
sqrt(region_area_km2) * scaling_factor, # Estimación basada en área
distance_from_centroid_to_port # Estimación basada en centroide
) * ribbon_factor

Factores de Escala por Modo de Transporte:

ModoFactor de Escala Pre/Post AcarreoDescripción
Mar0,29042sqrt(área)/2,43
Aire0,11782sqrt(área)/5,99
Carretera (misma región)0,56905Para transporte local

Factor de Cinta (Índice de Desvío):

El factor de cinta de 1,417 convierte distancias en línea recta a distancias de carretera realistas, basado en investigación de Ballou et al. (2002).

Cálculo de Emisiones de CO2

Las emisiones de CO2 se extraen directamente de las respuestas de EcoTransit en toneladas de CO2eq por tonelada de carga:

# Para cada segmento de acarreo
co2_value = section["emissions"]["co2Equivalents"][mode]["_value_1"]
distance = section["emissions"]["distances"][mode]["tankToWheel"]

# El CO2 de pre/post acarreo se escala según la distancia estimada
scaled_co2 = ecotransit_co2 * (estimated_distance / ecotransit_distance)

Selección de Modo de Transporte

El TransportDecisionGFM selecciona el modo óptimo mediante:

  1. Filtrar por Perecibilidad: Excluir modos donde el tiempo de viaje excede el tiempo de almacenamiento del producto
  2. Calcular Coste Total: Sumar costes de distancia y costes de carga para cada modo
  3. Seleccionar el Más Barato: Elegir el modo con el coste total más bajo
# Cálculo del tiempo total de viaje
travel_time = distance / travel_speed + loading_time

# Cálculo del coste total
total_cost = (distance_price * distance) + loading_price

Restricciones de Perecibilidad

Los productos con restricciones de tiempo de almacenamiento (refrigerados, congelados) se filtran a modos que pueden entregar dentro de la ventana de almacenamiento:

# Comprobar si el modo califica
storage_time_hours = product.storage_time * time_conversion_factor
if travel_time < storage_time_hours:
qualifying_modes.append(mode)

Si ningún modo califica dentro de la restricción de almacenamiento, se selecciona el modo más rápido como respaldo.


Detalles de Implementación

Distancias de Transporte por Defecto

Cuando el origen no puede determinarse (código FAO de producción desconocido), se usan distancias por defecto basadas en Argentina a Alemania vía Portugal:

AcarreoDistancia (km)CO2 (t/t)
Pre-acarreo (centroide de Argentina a puerto)666,020,0952
Acarreo principal (puerto de Argentina a puerto de Portugal)11.428,680,1202
Post-acarreo (puerto de Portugal a centroide de Alemania)2.569,740,1908
Total14.664,440,4062

Manejo de Productos No Alimentarios

Los productos no alimentarios (identificados por términos FoodEx2 EAT-0002 y EAT-0000) se excluyen de los cálculos de transporte.

Transporte en la Misma Ubicación

Cuando el origen y destino son la misma región GADM:

  1. Aplicar un desplazamiento de 50km a las coordenadas de origen y destino
  2. Forzar modo de transporte por carretera
  3. Calcular distancia usando el factor de cinta
if start_location_gadm_term == end_location_gadm_term:
start_location = add_offset_to_endpoint(start_lon, start_lat, -50_000)
end_location = add_offset_to_endpoint(end_lon, end_lat, 50_000)
pre_defined_mode = ServiceTransportModeEnum.GROUND

Mutaciones del Grafo

El TransportDecisionGFM crea la siguiente estructura de grafo:

FoodProductFlowNode (ingrediente)
|
+-- FoodProcessingActivityNode (actividad de transporte)
|
+-- FoodProductFlowNode (producto pre-transportado)
| |
| +-- [nodos hijos originales]
|
+-- PracticeFlowNode (Pre-acarreo)
| +-- TransportActivityNode
| +-- FlowNode (Consumo de combustible)
| +-- PracticeFlowNode (Infraestructura)
|
+-- PracticeFlowNode (Acarreo principal)
| +-- TransportActivityNode
| +-- FlowNode (Consumo de combustible)
| +-- PracticeFlowNode (Infraestructura)
|
+-- PracticeFlowNode (Post-acarreo)
| +-- TransportActivityNode
| +-- FlowNode (Consumo de combustible)
| +-- PracticeFlowNode (Infraestructura)
|
+-- PracticeFlowNode (Refrigeración/Congelación) [opcional]

Refrigeración y Congelación Durante el Transporte

Para productos etiquetados como refrigerados (J0131) o congelados (J0136), se añaden emisiones adicionales de refrigeración:

# Calcular tiempo de viaje para el modo seleccionado
travel_time_hours = total_distance / travel_speed + loading_time

# Crear nodo de flujo de refrigeración/congelación con cantidad en kg*hora
cooling_flow_node.amount = travel_time_hours # en unidad kg*hora

Referencia Completa del Código

Estructura de Solicitud EcoTransit

complex_transport_request = {
"cargo": Cargo(weight=1, unit="ton"),
"transportDate": None, # Fechas omitidas para evitar variaciones temporales
"accountingVariant": AccountingVariantParameters(
variant="ccwg-tradelane",
year=2024,
),
"section": {
"route": {
"departure": RequestStation(
wgs84=Wgs84Coordinates(departure_longitude, departure_latitude)
),
"destination": RequestStation(
wgs84=Wgs84Coordinates(destination_longitude, destination_latitude)
),
},
"carriage": {
"preCarriage": PreOrPostCarriageParameters(road=RoadParameters()),
"mainCarriage": CarriageParameters(mode_params),
"postCarriage": PreOrPostCarriageParameters(road=RoadParameters()),
},
},
"output": Output(split=OutputSplit(), createKml=False),
}

Procesamiento de Respuesta

La respuesta de EcoTransit se reduce a datos esenciales para el cacheo:

def strip_ecotransit_response(mode: str, response: dict) -> dict:
return {
"mainhaul": {
mode: [
{
"co2eq_value": section["emissions"]["co2Equivalents"][mode]["_value_1"],
"distance": section["emissions"]["distances"][mode]["tankToWheel"],
}
for section in mainhaul_sections
]
},
"mainhaul_start_location": response["mainhaul"][0]["route"]["startLocation"]["wgs84"],
"mainhaul_end_location": response["mainhaul"][-1]["route"]["endLocation"]["wgs84"],
"preCarriage": {ServiceTransportModeEnum.GROUND: [...]},
"postCarriage": {ServiceTransportModeEnum.GROUND: [...]},
}

Cálculo de Costes

async def get_minimal_cost_transportation_mode(
transport_modes_distances: TransportModesDistancesProp,
qualified_travel_modes: list,
) -> ServiceTransportModeEnum:
mile_to_km_constant = 0.621371192

# Precios por milla convertidos a km
distance_prices = {
ServiceTransportModeEnum.AIR: 0.01 * mile_to_km_constant,
ServiceTransportModeEnum.GROUND: 0.08 * mile_to_km_constant,
ServiceTransportModeEnum.SEA: 0.01 * mile_to_km_constant,
ServiceTransportModeEnum.TRAIN: 0.03 * mile_to_km_constant,
}
loading_prices = {
ServiceTransportModeEnum.AIR: 2085.0,
ServiceTransportModeEnum.GROUND: 84.62,
ServiceTransportModeEnum.SEA: 119.6646,
ServiceTransportModeEnum.TRAIN: 99.578,
}

total_prices = {}
for mode in qualified_travel_modes:
total_price = 0

# Añadir costes de pre/post acarreo (siempre carretera)
for carriage in ("pre_carriage", "post_carriage"):
if getattr(distances[mode], carriage).value > 0:
total_price += (
distance_prices[ServiceTransportModeEnum.GROUND]
* getattr(distances[mode], carriage).value
+ loading_prices[ServiceTransportModeEnum.GROUND]
)

# Añadir coste del acarreo principal
total_price += (
distance_prices[mode] * distances[mode].main_carriage.value
+ loading_prices[mode]
)
total_prices[mode] = total_price

return min(total_prices, key=total_prices.get)

Cálculo del Tiempo de Viaje

@staticmethod
def get_travel_time(distance: float, mode: str) -> float:
travel_speed = { # km/h
ServiceTransportModeEnum.AIR: 500,
ServiceTransportModeEnum.GROUND: 45,
ServiceTransportModeEnum.SEA: 26,
ServiceTransportModeEnum.TRAIN: 40,
}
travel_loading_time = { # horas
ServiceTransportModeEnum.AIR: 6,
ServiceTransportModeEnum.GROUND: 3,
ServiceTransportModeEnum.SEA: 48,
ServiceTransportModeEnum.TRAIN: 24,
}

return distance / travel_speed[mode] + travel_loading_time[mode]

Fuentes de Datos

API de EcoTransit

EcoTransit World proporciona cálculos de emisiones de transporte de mercancías:

  • Metodología: Marco GLEC (Global Logistics Emissions Council)
  • Variante de cálculo: CCWG-Tradelane (Clean Cargo Working Group)
  • Cobertura: Rutas globales de mercancías para carretera, ferrocarril, mar y aire
  • Año de datos: 2024 (configurable)

La metodología CCWG añade un factor de corrección del 15% a las distancias marítimas, ya que la distancia de ruta más corta típicamente subestima las distancias reales recorridas.

Base de Datos Geográfica GADM

GADM proporciona límites geográficos y centroides:

  • Centroides de países para nivel 1
  • Centroides regionales para nivel 2
  • Respaldo del nivel 3+ al padre de nivel 2

Códigos FAO para Casos Especiales

Código FAODescripciónComportamiento de Transporte
100000Producción localSin emisiones de transporte
200000Producción por defectoSe usan distancias por defecto
300000Producción de pescado desconocidaSe usan distancias por defecto
400000Coincidencia de producción fallidaSe usan distancias por defecto

Ejemplo de Cálculo

Escenario: 1 kg de naranjas de España (Valencia) a Suiza (Zúrich)

Paso 1: Resolver Ubicaciones

  • Origen: España, región de Valencia (GADM: ES.17_1)
    • Centroide: -0,4, 39,5
  • Destino: Suiza, Zúrich (GADM: CH.26_1)
    • Centroide: 8,5, 47,4

Paso 2: Consultar EcoTransit

Consultas realizadas para modos de carretera, mar y aire:

Respuesta de Carretera:

{
"mainhaul": {
"road": [
{"distance": 1284.3, "co2eq_value": 0.1156}
]
}
}

Respuesta de Mar:

{
"mainhaul": {
"sea": [
{"distance": 2156.7, "co2eq_value": 0.0345}
]
},
"preCarriage": {"road": [{"distance": 312.4, "co2eq_value": 0.0281}]},
"postCarriage": {"road": [{"distance": 428.6, "co2eq_value": 0.0386}]}
}

Paso 3: Calcular Opciones de Transporte

ModoPre-acarreoAcarreo principalPost-acarreoDistancia TotalCO2 Total
Carretera0 km1.284,3 km0 km1.284,3 km0,1156 t
Mar312,4 km2.156,7 km428,6 km2.897,7 km0,1012 t

Paso 4: Calcular Costes

Carretera:

Coste = (1284,3 * 0,0497) + 84,62 = $148,45

Mar:

Pre-acarreo: (312,4 * 0,0497) + 84,62 = $100,14
Acarreo principal: (2156,7 * 0,0062) + 119,66 = $133,03
Post-acarreo: (428,6 * 0,0497) + 84,62 = $105,92
Total: $339,09

Paso 5: Seleccionar Modo

Se selecciona carretera como la opción viable más barata ($148,45 vs $339,09).

Paso 6: Crear Nodos del Grafo

  1. Nodo de actividad de transporte creado
  2. Nodo de flujo de acarreo principal: 1.284,3 km transporte por carretera
  3. Nodo de consumo de combustible: 0,1156 t CO2eq
  4. Nodo de infraestructura: 1,0 tonelada-km

Salida Final

El módulo añade emisiones de 0,1156 kg CO2eq por kg de naranjas para transporte.


Estrategia de Cacheo

Niveles de Caché

  1. Caché región-a-región: Respuestas completas de EcoTransit cacheadas por pares de términos GADM
  2. Respaldo país-a-país: Usado cuando falla el caché de región
  3. Caché de respuesta reducida: Datos mínimos para búsquedas rápidas (cargados al arrancar)
# Caché de respuesta completa (no se carga al arrancar)
await cache.set(request_key, response_data, load_on_boot=False)

# Caché de respuesta reducida (se carga al arrancar)
await cache.set(request_key + "_stripped", stripped_data, load_on_boot=True)

Cálculo en Segundo Plano

Cuando hay un fallo de caché:

  1. Se inicia tarea en segundo plano para cálculo región-a-región
  2. Comprobar si hay coincidencia en caché país-a-país
  3. Usar respaldo de país si está disponible, de lo contrario esperar cálculo de región
# Iniciar cálculo en segundo plano
region_calc_task = asyncio.create_task(
get_transport_mode_responses_cached(origin, destination, mode, cache_only=False)
)

# Comprobar respaldo de país
country_result = await get_transport_mode_responses_cached(
origin_country, destination_country, mode, cache_only=True
)

Limitaciones Conocidas

Cobertura Geográfica

  • Depende de la cobertura de la base de datos de rutas de EcoTransit
  • Algunas ubicaciones remotas pueden no tener rutas válidas
  • Las rutas marítimas requieren conexiones de puerto válidas

Cobertura de Modos

  • Ferrocarril: Actualmente funcional pero menos priorizado en el modelo de costes
  • Vías navegables interiores: Disponible en EcoTransit pero aún no implementado
  • Ferry: Manejado como transporte por carretera (sin distinción)

Suposiciones del Modelo

  • Fecha de transporte no especificada para evitar variaciones temporales en factores de emisión
  • Factor de carga asumido al 60% (por defecto de EcoTransit)
  • Todo pre/post acarreo asumido como transporte por carretera
  • Misma mezcla de infraestructura usada globalmente

Restricciones de Perecibilidad

  • Solo aplica cuando la etiqueta de tiempo de almacenamiento está presente en el producto
  • El modo más rápido se selecciona como respaldo cuando ningún modo cumple las restricciones
  • Puede resultar en transporte aéreo para artículos altamente perecederos

Actualización de Datos

  • Los factores de emisión de EcoTransit se actualizan anualmente
  • Los límites de GADM pueden no reflejar cambios administrativos recientes
  • Los precios de transporte en el modelo de costes pueden no reflejar las tarifas actuales del mercado

Referencias

  1. EcoTransit World. Environmental methodology and data update. https://www.ecotransit.org/

  2. Smart Freight Centre (2019). Global Logistics Emissions Council Framework for Logistics Emissions Accounting and Reporting. https://www.smartfreightcentre.org/en/our-programs/global-logistics-emissions-council/

  3. Clean Cargo Working Group. Container shipping methodology for calculating emissions. https://www.smartfreightcentre.org/en/our-programs/clean-cargo-1/

  4. Ballou, R.H., Rahardja, H., & Sakai, N. (2002). Selected country circuity factors for road travel distance estimation. Transportation Research Part A, 36(9), 843-848.

  5. GADM Database. Global Administrative Areas. https://gadm.org/

  6. FAO. Food and Agriculture Organization trade statistics. https://www.fao.org/faostat/