@@ -108,6 +108,15 @@ def __init__(self, *args, **kwargs) -> None:
108108 """
109109 _logger = logging .getLogger (self .__class__ .__name__ )
110110
111+ if not (
112+ kwargs .get ("co2_intensity" )
113+ or kwargs .get ("co2_signal_api_token" )
114+ or kwargs .get ("offline" )
115+ ):
116+ raise ValueError (
117+ "ElectricityMaps API token or hardcoeded CO2 intensity value is required for emissions tracking."
118+ )
119+
111120 if not isinstance (kwargs .get ("thermal_design_power_per_cpu" ), float ):
112121 kwargs ["thermal_design_power_per_cpu" ] = 80.0
113122 _logger .warning (
@@ -229,7 +238,6 @@ def estimate_co2_emissions(
229238
230239 if self .co2_intensity :
231240 _current_co2_intensity = self .co2_intensity
232- _co2_units = "kgCO2/kWh"
233241 else :
234242 self .check_refresh ()
235243 # If no local data yet then return
@@ -238,7 +246,7 @@ def estimate_co2_emissions(
238246 "No CO2 emission data recorded as no CO2 intensity value "
239247 "has been provided and there is no local intensity data available."
240248 )
241- return
249+ return False
242250
243251 if self ._client :
244252 _country_code = self ._client .country_code
@@ -251,10 +259,8 @@ def estimate_co2_emissions(
251259 ** self ._local_data [_country_code ]
252260 )
253261 _current_co2_intensity = self ._current_co2_data .data .carbon_intensity
254- _co2_units = self ._current_co2_data .carbon_intensity_units
255262 _process .gpu_percentage = gpu_percent
256263 _process .cpu_percentage = cpu_percent
257- _previous_energy : float = _process .total_energy
258264 _process .power_usage = (_process .cpu_percentage / 100.0 ) * (
259265 self .thermal_design_power_per_cpu / self .n_cores_per_cpu
260266 )
@@ -263,23 +269,23 @@ def estimate_co2_emissions(
263269 _process .power_usage += (
264270 _process .gpu_percentage / 100.0
265271 ) * self .thermal_design_power_per_gpu
272+ # Convert W to kW
273+ _process .power_usage /= 1000
274+ # Measure energy in kWh
275+ _process .energy_delta = _process .power_usage * measure_interval / 3600
276+ _process .total_energy += _process .energy_delta
266277
267- _process .total_energy += _process .power_usage * measure_interval
268- _process .energy_delta = _process .total_energy - _previous_energy
269-
270- # Measured value is in g/kWh, convert to kg/kWs
271- _carbon_intensity_kgpws : float = _current_co2_intensity / (60 * 60 * 1e3 )
272-
273- _process .co2_delta = (
274- _process .power_usage * _carbon_intensity_kgpws * measure_interval
275- )
278+ # Measured value is in g/kWh, convert to kg/kWh
279+ _carbon_intensity : float = _current_co2_intensity / 1000
276280
281+ _process .co2_delta = _process .energy_delta * _carbon_intensity
277282 _process .co2_emission += _process .co2_delta
278283
279284 self ._logger .debug (
280- f"📝 For process '{ process_id } ', recorded: CPU={ _process .cpu_percentage :.2f} %, "
281- f"Power={ _process .power_usage :.2f} W, CO2={ _process .co2_emission :.2e} { _co2_units } "
285+ f"📝 For process '{ process_id } ', in interval { measure_interval } , recorded: CPU={ _process .cpu_percentage :.2f} %, "
286+ f"Power={ _process .power_usage :.2f} kW, Energy = { _process . energy_delta } kWh, CO2={ _process .co2_delta :.2e} kg "
282287 )
288+ return True
283289
284290 def simvue_metrics (self ) -> dict [str , float ]:
285291 """Retrieve metrics to send to Simvue server."""
0 commit comments