we differ on swd model because we're including the carbon intensity of the country of origin of the visit
127 lines
3.8 KiB
Crystal
127 lines
3.8 KiB
Crystal
# This is an adaptation of the Sustainable Web Design algorithm to
|
|
# calculate CO2 emissions per visit.
|
|
#
|
|
# In this case if we know the country of origin of the visit we can
|
|
# adapt the device emissions to the country, same as the datacenter
|
|
# variable on the original proposal.
|
|
#
|
|
# Also the CO2 per visit is adapted to the actual cache, since we know
|
|
# the status code. 304 visits are cached so the energy usage is much
|
|
# smaller and we don't need to make assumptions.
|
|
#
|
|
# @see https://sustainablewebdesign.org/calculating-digital-emissions/
|
|
|
|
require "./swd/intensity_data"
|
|
|
|
class SWD
|
|
getter bytes : Int8 | Int16 | Int32 | Int64 | UInt8 | UInt16 | UInt32 | UInt64
|
|
getter renewable : Bool
|
|
getter datacenter_iso_code : String?
|
|
getter consumer_device_iso_code : String?
|
|
getter intensity_calculator : Symbol
|
|
|
|
GIGABYTE = 1000.0 * 1000.0 * 1000.0
|
|
KWH_PER_GB = 0.81
|
|
END_USER_DEVICE_ENERGY = 0.52
|
|
NETWORK_ENERGY = 0.14
|
|
DATACENTER_ENERGY = 0.15
|
|
PRODUCTION_ENERGY = 0.19
|
|
GLOBAL_GRID_INTENSITY = 442.0
|
|
RENEWABLES_GRID_INTENSITY = 50.0
|
|
|
|
@transfered_bytes_to_gb : Float32? | Float64? = nil
|
|
@energy_usage : Float32? | Float64? = nil
|
|
@consumer_device_energy : Float32? | Float64? = nil
|
|
@network_energy : Float32? | Float64? = nil
|
|
@production_energy : Float32? | Float64? = nil
|
|
@datacenter_energy : Float32? | Float64? = nil
|
|
@total_energy : Float32? | Float64? = nil
|
|
@consumer_device_co2 : Float32? | Float64? = nil
|
|
@network_co2 : Float32? | Float64? = nil
|
|
@production_co2 : Float32? | Float64? = nil
|
|
@datacenter_co2 : Float32? | Float64? = nil
|
|
@total_co2 : Float32? | Float64? = nil
|
|
|
|
def initialize(@bytes, @renewable = false, @datacenter_iso_code = nil, @consumer_device_iso_code = nil, @intensity_calculator = :marginal); end
|
|
|
|
def transfered_bytes_to_gb
|
|
@transfered_bytes_to_gb ||= @bytes / GIGABYTE
|
|
end
|
|
|
|
def energy_usage
|
|
@energy_usage ||= transfered_bytes_to_gb / KWH_PER_GB
|
|
end
|
|
|
|
def consumer_device_energy
|
|
@consumer_device_energy ||= energy_usage * END_USER_DEVICE_ENERGY
|
|
end
|
|
|
|
def network_energy
|
|
@network_energy ||= energy_usage * NETWORK_ENERGY
|
|
end
|
|
|
|
def production_energy
|
|
@production_energy ||= energy_usage * PRODUCTION_ENERGY
|
|
end
|
|
|
|
def total_energy
|
|
@total_energy ||= production_energy + network_energy + datacenter_energy + consumer_device_energy
|
|
end
|
|
|
|
def datacenter_energy
|
|
@datacenter_energy ||= energy_usage * DATACENTER_ENERGY
|
|
end
|
|
|
|
# Returns the carbon intensity depending on renewable status and
|
|
# location, by default uses global grid intensity.
|
|
def datacenter_carbon_intensity : Float
|
|
renewable ? RENEWABLES_GRID_INTENSITY : (localized_datacenter_intensity || GLOBAL_GRID_INTENSITY)
|
|
end
|
|
|
|
# Returns the carbon intensity of user devices depending on location,
|
|
# by default uses global grid intensity
|
|
def device_carbon_intensity : Float
|
|
localized_consumer_device_intensity || GLOBAL_GRID_INTENSITY
|
|
end
|
|
|
|
def network_carbon_intensity : Float
|
|
GLOBAL_GRID_INTENSITY
|
|
end
|
|
|
|
def global_emissions : Float
|
|
GLOBAL_GRID_INTENSITY
|
|
end
|
|
|
|
def datacenter_co2
|
|
@datacenter_co2 ||= datacenter_carbon_intensity * datacenter_energy
|
|
end
|
|
|
|
def consumer_device_co2
|
|
@consumer_device_co2 ||= device_carbon_intensity * consumer_device_energy
|
|
end
|
|
|
|
def network_co2
|
|
@network_co2 ||= network_carbon_intensity * network_energy
|
|
end
|
|
|
|
def production_co2
|
|
@production_co2 ||= production_energy * global_emissions
|
|
end
|
|
|
|
def total_co2
|
|
@total_co2 ||= production_co2 + network_co2 + datacenter_co2 + consumer_device_co2
|
|
end
|
|
|
|
def localized_datacenter_intensity : Float64?
|
|
return unless datacenter_iso_code
|
|
|
|
SWD::IntensityData.by_iso(datacenter_iso_code || "", intensity_calculator)
|
|
end
|
|
|
|
def localized_consumer_device_intensity : Float64?
|
|
return unless consumer_device_iso_code
|
|
|
|
SWD::IntensityData.by_iso(consumer_device_iso_code || "", intensity_calculator)
|
|
end
|
|
end
|