# Ad Carbon Calculation Framework

![Status](https://img.shields.io/badge/alpha-green?label=status)

Reference framework for calculating the carbon footprint of digital campaigns.

## Usage

The DigitalCarbonFramework association presents a framework for assessing the carbon emissions generated by an advertising campaign. For more information on the methodology, please refer to the following link:
[Link to DigitalCarbonFramework methodology](https://www.sri-france.org/wp-content/uploads/2023/06/SRI_Calculating-the-carbon-footprint_V2.pdf).

This Python package offers an implementation of the DigitalCarbonFramework methodology. Let's delve into how we've modeled this methodology and explore how you can utilize it to quantify the campaign's carbon impact.

### Summary

The carbon emissions associated with an advertising campaign can be categorized into two main components: Allocation and Diffusion.

Allocation refers to the process of ad selection, which occurs either through programmatic or direct means. Once the ad selection process is successful, the ad is displayed on targeted devices, a process referred to as Diffusion. Each category can further be subdivided into subcategories to provide a more detailed breakdown of the carbon costs involved.

The Allocation phase is segmented into two parts: servers and networks. Servers are responsible for storing, managing, and delivering digital advertisements to end-users, while the ads transit through the network.

The Diffusion phase is divided into three components: servers, networks, and devices.

This modelization defines five pillars for computation to evaluate the carbon cost of a campaign:

- Allocation network
- Allocation servers
- Diffusion network
- Diffusion servers
- Diffusion devices

For each pillar, the DigitalCarbonFramework proposes the computation of two costs. Firstly, the cost of utilization (USE), which measures the carbon emissions associated with every impression displayed. Secondly, the cost of Manufacturing, Use, and End of Life (MAN), which accounts for the carbon emissions generated throughout the lifecycle of hardware or infrastructure.

The total carbon cost of the campaign is expressed in kilograms of carbon.

### Getting Started

Let's start by installing the project.

```bash
# Clone the repo
git clone https://github.com/DigitalCarbonFramework/DigitalCarbonFramework.git
cd DigitalCarbonFramework
# Create a Python virtual environment (https://docs.python.org/3/library/venv.html)
python -m venv .venv
# Activate your environment (https://docs.python.org/3/library/venv.html#how-venvs-work)
# Here is a bash example
source .venv/bin/activate
# Install the current directory as a Python package
# (https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-from-a-local-src-tree)
pip install .
```

From now on, you can start to see the framework in action, with it's example file `src/carbon/__main__.py`.
Run it to validate your installation:

```bash
python src/carbon
```

If the scripts execute without error, we can deep dive on how to use this framework.

Then, import the required methods and classes.

```python
from carbon.digital_carbon_framework import Framework

from carbon.compute_footprints import Distribution, Co2Cost
from carbon.compute_footprints import impressions_cost, adcalls_cost, bids_cost
```

#### The `Co2Cost` object

This package computes the carbon cost of each pillar of the advertising campaign. Each pillar is represented as `Co2Cost` object, which contains 2 attributes `use` and `manufacturing` to assess the carbon cost of USE and MAN for this pillar. To obtain the total cost of this pillar, you can use the `total` property.

```python
allocation_network = Co2Cost(use=0.1, manufacturing=0.2)
print(allocation_network.use)
#> 0.1
print(allocation_network.manufacturing)
#> 0.2
print(allocation_network.total)
#> 0.3
```

#### The `Framework` object

The `Framework` object contains all the parameters to compute the carbon cost of an advertising campaign. It contains 11 attributes, each of this one is class representing the parameters of a pillar, either for usage or manufacturing.
All the parameters are defined in the `digital_carbon_framework.yml`, which is loaded by default when an instance of the Framework class is loaded. All the parameters are mutable and can be changed if needed.

```python
campaign = Framework.load() # load by default the digital_carbon_framework.yml
print(campaign.allocation_network_use.nb_requests_per_active_path)
#> 3
campaign.allocation_network_use.nb_requests_per_active_path = 5
print(campaign.allocation_network_use.nb_requests_per_active_path)
#> 5
```

##### Changing the target country

By default, all costs are computed with *France* as the target country. This implies that the emission factor used to calculate the pillars is based on the emission factor of France. This can be easily changed using the `change_target_country` method.  This method accepts the alpha code of the country, either in [ISO2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) or [ISO3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) format, and adjusts the emission factor values accordingly.

```python
print(campaign.allocation_servers_use.emission_factor_country)
#> 0.052

campaign.change_target_country('DE') # Changed from France to Germany
print(campaign.allocation_servers_use.emission_factor_country)
#> 0.311
```

#### Measures

This package proposes several carbon measurements. All the methods available are located in the `compute_footprints.py` python file.

##### The `impressions_cost` method

The primary objective of this repository is to compute the carbon cost of an advertising campaign in accordance with the DigitalCarbonFramework methodology. This is achieved through the `impression_costs` method. Following the DigitalCarbonFramework methodology, this method requires several mandatory fields:

- `nb_impressions`: the number of impressions
- `creative_type`: 'display' or 'video'
- `allocation`: 'direct' or 'programmatic'
- `creative_size_ko` (int): the size of the creative
- `devices_repartition`: the devices targeted
- (Optional) `creative_avg_view_s`: the average view of the creative. This value is mandatory for a display creative. For a video, the default value is 3s.

This function returns a `Co2CampaignCost` object, which summarizes the carbon cost of the five pillars, for both usage & manufacturing. Additionally, it provides the total carbon cost of the campaign.

```python
from carbon.digital_carbon_framework import Framework

from carbon.compute_footprints import Distribution, Co2Cost
from carbon.compute_footprints import impressions_cost, adcalls_cost, bids_cost

campaign = Framework.load()

campaign.change_target_country('FR')
DEVICES_REPARTITION = {'desktop':1, 'smart_phone': 0, 'tablet': 0, 'connected_tv':0}
Devices = Distribution(weights=DEVICES_REPARTITION)

results = impressions_cost(campaign,
            creative_type='display', nb_impressions=1e6,
            allocation='programmatic', creative_size_ko=1e3,
            devices_repartition=Devices, creative_avg_view_s=1)

print(results.shows())
# This is a Co2CampaignCost object.
#            kgco2_distrib_server:       use:   5.0016    manufacture:   0.1856
#           kgco2_distrib_network:       use:  12.3361    manufacture:   4.7840
#          kgco2_distrib_terminal:       use:   0.4247    manufacture:  13.1863
#        kgco2_allocation_network:       use: 690.3320    manufacture: 202.3402
#         kgco2_allocation_server:       use:  18.4289    manufacture:  60.9374
#                         Overall:       use: 726.5232    manufacture: 281.4334

print(f'The total of the carbon emissions for the campaign is: {results.overall.total} kgco2')
#> The total of the carbon emissions for the campaign is: 1007.9566426365125 kgco2
```

##### The `bids_cost` function

This function computes the carbon emissions associated with a bid only. It specifically focuses on the carbon emissions related to the allocation process. A bid is approximated as a direct buying process, resembling a single path from the Demand-Side Platform (DSP) to the Supply-Side Platform (SSP). However, considering internal processes and calls during bidding, we estimate that approximately 4 paths are activated. Therefore, the function takes into account the emissions from these 4 paths when computing the carbon emissions of a bid.

```python
co2_bids_only = bids_cost(campaign, nb_bids=10000)
co2_bids_only.shows()

#This is a BidCost object.
#        kgco2_allocation_network:       use:   0.0789    manufacture:   0.0231
#         kgco2_allocation_server:       use:   0.0021    manufacture:   0.0070
#                         Overall:       use:   0.0810    manufacture:   0.0301

print(f'The carbon emissions for the bidding process is: {co2_bids_only.overall.total} kgco2')
#> The carbon emissions for the bidding process is: 0.11109010712522793 kgco2
```

##### The `adcalls_cost` function

This function computes the carbon emissions of a number of ad calls. The number of SSPs connected to prebid is estimated to 10 on average.
The DigitalCarbonFramework defines a number of paths activated for video creative (100) and display creative (350).
An ad call is made to only 1 SSP. Given the estimation of 10 SSPs, each ad call activates 10 paths for a video, 35 paths for a display.

```python
co2_adcalls = adcalls_cost(campaign, nb_ad_calls=10000, creative_type='video')
co2_adcalls.shows()

# This is a AdcallCost object.
#        kgco2_allocation_network:       use:   0.1972    manufacture:   0.0578
#         kgco2_allocation_server:       use:   0.0053    manufacture:   0.0174
#                         Overall:       use:   0.2025    manufacture:   0.0752

print(f'The carbon emissions for the number of ad calls is: {co2_adcalls.overall.total} kgco2')
#> The carbon emissions for the number of ad calls is: 0.27772526781306983 kgco2
```

## Authors and acknowledgment

Initially developped [@greenbids.ai](https://greenbids.ai).

Based on DigitalCarbon framework.
