@@ -189,6 +189,7 @@ def running_costs(
189189 capacity : xr .DataArray ,
190190 production : xr .DataArray ,
191191 consumption : xr .DataArray ,
192+ aggregate_timeslices : bool = False ,
192193) -> xr .DataArray :
193194 """Total annual running costs (excluding capital costs).
194195
@@ -206,19 +207,26 @@ def running_costs(
206207 _fuel_costs = fuel_costs (technologies , prices , consumption )
207208 _material_costs = material_costs (technologies , prices , consumption )
208209
210+ # Aggregate over timeslices (if required)
211+ if aggregate_timeslices :
212+ _environmental_costs = _environmental_costs .sum ("timeslice" )
213+ _fuel_costs = _fuel_costs .sum ("timeslice" )
214+ _material_costs = _material_costs .sum ("timeslice" )
215+
209216 # Costs associated with capacity and production level (annual)
210217 _fixed_costs = fixed_costs (technologies , capacity )
211218 _variable_costs = variable_costs (technologies , production )
212219
213- # Split fixed/variable across timeslices in proportion to production
214- timeslice_level = get_level (production )
215- tech_activity = production_amplitude (production , technologies )
216- _fixed_costs = distribute_timeslice (
217- _fixed_costs , ts = tech_activity , level = timeslice_level
218- )
219- _variable_costs = distribute_timeslice (
220- _variable_costs , ts = tech_activity , level = timeslice_level
221- )
220+ # Split fixed/variable across timeslices in proportion to production (if required)
221+ if not aggregate_timeslices :
222+ timeslice_level = get_level (production )
223+ tech_activity = production_amplitude (production , technologies )
224+ _fixed_costs = distribute_timeslice (
225+ _fixed_costs , ts = tech_activity , level = timeslice_level
226+ )
227+ _variable_costs = distribute_timeslice (
228+ _variable_costs , ts = tech_activity , level = timeslice_level
229+ )
222230
223231 # Total running costs
224232 result = (
@@ -238,6 +246,7 @@ def net_present_value(
238246 capacity : xr .DataArray ,
239247 production : xr .DataArray ,
240248 consumption : xr .DataArray ,
249+ aggregate_timeslices : bool = False ,
241250) -> xr .DataArray :
242251 """Net present value (NPV) of the relevant technologies.
243252
@@ -265,23 +274,28 @@ def net_present_value(
265274 production: xr.DataArray with commodity production by the relevant technologies
266275 consumption: xr.DataArray with commodity consumption by the relevant
267276 technologies
277+ aggregate_timeslices: If True, the LCOE is aggregated over timeslices (result
278+ will not have a "timeslice" dimension)
268279
269280 Return:
270281 xr.DataArray with the NPV calculated for the relevant technologies
271282 """
272283 # Capital costs (lifetime)
273284 _capital_costs = capital_costs (technologies , capacity , method = "lifetime" )
274285
275- # Distribute capital costs across timeslices in proportion to production
276- tech_activity = production_amplitude (production , technologies )
277- _capital_costs = distribute_timeslice (
278- _capital_costs , ts = tech_activity , level = get_level (production )
279- )
286+ # Split capital costs across timeslices in proportion to production (if required)
287+ if not aggregate_timeslices :
288+ tech_activity = production_amplitude (production , technologies )
289+ _capital_costs = distribute_timeslice (
290+ _capital_costs , ts = tech_activity , level = get_level (production )
291+ )
280292
281293 # Revenue (annual)
282294 products = is_enduse (technologies .comm_usage )
283295 prices_non_env = filter_input (prices , commodity = products )
284296 revenues = (production * prices_non_env ).sum ("commodity" )
297+ if aggregate_timeslices :
298+ revenues = revenues .sum ("timeslice" )
285299
286300 # Running costs (annual)
287301 _running_costs = running_costs (
@@ -290,6 +304,7 @@ def net_present_value(
290304 capacity ,
291305 production ,
292306 consumption ,
307+ aggregate_timeslices ,
293308 )
294309
295310 # Calculate running costs and revenues over lifetime
@@ -308,6 +323,7 @@ def net_present_cost(
308323 capacity : xr .DataArray ,
309324 production : xr .DataArray ,
310325 consumption : xr .DataArray ,
326+ aggregate_timeslices : bool = False ,
311327) -> xr .DataArray :
312328 """Net present cost (NPC) of the relevant technologies.
313329
@@ -325,11 +341,20 @@ def net_present_cost(
325341 production: xr.DataArray with commodity production by the relevant technologies
326342 consumption: xr.DataArray with commodity consumption by the relevant
327343 technologies
344+ aggregate_timeslices: If True, the LCOE is aggregated over timeslices (result
345+ will not have a "timeslice" dimension)
328346
329347 Return:
330348 xr.DataArray with the NPC calculated for the relevant technologies
331349 """
332- result = - net_present_value (technologies , prices , capacity , production , consumption )
350+ result = - net_present_value (
351+ technologies ,
352+ prices ,
353+ capacity ,
354+ production ,
355+ consumption ,
356+ aggregate_timeslices ,
357+ )
333358 return result
334359
335360
@@ -340,6 +365,7 @@ def equivalent_annual_cost(
340365 capacity : xr .DataArray ,
341366 production : xr .DataArray ,
342367 consumption : xr .DataArray ,
368+ aggregate_timeslices : bool = False ,
343369) -> xr .DataArray :
344370 """Equivalent annual costs (or annualized cost) of a technology.
345371
@@ -361,6 +387,8 @@ def equivalent_annual_cost(
361387 production: xr.DataArray with commodity production by the relevant technologies
362388 consumption: xr.DataArray with commodity consumption by the relevant
363389 technologies
390+ aggregate_timeslices: If True, the LCOE is aggregated over timeslices (result
391+ will not have a "timeslice" dimension)
364392
365393 Return:
366394 xr.DataArray with the EAC calculated for the relevant technologies
@@ -371,9 +399,12 @@ def equivalent_annual_cost(
371399 capacity ,
372400 production ,
373401 consumption ,
402+ aggregate_timeslices ,
374403 )
375404 crf = capital_recovery_factor (technologies )
376- result = npc * broadcast_timeslice (crf , level = get_level (production ))
405+ if not aggregate_timeslices :
406+ crf = broadcast_timeslice (crf , level = get_level (production ))
407+ result = npc * crf
377408 return result
378409
379410
@@ -385,6 +416,7 @@ def levelized_cost_of_energy(
385416 production : xr .DataArray ,
386417 consumption : xr .DataArray ,
387418 method : str = "lifetime" ,
419+ aggregate_timeslices : bool = False ,
388420) -> xr .DataArray :
389421 """Levelized cost of energy (LCOE) of technologies over their lifetime.
390422
@@ -415,6 +447,8 @@ def levelized_cost_of_energy(
415447 consumption: xr.DataArray with commodity consumption by the relevant
416448 technologies
417449 method: "lifetime" or "annual"
450+ aggregate_timeslices: If True, the LCOE is aggregated over timeslices (result
451+ will not have a "timeslice" dimension)
418452
419453 Return:
420454 xr.DataArray with the LCOE calculated for the relevant technologies
@@ -425,15 +459,16 @@ def levelized_cost_of_energy(
425459 # Capital costs (lifetime or annual depending on method)
426460 _capital_costs = capital_costs (technologies , capacity , method )
427461
428- # Split capital costs across timeslices in proportion to production
429- tech_activity = production_amplitude (production , technologies )
430- _capital_costs = distribute_timeslice (
431- _capital_costs , ts = tech_activity , level = get_level (production )
432- )
462+ # Split capital costs across timeslices in proportion to production (if required)
463+ if not aggregate_timeslices :
464+ tech_activity = production_amplitude (production , technologies )
465+ _capital_costs = distribute_timeslice (
466+ _capital_costs , ts = tech_activity , level = get_level (production )
467+ )
433468
434469 # Running costs (annual)
435470 _running_costs = running_costs (
436- technologies , prices , capacity , production , consumption
471+ technologies , prices , capacity , production , consumption , aggregate_timeslices
437472 )
438473
439474 # Production (annual)
@@ -445,6 +480,8 @@ def levelized_cost_of_energy(
445480 "commodity"
446481 ) # TODO: is this the correct way to deal with multiple products?
447482 )
483+ if aggregate_timeslices :
484+ prod = prod .sum ("timeslice" )
448485
449486 # If method is lifetime, have to adjust running costs and production
450487 if method == "lifetime" :
@@ -453,7 +490,6 @@ def levelized_cost_of_energy(
453490
454491 # LCOE
455492 result = (_capital_costs + _running_costs ) / prod
456- assert "timeslice" in result .dims
457493 return result
458494
459495
@@ -520,7 +556,6 @@ def annual_to_lifetime(costs: xr.DataArray, technologies: xr.Dataset):
520556 """
521557 assert "year" not in costs .dims
522558 assert "year" not in technologies .dims
523- assert "timeslice" in costs .dims
524559 life = technologies .technical_life .astype (int )
525560 iyears = range (life .values .max ())
526561 years = xr .DataArray (iyears , coords = {"year" : iyears }, dims = "year" )
@@ -529,7 +564,8 @@ def annual_to_lifetime(costs: xr.DataArray, technologies: xr.Dataset):
529564 interest_rate = technologies .interest_rate ,
530565 mask = years <= life ,
531566 )
532- rates = broadcast_timeslice (rates , level = get_level (costs ))
567+ if "timeslice" in costs .dims :
568+ rates = broadcast_timeslice (rates , level = get_level (costs ))
533569 return (costs * rates ).sum ("year" )
534570
535571
0 commit comments