Skip to content

Commit a525f33

Browse files
committed
calculate operational and embodied emissions per segment
1 parent 7bb79bd commit a525f33

File tree

3 files changed

+238
-0
lines changed

3 files changed

+238
-0
lines changed

src/constants/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ const FIRST_TIME_VIEWING_PERCENTAGE = 0.75;
2424
const RETURNING_VISITOR_PERCENTAGE = 0.25;
2525
const PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD = 0.02;
2626

27+
const SWDV4 = {
28+
OPERATIONAL_KWH_PER_GB_DATACENTER: 0.055,
29+
OPERATIONAL_KWH_PER_GB_NETWORK: 0.059,
30+
OPERATIONAL_KWH_PER_GB_DEVICE: 0.08,
31+
EMBODIED_KWH_PER_GB_DATACENTER: 0.012,
32+
EMBODIED_KWH_PER_GB_NETWORK: 0.013,
33+
EMBODIED_KWH_PER_GB_DEVICE: 0.081,
34+
GLOBAL_GRID_INTENSITY: 494,
35+
};
36+
2737
export {
2838
fileSize,
2939
KWH_PER_GB,
@@ -36,4 +46,5 @@ export {
3646
FIRST_TIME_VIEWING_PERCENTAGE,
3747
RETURNING_VISITOR_PERCENTAGE,
3848
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD,
49+
SWDV4,
3950
};

src/sustainable-web-design-v4.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"use strict";
2+
3+
/**
4+
* Sustainable Web Design version 4
5+
*
6+
* Updated calculations and figures from
7+
* https://sustainablewebdesign.org/estimating-digital-emissions/
8+
*
9+
*/
10+
11+
import { fileSize, SWDV4 } from "./constants/index.js";
12+
import { formatNumber } from "./helpers/index.js";
13+
14+
const {
15+
OPERATIONAL_KWH_PER_GB_DATACENTER,
16+
OPERATIONAL_KWH_PER_GB_NETWORK,
17+
OPERATIONAL_KWH_PER_GB_DEVICE,
18+
EMBODIED_KWH_PER_GB_DATACENTER,
19+
EMBODIED_KWH_PER_GB_NETWORK,
20+
EMBODIED_KWH_PER_GB_DEVICE,
21+
GLOBAL_GRID_INTENSITY,
22+
} = SWDV4;
23+
24+
class SustainableWebDesign {
25+
constructor(options) {
26+
this.options = options;
27+
}
28+
29+
/**
30+
* Calculate the operational energy of data transfer for each system segment
31+
*
32+
* @param {number} bytes
33+
* @returns {object}
34+
*/
35+
operationalEnergyPerSegment(bytes) {
36+
const transferedBytesToGb = bytes / fileSize.GIGABYTE;
37+
const dataCenter = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_DATACENTER;
38+
const network = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_NETWORK;
39+
const device = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_DEVICE;
40+
41+
return {
42+
dataCenter,
43+
network,
44+
device,
45+
};
46+
}
47+
48+
/**
49+
* Calculate the operational emissions of data transfer for each system segment
50+
*
51+
* @param {number} bytes
52+
* @param {object} options
53+
* @returns {object}
54+
*/
55+
operationalEmissions(bytes, options = {}) {
56+
const { dataCenter, network, device } =
57+
this.operationalEnergyPerSegment(bytes);
58+
59+
let dataCenterGridIntensity = GLOBAL_GRID_INTENSITY;
60+
let networkGridIntensity = GLOBAL_GRID_INTENSITY;
61+
let deviceGridIntensity = GLOBAL_GRID_INTENSITY;
62+
63+
if (options?.gridIntensity) {
64+
const { device, network, dataCenter } = options.gridIntensity;
65+
66+
if (device?.value || device?.value === 0) {
67+
deviceGridIntensity = device.value;
68+
}
69+
70+
if (network?.value || network?.value === 0) {
71+
networkGridIntensity = network.value;
72+
}
73+
74+
if (dataCenter?.value || dataCenter?.value === 0) {
75+
dataCenterGridIntensity = dataCenter.value;
76+
}
77+
}
78+
79+
const dataCenterEmissions = dataCenter * dataCenterGridIntensity;
80+
const networkEmissions = network * networkGridIntensity;
81+
const deviceEmissions = device * deviceGridIntensity;
82+
83+
return {
84+
dataCenter: dataCenterEmissions,
85+
network: networkEmissions,
86+
device: deviceEmissions,
87+
};
88+
}
89+
90+
/**
91+
* Calculate the embodied energy of data transfer for each system segment
92+
*
93+
* @param {number} bytes
94+
* @returns {object}
95+
*/
96+
embodiedEnergyPerSegment(bytes) {
97+
const transferedBytesToGb = bytes / fileSize.GIGABYTE;
98+
const dataCenter = transferedBytesToGb * EMBODIED_KWH_PER_GB_DATACENTER;
99+
const network = transferedBytesToGb * EMBODIED_KWH_PER_GB_NETWORK;
100+
const device = transferedBytesToGb * EMBODIED_KWH_PER_GB_DEVICE;
101+
102+
return {
103+
dataCenter,
104+
network,
105+
device,
106+
};
107+
}
108+
109+
/**
110+
* Calculate the embodied emissions of data transfer for each system segment
111+
*
112+
* @param {number} bytes
113+
* @returns {object}
114+
*/
115+
embodiedEmissions(bytes) {
116+
const { dataCenter, network, device } =
117+
this.embodiedEnergyPerSegment(bytes);
118+
119+
const dataCenterGridIntensity = GLOBAL_GRID_INTENSITY;
120+
const networkGridIntensity = GLOBAL_GRID_INTENSITY;
121+
const deviceGridIntensity = GLOBAL_GRID_INTENSITY;
122+
123+
// NOTE: Per the guidance in the SWDM v4, the grid intensity values for embodied emissions are fixed to the global grid intensity.
124+
125+
const dataCenterEmissions = dataCenter * dataCenterGridIntensity;
126+
const networkEmissions = network * networkGridIntensity;
127+
const deviceEmissions = device * deviceGridIntensity;
128+
129+
return {
130+
dataCenter: dataCenterEmissions,
131+
network: networkEmissions,
132+
device: deviceEmissions,
133+
};
134+
}
135+
}
136+
137+
export { SustainableWebDesign };
138+
export default SustainableWebDesign;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import SustainableWebDesign from "./sustainable-web-design-v4.js";
2+
import { MILLION, SWDV4 } from "./constants/test-constants.js";
3+
4+
describe("sustainable web design model version 4", () => {
5+
const swd = new SustainableWebDesign();
6+
7+
describe("operational emissions", () => {
8+
it("returns the expected emissions for 1GB data transfer", () => {
9+
const result = swd.operationalEmissions(1000000000);
10+
expect(result).toEqual(
11+
expect.objectContaining({
12+
dataCenter: expect.any(Number),
13+
network: expect.any(Number),
14+
device: expect.any(Number),
15+
})
16+
);
17+
expect(result.dataCenter).toBeCloseTo(27.17, 3);
18+
expect(result.network).toBeCloseTo(29.146, 3);
19+
expect(result.device).toBeCloseTo(39.52, 3);
20+
});
21+
22+
it("returns the expected emissions for 0bytes data transfer", () => {
23+
const result = swd.operationalEmissions(0);
24+
expect(result).toEqual(
25+
expect.objectContaining({
26+
dataCenter: expect.any(Number),
27+
network: expect.any(Number),
28+
device: expect.any(Number),
29+
})
30+
);
31+
expect(result.dataCenter).toBeCloseTo(0, 3);
32+
expect(result.network).toBeCloseTo(0, 3);
33+
expect(result.device).toBeCloseTo(0, 3);
34+
});
35+
36+
if (
37+
("returns the expected emissions for 1GB data transfer with custom grid intensities",
38+
() => {
39+
const result = swd.operationalEmissions(1000000000, {
40+
gridIntensity: {
41+
dataCenter: { value: 100 },
42+
network: { value: 200 },
43+
device: { value: 300 },
44+
},
45+
});
46+
expect(result).toEqual(
47+
expect.objectContaining({
48+
dataCenter: expect.any(Number),
49+
network: expect.any(Number),
50+
device: expect.any(Number),
51+
})
52+
);
53+
expect(result.dataCenter).toBeCloseTo(5.5, 3);
54+
expect(result.network).toBeCloseTo(11.8, 3);
55+
expect(result.device).toBeCloseTo(24, 3);
56+
})
57+
);
58+
});
59+
60+
describe("embodied emissions", () => {
61+
it("returns the expected emissions for 1GB data transfer", () => {
62+
const result = swd.embodiedEmissions(1000000000);
63+
expect(result).toEqual(
64+
expect.objectContaining({
65+
dataCenter: expect.any(Number),
66+
network: expect.any(Number),
67+
device: expect.any(Number),
68+
})
69+
);
70+
expect(result.dataCenter).toBeCloseTo(5.928, 3);
71+
expect(result.network).toBeCloseTo(6.422, 3);
72+
expect(result.device).toBeCloseTo(40.014, 3);
73+
});
74+
75+
it("returns the expected emissions for 0bytes data transfer", () => {
76+
const result = swd.embodiedEmissions(0);
77+
expect(result).toEqual(
78+
expect.objectContaining({
79+
dataCenter: expect.any(Number),
80+
network: expect.any(Number),
81+
device: expect.any(Number),
82+
})
83+
);
84+
expect(result.dataCenter).toBeCloseTo(0, 3);
85+
expect(result.network).toBeCloseTo(0, 3);
86+
expect(result.device).toBeCloseTo(0, 3);
87+
});
88+
});
89+
});

0 commit comments

Comments
 (0)