Source code for cmtklib.carbonfootprint
# Copyright (C) 2009-2022, Ecole Polytechnique Federale de Lausanne (EPFL) and
# Hospital Center and University of Lausanne (UNIL-CHUV), Switzerland, and CMP3 contributors
# All rights reserved.
#
# This software is distributed under the open-source license Modified BSD.
"""Module that defines CMTK functions for converting C02 emissions estimated with `codecarbon`."""
import os
from pkg_resources import resource_filename
import logging
from pathlib import Path
import pandas as pd
from codecarbon import EmissionsTracker
from cmp.info import __version__
[docs]def create_emissions_tracker(bids_root):
"""Return a new instance of `codecarbon.EmissionsTracker`.
Parameters
----------
bids_root : string
Path to the root directory of the BIDS dataset
Returns
-------
tracker: `codecarbon.EmissionsTracker`
Return a new instance of `codecarbon.EmissionsTracker`
References
----------
https://github.com/mlco2/codecarbon/blob/v1.2.0/codecarbon/emissions_tracker.py
"""
# Create the code folder if it does not exist yet
if not os.path.exists(str(Path(bids_root) / "code")):
os.makedirs(str(Path(bids_root) / "code"), exist_ok=True)
# To not pollute CMP3 outputs with codecarbon outputs
# Comment this line for debug if you get for instance
# Emissions: O Kg
logging.getLogger("codecarbon").disabled = True
# Create and return the emissions tracker
return EmissionsTracker(
project_name=f"connectomemapper_{__version__}_gui",
output_dir=str(Path(bids_root) / "code"),
measure_power_secs=15,
)
[docs]def get_emission_car_miles_equivalent(emissions):
"""Return the equivalent of CO2 emissions [Kg] in terms of kms traveled by an average car.
References
----------
https://github.com/mlco2/codecarbon/blob/c6aebb9681186a71573748e381b6a3c9731de2d3/codecarbon/viz/data.py#L53
"""
return "{:.0f}".format((emissions / 0.409) * 1.60934)
[docs]def get_emission_tv_time_equivalent(emissions):
"""Return the equivalent of CO2 emissions [Kg] in terms of kms traveled by an average car.
References
----------
https://github.com/mlco2/codecarbon/blob/c6aebb9681186a71573748e381b6a3c9731de2d3/codecarbon/viz/data.py#L66
"""
tv_time_in_minutes = emissions * (1 / 0.097) * 60
tv_time = "{:.0f} minutes".format(tv_time_in_minutes)
if tv_time_in_minutes >= 60:
time_in_hours = tv_time_in_minutes / 60
tv_time = "{:.0f} hours".format(time_in_hours)
if time_in_hours >= 24:
time_in_days = time_in_hours / 24
tv_time = "{:.0f} days".format(time_in_days)
return tv_time
[docs]def load_and_compute_carbon_footprint_metrics(emissions_csv_file, nb_of_subjects_processed) -> dict:
"""Return a dictionary storing the different metrics and variables displayed in the carbon footprint report.
The dictionary has the different fields: `'country_name'`, `'region_name'`, `'country_emissions_per_kwh'`,
`'duration'`, `'energy_consumed'`, `'emissions'`, `'car_kms'`, `'tv_time'`, `'pred_energy_consumed'`,
`'pred_emissions'`, `'pred_car_kms'`, `'pred_tv_time'`.
Parameters
----------
emissions_csv_file : string
Path to the `emissions.csv` file generated by `Codecarbon`.
nb_of_subjects_processed : int
Number of subject processed.
"""
emissions_df = pd.read_csv(emissions_csv_file)
last_index = len(emissions_df) - 1
duration = emissions_df['duration'][last_index]
energy_consumed = emissions_df['energy_consumed'][last_index]
emissions = emissions_df['emissions'][last_index]
country_name = emissions_df['country_name'][last_index]
region_name = emissions_df['region'][last_index]
del emissions_df
country_emissions_per_kwh = float(emissions / energy_consumed)
car_kms = get_emission_car_miles_equivalent(emissions)
tv_time = get_emission_tv_time_equivalent(emissions)
pred_duration = 100 * duration / nb_of_subjects_processed
pred_energy_consumed = 100 * energy_consumed / nb_of_subjects_processed
pred_emissions = 100 * emissions / nb_of_subjects_processed
pred_car_kms = get_emission_car_miles_equivalent(pred_emissions)
pred_tv_time = get_emission_tv_time_equivalent(pred_emissions)
carbon_footprint_metrics = {
'country_name': f'{country_name}',
'region_name': f'{region_name}',
'country_emissions_per_kwh': f'{country_emissions_per_kwh}',
'duration': f'{duration}',
'energy_consumed': f'{energy_consumed}',
'emissions': f'{emissions}',
'car_kms': f'{car_kms}',
'tv_time': f'{tv_time}',
'pred_duration': f'{pred_duration}',
'pred_energy_consumed': f'{pred_energy_consumed}',
'pred_emissions': f'{pred_emissions}',
'pred_car_kms': f'{pred_car_kms}',
'pred_tv_time': f'{pred_tv_time}',
}
return carbon_footprint_metrics
[docs]def create_carbon_footprint_message(bids_dir, emissions_csv_file, nb_of_subjects_processed):
"""Return a string containg the carbon footprint print message to be passed to `print()`.
Parameters
----------
bids_dir : string
Path to root directory of the BIDS dataset
emissions_csv_file : string
Path to the `emissions.csv` file generated by `Codecarbon`.
nb_of_subjects_processed : int
Number of subject processed.
Returns
-------
carbon_footprint_msg : string
String formatted containing the carbon footprint meassge to be passed to `print()`
"""
carbon_footprint_metrics = load_and_compute_carbon_footprint_metrics(
emissions_csv_file=emissions_csv_file,
nb_of_subjects_processed=nb_of_subjects_processed
)
carbon_footprint_msg = "#" * 80 + "\n"
carbon_footprint_msg += f"CARBON FOOTPRINT REPORT\n"
carbon_footprint_msg += "#" * 80 + "\n"
carbon_footprint_msg += "Carbon footprint results\n"
carbon_footprint_msg += "-" * 80 + "\n"
carbon_footprint_msg += f"Connectome Mapper ({__version__}) was run on {nb_of_subjects_processed} subject(s) "
carbon_footprint_msg += f"in {carbon_footprint_metrics['region_name']} ({carbon_footprint_metrics['country_name']})"
carbon_footprint_msg += f" (Mean CO<sub>2</sub> kg / kWH: {carbon_footprint_metrics['country_emissions_per_kwh']}),"
carbon_footprint_msg += " having the following estimated carbon footprint:\n"
carbon_footprint_msg += f"\t* Duration: {carbon_footprint_metrics['duration']} s\n"
carbon_footprint_msg += f"\t* Energy consumed: {carbon_footprint_metrics['energy_consumed']} kWh\n"
carbon_footprint_msg += f"\t* Estimated Co2 emissions: {carbon_footprint_metrics['emissions']} kg\n"
carbon_footprint_msg += "\t* Equivalent in distance travelled by "
carbon_footprint_msg += f"avg car: {carbon_footprint_metrics['car_kms']} kms\n"
carbon_footprint_msg += "\t* Equivalent in amount of time watching a 32-inch LCD flat "
carbon_footprint_msg += f"screen TV: {carbon_footprint_metrics['tv_time']}\n"
carbon_footprint_msg += "#" * 80 + "\n"
carbon_footprint_msg += f"Carbon footprint prediction for 100 subjects in the same conditions\n"
carbon_footprint_msg += "-" * 80 + "\n"
carbon_footprint_msg += f"\t* Predicted duration: {carbon_footprint_metrics['pred_duration']} s\n"
carbon_footprint_msg += f"\t* Predicted energy consumed: {carbon_footprint_metrics['pred_energy_consumed']} kWh\n"
carbon_footprint_msg += f"\t* Predicted Co2 emissions: {carbon_footprint_metrics['pred_emissions']} kg\n"
carbon_footprint_msg += "\t* Equivalent in distance travelled by "
carbon_footprint_msg += f"avg car: {carbon_footprint_metrics['pred_car_kms']} kms\n"
carbon_footprint_msg += "\t* Equivalent in amount of time watching a 32-inch LCD flat "
carbon_footprint_msg += f"screen TV: {carbon_footprint_metrics['pred_tv_time']}\n"
carbon_footprint_msg += "#" * 80 + "\n"
carbon_footprint_msg += "Results can be visualized with the codecarbon visualization "
carbon_footprint_msg += "tool using following command:\n\n"
carbon_footprint_msg += f'\t$ carbonboard --filepath="{bids_dir}/code/emissions.csv" --port=9999\n'
return carbon_footprint_msg
[docs]def create_html_carbon_footprint_report(emissions_csv_file, nb_of_subjects_processed):
"""Return a string containing the content of html report to be passed to traits `Str` with `HTMLEditor`.
Parameters
----------
emissions_csv_file : string
Path to the `emissions.csv` file generated by `Codecarbon`.
nb_of_subjects_processed : int
Number of subject processed.
"""
carbon_footprint_metrics = load_and_compute_carbon_footprint_metrics(
emissions_csv_file=emissions_csv_file,
nb_of_subjects_processed=nb_of_subjects_processed
)
# Get path to different resources used in the <head> of the HTML document
resources_dir = os.path.join('data', 'report', 'carbonfootprint')
jquery_js_file = resource_filename('cmtklib', os.path.join(resources_dir, 'js', 'jquery.3.3.1.min.js'))
bootstrap_css_file = resource_filename(
'cmtklib', os.path.join(resources_dir, 'css', 'bootstrap-combined.no-icons.min.css')
)
return f"""
<!DOCTYPE html>
<html>
<head>
<title>Footer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="{jquery_js_file}"></script>
<link href="{bootstrap_css_file}" rel="stylesheet">
<script src="https://kit.fontawesome.com/d2ef6e0082.js" crossorigin="anonymous"></script>
<style>
div {{
border: 1px solid gray;
padding: 8px;
}}
h1 {{
text-align: center;
text-transform: uppercase;
color: #4CAF50;
}}
p {{
margin: 0px 10px 0px 10px;
padding: 10px 10px 10px 10px;
text-indent: 0px;
text-align: justify;
background-color: #EEEEEE;
}}
a {{
text-decoration: none;
color: #008CBA;
}}
#footer {{
border: 0px solid gray;
padding: 8px;
}}
#GFG {{
border: 0px solid gray;
padding: 8px;
height: 60px;
text-align: center;
padding: 3px;
color: white;
background-image: url(https://ohbm-environment.org/wp-content/uploads/slider/cache/aceabfbee23a7b3e8e9fed910c639555/Borneo_rainforest-3.jpg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}}
.fa-brain{{
color: pink;
font-size: 1em;
margin: 0px 10px 0px 10px;
vertical-align: middle;
horizontal-align: left;
}}
</style>
</head>
<body>
<div id="GFG">
</div>
<div>
<h4>
Carbon footprint results
</h4>
<p>
Connectome Mapper ({__version__}) was run on {nb_of_subjects_processed} subject(s)
in {carbon_footprint_metrics['region_name']} ({carbon_footprint_metrics['country_name']})
(Mean CO<sub>2</sub> kg / kWH: {carbon_footprint_metrics['country_emissions_per_kwh']}), having
the following estimated carbon footprint:
</p>
<ul>
<li>Total run time: {carbon_footprint_metrics['duration']}s </li>
<li>Total energy consumed: {carbon_footprint_metrics['energy_consumed']} kWh </li>
<li>Total estimated CO<sub>2</sub> emissions: {carbon_footprint_metrics['emissions']} kg </li>
<li>
Equivalent in distance travelled by avg
<i class="fas fa-car"></i>: {carbon_footprint_metrics['car_kms']} kms
</li>
<li>
Equivalent in amount of time watching a 32-inch LCD flat screen
<i class="fas fa-tv"></i>: {carbon_footprint_metrics['tv_time']}
</li>
</ul>
<p>
<em>
Estimations were conducted using the
<a href="https://github.com/mlco2/codecarbon">CodeCarbon emissions tracker</a>.
</em>
</p>
<h4>
Carbon footprint prediction for 100 subjects
</h4>
<p>
In the same conditions, this would have resulted in:
</p>
<ul>
<li>Total run time: {carbon_footprint_metrics['pred_duration']}s </li>
<li>Total energy consumed: {carbon_footprint_metrics['pred_energy_consumed']} kWh </li>
<li>Co2 emissions: {carbon_footprint_metrics['pred_emissions']} kg</li>
<li>
Equivalent in distance travelled by avg
<i class="fas fa-car"></i>: {carbon_footprint_metrics['pred_car_kms']} kms
</li>
<li>
Equivalent in amount of time watching a 32-inch LCD flat screen
<i class="fas fa-tv"></i>: {carbon_footprint_metrics['pred_tv_time']}
</li>
</ul>
</div>
</body>
<footer>
<div id="footer">
<p>
Actively part of the initiative created by the
<a href="https://neuropipelines.github.io/20pipelines">
Sustainability and Environment Action Special Interest Group</a>,
the CMP developers hope that by providing you with such metrics it can allow you to be more aware about
the carbon footprint of your<i class="fas fa-brain" aria-hidden= "true"></i>research. 🌍 ✨
</p>
</div>
</footer>
<html>
"""