Zayeemk commited on
Commit
88e6738
·
verified ·
1 Parent(s): 5e36adb

Create emissions/emission_calculator

Browse files
Files changed (1) hide show
  1. emissions/emission_calculator +291 -0
emissions/emission_calculator ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GreenPath CO₂ Emission Calculator
3
+ Calculates CO₂ emissions for different transport modes using IPCC emission factors
4
+ """
5
+
6
+ import pandas as pd
7
+ from typing import Dict, List, Tuple, Optional
8
+ from dataclasses import dataclass
9
+ from enum import Enum
10
+
11
+
12
+ class TransportMode(Enum):
13
+ """Transport mode enumeration"""
14
+ ROAD_TRUCK = "road_truck"
15
+ ROAD_VAN = "road_van"
16
+ RAIL = "rail"
17
+ AIR_CARGO = "air_cargo"
18
+ SHIP_CONTAINER = "ship_container"
19
+ SHIP_BULK = "ship_bulk"
20
+
21
+
22
+ @dataclass
23
+ class EmissionFactor:
24
+ """Emission factor data structure"""
25
+ mode: TransportMode
26
+ factor_kg_co2_per_tonne_km: float
27
+ description: str
28
+ source: str
29
+
30
+
31
+ class EmissionCalculator:
32
+ """
33
+ CO₂ emission calculator for shipments
34
+ Formula: CO₂ = Distance × Weight × EmissionFactor
35
+ """
36
+
37
+ def __init__(self):
38
+ """Initialize with IPCC and government emission factors"""
39
+ self.emission_factors = self._load_emission_factors()
40
+ # Debug: Print loaded factors
41
+ print(f"Loaded emission factors: {list(self.emission_factors.keys())}")
42
+
43
+ def _load_emission_factors(self) -> Dict[TransportMode, EmissionFactor]:
44
+ """Load emission factors based on IPCC guidelines and government data"""
45
+ factors = {
46
+ TransportMode.ROAD_TRUCK: EmissionFactor(
47
+ mode=TransportMode.ROAD_TRUCK,
48
+ factor_kg_co2_per_tonne_km=0.062, # kg CO₂ per tonne-km
49
+ description="Heavy duty truck (>32 tonnes)",
50
+ source="IPCC 2019 Guidelines"
51
+ ),
52
+ TransportMode.ROAD_VAN: EmissionFactor(
53
+ mode=TransportMode.ROAD_VAN,
54
+ factor_kg_co2_per_tonne_km=0.158, # Higher per tonne due to smaller capacity
55
+ description="Light commercial vehicle (<3.5 tonnes)",
56
+ source="IPCC 2019 Guidelines"
57
+ ),
58
+ TransportMode.RAIL: EmissionFactor(
59
+ mode=TransportMode.RAIL,
60
+ factor_kg_co2_per_tonne_km=0.022, # Very efficient
61
+ description="Electric/diesel freight train",
62
+ source="IPCC 2019 Guidelines"
63
+ ),
64
+ TransportMode.AIR_CARGO: EmissionFactor(
65
+ mode=TransportMode.AIR_CARGO,
66
+ factor_kg_co2_per_tonne_km=0.602, # Highest emissions
67
+ description="Air cargo freight",
68
+ source="IPCC 2019 Guidelines"
69
+ ),
70
+ TransportMode.SHIP_CONTAINER: EmissionFactor(
71
+ mode=TransportMode.SHIP_CONTAINER,
72
+ factor_kg_co2_per_tonne_km=0.011, # Most efficient
73
+ description="Container ship",
74
+ source="IMO Fourth GHG Study 2020"
75
+ ),
76
+ TransportMode.SHIP_BULK: EmissionFactor(
77
+ mode=TransportMode.SHIP_BULK,
78
+ factor_kg_co2_per_tonne_km=0.008, # Very efficient for bulk
79
+ description="Bulk carrier ship",
80
+ source="IMO Fourth GHG Study 2020"
81
+ )
82
+ }
83
+ return factors
84
+
85
+ def calculate_emissions(
86
+ self,
87
+ distance_km: float,
88
+ weight_tonnes: float,
89
+ transport_mode: TransportMode
90
+ ) -> Dict[str, float]:
91
+ """
92
+ Calculate CO₂ emissions for a shipment
93
+
94
+ Args:
95
+ distance_km: Distance in kilometers
96
+ weight_tonnes: Weight in tonnes
97
+ transport_mode: Mode of transport
98
+
99
+ Returns:
100
+ Dictionary with emission calculations
101
+ """
102
+ if transport_mode not in self.emission_factors:
103
+ # Debug: print available keys and the requested mode
104
+ available_modes = list(self.emission_factors.keys())
105
+ print(f"Available modes: {available_modes}")
106
+ print(f"Requested mode: {transport_mode} (type: {type(transport_mode)})")
107
+ raise ValueError(
108
+ f"Unsupported transport mode: {transport_mode}. Available: {[m.value for m in available_modes]}")
109
+
110
+ factor = self.emission_factors[transport_mode]
111
+
112
+ # Core calculation: CO₂ = Distance × Weight × EmissionFactor
113
+ co2_kg = distance_km * weight_tonnes * factor.factor_kg_co2_per_tonne_km
114
+ co2_tonnes = co2_kg / 1000
115
+
116
+ return {
117
+ 'co2_emissions_kg': round(co2_kg, 3),
118
+ 'co2_emissions_tonnes': round(co2_tonnes, 6),
119
+ 'distance_km': distance_km,
120
+ 'weight_tonnes': weight_tonnes,
121
+ 'transport_mode': transport_mode.value,
122
+ 'emission_factor': factor.factor_kg_co2_per_tonne_km,
123
+ 'emission_factor_source': factor.source
124
+ }
125
+
126
+ def compare_transport_modes(
127
+ self,
128
+ distance_km: float,
129
+ weight_tonnes: float,
130
+ modes: Optional[List[TransportMode]] = None
131
+ ) -> pd.DataFrame:
132
+ """
133
+ Compare CO₂ emissions across different transport modes
134
+
135
+ Args:
136
+ distance_km: Distance in kilometers
137
+ weight_tonnes: Weight in tonnes
138
+ modes: List of transport modes to compare (default: all)
139
+
140
+ Returns:
141
+ DataFrame with comparison results
142
+ """
143
+ if modes is None:
144
+ modes = list(TransportMode)
145
+
146
+ results = []
147
+ for mode in modes:
148
+ try:
149
+ emissions = self.calculate_emissions(distance_km, weight_tonnes, mode)
150
+ results.append({
151
+ 'transport_mode': mode.value,
152
+ 'co2_emissions_kg': emissions['co2_emissions_kg'],
153
+ 'emission_factor': emissions['emission_factor'],
154
+ 'description': self.emission_factors[mode].description
155
+ })
156
+ except ValueError:
157
+ continue
158
+
159
+ df = pd.DataFrame(results)
160
+ if not df.empty:
161
+ df = df.sort_values('co2_emissions_kg')
162
+ df['emission_rank'] = range(1, len(df) + 1)
163
+ df['emission_difference_vs_best'] = df['co2_emissions_kg'] - df['co2_emissions_kg'].min()
164
+ df['emission_percentage_vs_best'] = (
165
+ (df['co2_emissions_kg'] / df['co2_emissions_kg'].min() - 1) * 100
166
+ ).round(1)
167
+
168
+ return df
169
+
170
+ def calculate_carbon_tax_cost(
171
+ self,
172
+ co2_emissions_kg: float,
173
+ carbon_tax_rate_per_tonne: float = 50.0
174
+ ) -> Dict[str, float]:
175
+ """
176
+ Calculate carbon tax cost based on emissions
177
+
178
+ Args:
179
+ co2_emissions_kg: CO₂ emissions in kg
180
+ carbon_tax_rate_per_tonne: Carbon tax rate per tonne CO₂ (default: $50)
181
+
182
+ Returns:
183
+ Dictionary with cost calculations
184
+ """
185
+ co2_tonnes = co2_emissions_kg / 1000
186
+ carbon_tax_cost = co2_tonnes * carbon_tax_rate_per_tonne
187
+
188
+ return {
189
+ 'co2_emissions_kg': co2_emissions_kg,
190
+ 'co2_emissions_tonnes': round(co2_tonnes, 6),
191
+ 'carbon_tax_rate_per_tonne': carbon_tax_rate_per_tonne,
192
+ 'carbon_tax_cost_usd': round(carbon_tax_cost, 2)
193
+ }
194
+
195
+ def get_emission_factors_table(self) -> pd.DataFrame:
196
+ """Get emission factors as a DataFrame for display"""
197
+ data = []
198
+ for mode, factor in self.emission_factors.items():
199
+ data.append({
200
+ 'transport_mode': mode.value,
201
+ 'emission_factor_kg_co2_per_tonne_km': factor.factor_kg_co2_per_tonne_km,
202
+ 'description': factor.description,
203
+ 'source': factor.source
204
+ })
205
+
206
+ return pd.DataFrame(data).sort_values('emission_factor_kg_co2_per_tonne_km')
207
+
208
+
209
+ class EmissionOptimizer:
210
+ """Optimize transport mode selection for minimum emissions"""
211
+
212
+ def __init__(self):
213
+ self.calculator = EmissionCalculator()
214
+
215
+ def find_greenest_option(
216
+ self,
217
+ distance_km: float,
218
+ weight_tonnes: float,
219
+ available_modes: List[TransportMode],
220
+ max_time_penalty_percent: float = 10.0
221
+ ) -> Dict:
222
+ """
223
+ Find the transport mode with lowest emissions within time constraints
224
+
225
+ Args:
226
+ distance_km: Distance in kilometers
227
+ weight_tonnes: Weight in tonnes
228
+ available_modes: Available transport modes
229
+ max_time_penalty_percent: Maximum acceptable time penalty for green option
230
+
231
+ Returns:
232
+ Dictionary with recommendation
233
+ """
234
+ # Typical speeds for different modes (km/h)
235
+ mode_speeds = {
236
+ TransportMode.ROAD_TRUCK: 80,
237
+ TransportMode.ROAD_VAN: 70,
238
+ TransportMode.RAIL: 50,
239
+ TransportMode.AIR_CARGO: 800,
240
+ TransportMode.SHIP_CONTAINER: 25,
241
+ TransportMode.SHIP_BULK: 20
242
+ }
243
+
244
+ options = []
245
+ for mode in available_modes:
246
+ emissions = self.calculator.calculate_emissions(distance_km, weight_tonnes, mode)
247
+ speed = mode_speeds.get(mode, 50)
248
+ travel_time_hours = distance_km / speed
249
+
250
+ options.append({
251
+ 'mode': mode,
252
+ 'co2_emissions_kg': emissions['co2_emissions_kg'],
253
+ 'travel_time_hours': travel_time_hours,
254
+ 'emission_factor': emissions['emission_factor']
255
+ })
256
+
257
+ # Sort by emissions (lowest first)
258
+ options.sort(key=lambda x: x['co2_emissions_kg'])
259
+
260
+ if not options:
261
+ return {'error': 'No available transport modes'}
262
+
263
+ greenest = options[0]
264
+ fastest = min(options, key=lambda x: x['travel_time_hours'])
265
+
266
+ # Check if greenest option meets time constraint
267
+ time_penalty = (greenest['travel_time_hours'] - fastest['travel_time_hours']) / fastest[
268
+ 'travel_time_hours'] * 100
269
+
270
+ recommendation = {
271
+ 'recommended_mode': greenest['mode'].value,
272
+ 'co2_emissions_kg': greenest['co2_emissions_kg'],
273
+ 'travel_time_hours': greenest['travel_time_hours'],
274
+ 'is_within_time_constraint': time_penalty <= max_time_penalty_percent,
275
+ 'time_penalty_percent': round(time_penalty, 1),
276
+ 'emission_savings_vs_fastest': round(
277
+ fastest['co2_emissions_kg'] - greenest['co2_emissions_kg'], 2
278
+ ),
279
+ 'emission_reduction_percent': round(
280
+ (1 - greenest['co2_emissions_kg'] / fastest['co2_emissions_kg']) * 100, 1
281
+ ) if fastest['co2_emissions_kg'] > 0 else 0,
282
+ 'all_options': [
283
+ {
284
+ 'mode': opt['mode'].value,
285
+ 'co2_emissions_kg': opt['co2_emissions_kg'],
286
+ 'travel_time_hours': round(opt['travel_time_hours'], 1)
287
+ } for opt in options
288
+ ]
289
+ }
290
+
291
+ return recommendation