commit 75ea1d1d52247755eafe6cc791ec2727655a101b
parent 5603b487228061a85a837c3fb2b503f84dd8f554
Author: Antoine Amarilli <a3nm@a3nm.net>
Date: Fri, 8 Nov 2024 12:31:03 +0100
2023 scripts by León Bohn
Diffstat:
9 files changed, 513 insertions(+), 0 deletions(-)
diff --git a/2023/.gitignore b/2023/.gitignore
@@ -0,0 +1,5 @@
+trips
+trips_with_footprint
+trips_with_dist
+map.geojson
+registrations*.csv
diff --git a/2023/LICENSE b/2023/LICENSE
@@ -0,0 +1,18 @@
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/2023/README.md b/2023/README.md
@@ -0,0 +1,3 @@
+This code computed the carbon footprint of the Highlights'23 conference. It was
+written by León Bohn.
+
diff --git a/2023/addnoise.py b/2023/addnoise.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+import sys
+from random import uniform
+
+noise = float(sys.argv[1])
+
+for l in sys.stdin.readlines():
+ f = l.strip().split(',')
+ mode = f[0]
+ dist = float(f[3])
+ dist_anon = round(uniform(dist * (1-noise), dist * (1+noise)))
+ print(','.join((mode, str(dist_anon))))
+
diff --git a/2023/co2.py b/2023/co2.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+
+# output: two fields, distance, inferred mode, CO2e emission in kg
+# also output a map (map.geojson)
+
+import json
+
+import sys
+from collections import defaultdict
+
+places = defaultdict(lambda: (0, 0, None))
+
+n_trips = 0
+total_dist = 0
+total_co2 = 0
+trips_by_type = defaultdict(lambda : 0)
+dist_by_type = defaultdict(lambda : 0)
+co2_by_type = defaultdict(lambda : 0)
+
+
+for l in sys.stdin.readlines():
+ f = l.strip().split(',')
+ mode = f[0]
+ lat = f[1]
+ lon = f[2]
+
+ distance = float(f[3])
+
+ if mode.strip() not in ['plane', 'train', 'bus/coach', 'car']:
+ if distance > 400000:
+ mode = "plane"
+ trips_by_type['plane_assumed'] += 1
+ else:
+ mode = "train"
+ trips_by_type['train_assumed'] += 1
+ else:
+ trips_by_type[mode] += 1
+
+ k = (lat,lon)
+ plane = mode == "plane"
+ places[k] = (places[k][0] + (1 if plane else 0), places[k][1] + 1)
+
+ dist_by_type[mode] += distance
+ n_trips += 1
+ total_dist += distance
+ g_km_person = None
+ if mode == "train":
+ g_km_person = 37
+ if mode == "bus/coach":
+ g_km_person = 28
+ if mode == "car":
+ g_km_person = 192
+ if mode == "plane":
+ if distance <= 1000000:
+ g_km_person = 258
+ elif 1000000 < distance <= 3500000:
+ g_km_person = 187
+ elif 3500000 < distance:
+ g_km_person = 152
+ co2 = (g_km_person * (distance / 1000.))/1000.
+ co2_by_type[mode] += co2
+ total_co2 += co2
+ print (','.join([str(distance), mode, str(co2)]))
+
+
+## OUTPUT GEOJSON
+
+features = []
+for k in places.keys():
+ red = int(255.*places[k][0]/places[k][1])
+ green = 0
+ blue = int(255.*(places[k][1]-places[k][0])/places[k][1])
+ color = '#%02X%02X%02X' % (red, green, blue)
+ feature = {
+ "type": "Feature",
+ "properties": {
+ #"name":places[k][2],
+ "_umap_options": {"color": color}
+ },
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ k[1], k[0]
+ ]
+ }
+ }
+ features.append(feature)
+
+output = {
+ "type": "FeatureCollection",
+ "features": features
+}
+
+with open("map.geojson", 'w') as f:
+ print (json.dumps(output), file=f)
+
+print("%d total trips" % n_trips, file=sys.stderr)
+print("%d total distance" % total_dist, file=sys.stderr)
+print("%f total CO2" % total_co2, file=sys.stderr)
+for k in trips_by_type:
+ print("%d trips by %s" % (trips_by_type[k], k), file=sys.stderr)
+for k in dist_by_type:
+ print("%d distance by %s" % (dist_by_type[k], k), file=sys.stderr)
+for k in co2_by_type:
+ print("%f kgCO2e by %s" % (co2_by_type[k], k), file=sys.stderr)
+
diff --git a/2023/compute_trips.py b/2023/compute_trips.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+import csv
+import sys
+import math
+from geopy.geocoders import Nominatim
+from functools import cache
+
+# Define carbon emissions data for each mode of transportation (in gCO2e per passenger-kilometer)
+emissions_data = {
+ "train": 41,
+ "plane": 160,
+ "bike": 0,
+ "bus": 105,
+ "car": 192,
+ "car_shared": 0
+}
+
+if len(sys.argv) != 4:
+ print("Usage: python script.py <input_csv_file> <country> <city>")
+ sys.exit(1)
+
+geolocator = Nominatim(user_agent='Highlights Conference 2023')
+
+@cache
+def get_lat_lon(country, city):
+ location = geolocator.geocode(country + ", " + city)
+ if location is None:
+ print(f"got None response for {country} and {city}")
+ return location.latitude, location.longitude
+
+target_lat, target_lon = get_lat_lon(sys.argv[2], sys.argv[3])
+
+def haversine_distance(lat1, lon1, lat2, lon2):
+ # Convert latitude and longitude from degrees to radians
+ lat1 = math.radians(lat1)
+ lon1 = math.radians(lon1)
+ lat2 = math.radians(lat2)
+ lon2 = math.radians(lon2)
+
+ # Radius of the Earth in kilometers (mean value)
+ earth_radius = 6371.0 # km
+
+ # Haversine formula
+ dlon = lon2 - lon1
+ dlat = lat2 - lat1
+ a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
+ c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
+ distance = earth_radius * c
+
+ return distance
+
+def estimate_distance(country, city):
+ lat, lon = get_lat_lon(country, city)
+ return haversine_distance(lat, lon, target_lat, target_lon)
+
+
+total_carbon_footprint = 0
+total_carbon_footprint2 = 0
+# Available fields are
+# timestamp,firstname,lastname,email,affiliation,no_zulip,level,presenting,extra,physical,hcrw,country,city,mode
+with open(sys.argv[1], 'r') as csv_file:
+ reader = csv.DictReader(csv_file)
+ for row in reader:
+ if row['physical'] == "true" and emissions_data.get(row['mode']) is not None:
+ # Calculate the carbon footprint for the round trip
+ mode = None
+ match row['mode']:
+ case "car":
+ mode = "car"
+ case "train":
+ mode = "train"
+ case "bus":
+ mode = "bus"
+ case "plane":
+ mode = "plane"
+ case _:
+ mode = "none"
+
+ lat, lon = get_lat_lon(row['country'], row['city'])
+ distance = haversine_distance(lat, lon, target_lat, target_lon)
+ if distance != 0 and mode != "none":
+ print(f"{mode}, {lat}, {lon}, {distance*1000}")
+ print(f"{mode}, {lat}, {lon}, {distance*1000}")
+
+
diff --git a/2023/run.sh b/2023/run.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+FILE="$1"
+COUNTRY="$2"
+CITY="$3"
+NOISE="$4"
+
+>&2 echo "computing trips"
+./compute_trips.py "$FILE" "$COUNTRY" "$CITY" > trips_with_dist
+>&2 echo "adding noise"
+./addnoise.py "$NOISE" < trips_with_dist | sort -t',' -k2,2n |
+ cat <(echo 'mode,distance in meters') - > trips_anonymized.csv
+python3 co2.py < trips_with_dist > trips_with_footprint
+
diff --git a/2023/transform.py b/2023/transform.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import json
+import sys
+
+year = int(sys.argv[1])
+people = int(sys.argv[2])
+total = int(sys.argv[3])
+location = sys.argv[4]
+
+trips = []
+for l in sys.stdin.readlines():
+ f = l.strip().split(',')
+ mode = f[0]
+ dist = f[1]
+ trip = {
+ "mode": mode,
+ "dist": int(dist)
+ }
+ trips.append(trip)
+
+edition_data = {
+ "year": year,
+ "location": location,
+ "participants": people,
+ "emissions": total,
+ "trips": trips
+}
+
+print(json.dumps(edition_data))+
\ No newline at end of file
diff --git a/2023/trips_anonymized.csv b/2023/trips_anonymized.csv
@@ -0,0 +1,234 @@
+train,40442
+train,45579
+train,68361
+train,71473
+train,79562
+train,80487
+train,84153
+train,84310
+train,134654
+car,137170
+car,143119
+train,143277
+train,143980
+car,145419
+car,145424
+train,148908
+train,150953
+train,152292
+train,153107
+train,159332
+train,161652
+train,162322
+train,171985
+train,172383
+train,190030
+train,195807
+train,197601
+train,202542
+train,220599
+train,220740
+train,221664
+train,222744
+train,223906
+train,232625
+train,233717
+train,234301
+train,237533
+train,239465
+train,240026
+train,241647
+train,244242
+car,244414
+train,244432
+train,246899
+train,250056
+train,251657
+train,251964
+car,252797
+train,254312
+train,254766
+train,254973
+train,258107
+train,260730
+train,261788
+train,261919
+train,262756
+train,262903
+train,263013
+train,263325
+train,263877
+train,268639
+train,275892
+train,278298
+train,285034
+train,286962
+train,296400
+train,302812
+train,303821
+train,311182
+train,316972
+train,318624
+train,323317
+train,332718
+plane,337316
+plane,342487
+train,343262
+train,344396
+train,352986
+train,353783
+train,361156
+train,361919
+train,367915
+train,374289
+train,379405
+train,384594
+train,385807
+train,386876
+train,388557
+train,392017
+train,396339
+train,398152
+train,400144
+train,402171
+train,404400
+train,405291
+train,415104
+train,416829
+train,417423
+train,428333
+train,433436
+train,461498
+car,469781
+train,485684
+car,501208
+train,521055
+train,526773
+train,528867
+train,530789
+train,535997
+train,537496
+train,543608
+train,544019
+train,544213
+car,549273
+train,550990
+train,551594
+plane,554125
+train,556013
+car,557227
+train,559462
+train,563082
+plane,564758
+train,566065
+train,571465
+train,579358
+train,579460
+train,584085
+train,585752
+train,585816
+train,588813
+train,594422
+train,596516
+plane,598343
+train,601072
+train,608674
+train,610385
+train,611610
+train,614637
+train,619434
+train,620090
+train,625873
+plane,627076
+train,631931
+train,633509
+train,636224
+train,637377
+train,647130
+train,648076
+plane,658330
+train,660866
+train,665122
+train,671055
+train,673368
+plane,677997
+plane,680011
+train,680320
+plane,682538
+train,688114
+train,694705
+plane,697537
+plane,705632
+train,716695
+train,718754
+train,719200
+plane,727637
+train,728786
+train,729802
+train,732765
+train,734480
+plane,740395
+train,751389
+plane,759494
+train,761557
+train,762762
+plane,762883
+train,762971
+train,764176
+train,774882
+plane,775586
+train,777230
+train,787546
+train,788824
+train,791106
+plane,799268
+train,801830
+train,851880
+plane,853435
+plane,855522
+train,863394
+train,863960
+train,871373
+plane,872078
+train,891796
+train,901518
+plane,908116
+plane,912851
+plane,913437
+plane,918838
+plane,923204
+plane,926731
+plane,931541
+train,934890
+plane,946823
+train,955409
+plane,955970
+train,958250
+train,981357
+train,1005947
+train,1060376
+train,1094812
+plane,1097071
+train,1103612
+plane,1159316
+train,1161401
+plane,1481186
+plane,1512669
+plane,1518530
+plane,1728065
+plane,2633310
+plane,2687854
+plane,2729170
+plane,2731108
+plane,2902517
+plane,2936940
+plane,3185977
+plane,3221225
+plane,6849671
+plane,7164057
+plane,7383622
+plane,7503125
+plane,9502737
+plane,9821515
+plane,9933396
+plane,10428282