Skip to content

Commit 87e89b3

Browse files
SBTEconomics - call calculate_plant_costs
1 parent 7d1f8b5 commit 87e89b3

File tree

1 file changed

+1
-224
lines changed

1 file changed

+1
-224
lines changed

src/geophires_x/SBTEconomics.py

Lines changed: 1 addition & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -223,230 +223,7 @@ def Calculate(self, model: Model) -> None:
223223
self.Cgath.value = 1.15 * self.ccgathadjfactor.value * self._indirect_cost_factor * (
224224
(model.wellbores.nprod.value + model.wellbores.ninj.value) * 750 * 500. + self.Cpumps) / 1E6
225225

226-
# plant costs
227-
if (model.surfaceplant.enduse_option.value == EndUseOptions.HEAT
228-
and model.surfaceplant.plant_type.value not in [PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]): # direct-use
229-
if self.ccplantfixed.Valid:
230-
self.Cplant.value = self.ccplantfixed.value
231-
else:
232-
self.Cplant.value = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
233-
model.surfaceplant.HeatExtracted.value) * 1000. # 1.15 for 15% contingency
234-
235-
# absorption chiller
236-
elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: # absorption chiller
237-
if self.ccplantfixed.Valid:
238-
self.Cplant.value = self.ccplantfixed.value
239-
else:
240-
# this is for the direct-use part all the way up to the absorption chiller
241-
self.Cplant.value = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
242-
model.surfaceplant.HeatExtracted.value) * 1000. # 1.15 for 15% contingency
243-
if self.chillercapex.value == -1: # no value provided by user, use built-in correlation ($2500/ton)
244-
self.chillercapex.value = self._indirect_cost_factor * 1.15 * np.max(
245-
model.surfaceplant.cooling_produced.value) * 1000 / 3.517 * 2500 / 1e6 # $2,500/ton of cooling. 1.15 for 15% contingency
246-
247-
# now add chiller cost to surface plant cost
248-
self.Cplant.value += self.chillercapex.value
249-
250-
# heat pump
251-
elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP:
252-
if self.ccplantfixed.Valid:
253-
self.Cplant.value = self.ccplantfixed.value
254-
else:
255-
# this is for the direct-use part all the way up to the heat pump
256-
self.Cplant.value = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
257-
model.surfaceplant.HeatExtracted.value) * 1000. # 1.15 for 15% contingency
258-
if self.heatpumpcapex.value == -1: # no value provided by user, use built-in correlation ($150/kWth)
259-
self.heatpumpcapex.value = self._indirect_cost_factor * 1.15 * np.max(
260-
model.surfaceplant.HeatProduced.value) * 1000 * 150 / 1e6 # $150/kW. 1.15 for 15% contingency
261-
262-
# now add heat pump cost to surface plant cost
263-
self.Cplant.value += self.heatpumpcapex.value
264-
265-
# district heating
266-
elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING:
267-
if self.ccplantfixed.Valid:
268-
self.Cplant.value = self.ccplantfixed.value
269-
else:
270-
self.Cplant.value = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
271-
model.surfaceplant.HeatExtracted.value) * 1000. # 1.15 for 15% contingency
272-
273-
self.peakingboilercost.value = (self.peaking_boiler_cost_per_kW.quantity()
274-
.to('USD / kilowatt').magnitude
275-
* model.surfaceplant.max_peaking_boiler_demand.value
276-
/ 1000)
277-
278-
self.Cplant.value += self.peakingboilercost.value # add peaking boiler cost to surface plant cost
279-
280-
281-
else: # all other options have power plant
282-
if model.surfaceplant.plant_type.value == PlantType.SUB_CRITICAL_ORC:
283-
MaxProducedTemperature = np.max(model.surfaceplant.TenteringPP.value)
284-
if MaxProducedTemperature < 150.:
285-
C3 = -1.458333E-3
286-
C2 = 7.6875E-1
287-
C1 = -1.347917E2
288-
C0 = 1.0075E4
289-
CCAPP1 = C3 * MaxProducedTemperature ** 3 + C2 * MaxProducedTemperature ** 2 + C1 * MaxProducedTemperature + C0
290-
else:
291-
CCAPP1 = 2231 - 2 * (MaxProducedTemperature - 150.)
292-
x = np.max(model.surfaceplant.ElectricityProduced.value)
293-
y = np.max(model.surfaceplant.ElectricityProduced.value)
294-
if y == 0.0:
295-
y = 15.0
296-
z = math.pow(y / 15., -0.06)
297-
self.Cplantcorrelation = CCAPP1 * z * x * 1000. / 1E6
298-
299-
elif model.surfaceplant.plant_type.value == PlantType.SUPER_CRITICAL_ORC:
300-
MaxProducedTemperature = np.max(model.surfaceplant.TenteringPP.value)
301-
if MaxProducedTemperature < 150.:
302-
C3 = -1.458333E-3
303-
C2 = 7.6875E-1
304-
C1 = -1.347917E2
305-
C0 = 1.0075E4
306-
CCAPP1 = C3 * MaxProducedTemperature ** 3 + C2 * MaxProducedTemperature ** 2 + C1 * MaxProducedTemperature + C0
307-
else:
308-
CCAPP1 = 2231 - 2 * (MaxProducedTemperature - 150.)
309-
# factor 1.1 to make supercritical 10% more expansive than subcritical
310-
self.Cplantcorrelation = 1.1 * CCAPP1 * math.pow(
311-
np.max(model.surfaceplant.ElectricityProduced.value) / 15., -0.06) * np.max(
312-
model.surfaceplant.ElectricityProduced.value) * 1000. / 1E6
313-
314-
elif model.surfaceplant.plant_type.value == PlantType.SINGLE_FLASH:
315-
if np.max(model.surfaceplant.ElectricityProduced.value) < 10.:
316-
C2 = 4.8472E-2
317-
C1 = -35.2186
318-
C0 = 8.4474E3
319-
D2 = 4.0604E-2
320-
D1 = -29.3817
321-
D0 = 6.9911E3
322-
PLL = 5.
323-
PRL = 10.
324-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 25.:
325-
C2 = 4.0604E-2
326-
C1 = -29.3817
327-
C0 = 6.9911E3
328-
D2 = 3.2773E-2
329-
D1 = -23.5519
330-
D0 = 5.5263E3
331-
PLL = 10.
332-
PRL = 25.
333-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 50.:
334-
C2 = 3.2773E-2
335-
C1 = -23.5519
336-
C0 = 5.5263E3
337-
D2 = 3.4716E-2
338-
D1 = -23.8139
339-
D0 = 5.1787E3
340-
PLL = 25.
341-
PRL = 50.
342-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 75.:
343-
C2 = 3.4716E-2
344-
C1 = -23.8139
345-
C0 = 5.1787E3
346-
D2 = 3.5271E-2
347-
D1 = -24.3962
348-
D0 = 5.1972E3
349-
PLL = 50.
350-
PRL = 75.
351-
else:
352-
C2 = 3.5271E-2
353-
C1 = -24.3962
354-
C0 = 5.1972E3
355-
D2 = 3.3908E-2
356-
D1 = -23.4890
357-
D0 = 5.0238E3
358-
PLL = 75.
359-
PRL = 100.
360-
maxProdTemp = np.max(model.surfaceplant.TenteringPP.value)
361-
CCAPPLL = C2 * maxProdTemp ** 2 + C1 * maxProdTemp + C0
362-
CCAPPRL = D2 * maxProdTemp ** 2 + D1 * maxProdTemp + D0
363-
b = math.log(CCAPPRL / CCAPPLL) / math.log(PRL / PLL)
364-
a = CCAPPRL / PRL ** b
365-
# factor 0.75 to make double flash 25% more expansive than single flash
366-
self.Cplantcorrelation = (0.8 * a * math.pow(np.max(model.surfaceplant.ElectricityProduced.value), b) *
367-
np.max(model.surfaceplant.ElectricityProduced.value) * 1000. / 1E6)
368-
369-
elif model.surfaceplant.plant_type.value == PlantType.DOUBLE_FLASH:
370-
if np.max(model.surfaceplant.ElectricityProduced.value) < 10.:
371-
C2 = 4.8472E-2
372-
C1 = -35.2186
373-
C0 = 8.4474E3
374-
D2 = 4.0604E-2
375-
D1 = -29.3817
376-
D0 = 6.9911E3
377-
PLL = 5.
378-
PRL = 10.
379-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 25.:
380-
C2 = 4.0604E-2
381-
C1 = -29.3817
382-
C0 = 6.9911E3
383-
D2 = 3.2773E-2
384-
D1 = -23.5519
385-
D0 = 5.5263E3
386-
PLL = 10.
387-
PRL = 25.
388-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 50.:
389-
C2 = 3.2773E-2
390-
C1 = -23.5519
391-
C0 = 5.5263E3
392-
D2 = 3.4716E-2
393-
D1 = -23.8139
394-
D0 = 5.1787E3
395-
PLL = 25.
396-
PRL = 50.
397-
elif np.max(model.surfaceplant.ElectricityProduced.value) < 75.:
398-
C2 = 3.4716E-2
399-
C1 = -23.8139
400-
C0 = 5.1787E3
401-
D2 = 3.5271E-2
402-
D1 = -24.3962
403-
D0 = 5.1972E3
404-
PLL = 50.
405-
PRL = 75.
406-
else:
407-
C2 = 3.5271E-2
408-
C1 = -24.3962
409-
C0 = 5.1972E3
410-
D2 = 3.3908E-2
411-
D1 = -23.4890
412-
D0 = 5.0238E3
413-
PLL = 75.
414-
PRL = 100.
415-
maxProdTemp = np.max(model.surfaceplant.TenteringPP.value)
416-
CCAPPLL = C2 * maxProdTemp ** 2 + C1 * maxProdTemp + C0
417-
CCAPPRL = D2 * maxProdTemp ** 2 + D1 * maxProdTemp + D0
418-
b = math.log(CCAPPRL / CCAPPLL) / math.log(PRL / PLL)
419-
a = CCAPPRL / PRL ** b
420-
self.Cplantcorrelation = (a * math.pow(np.max(model.surfaceplant.ElectricityProduced.value), b) *
421-
np.max(model.surfaceplant.ElectricityProduced.value) * 1000. / 1E6)
422-
423-
if self.ccplantfixed.Valid:
424-
self.Cplant.value = self.ccplantfixed.value
425-
self.CAPEX_cost_electricity_plant = self.Cplant.value * self.CAPEX_heat_electricity_plant_ratio.value
426-
self.CAPEX_cost_heat_plant = self.Cplant.value * (1.0 - self.CAPEX_heat_electricity_plant_ratio.value)
427-
else:
428-
# 1.02 to convert cost from 2012 to 2016 #factor 1.15 for 15% contingency and factor 1.10 to convert from 2016 to 2022
429-
self.Cplant.value = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * self.Cplantcorrelation * 1.02 * 1.10
430-
self.CAPEX_cost_electricity_plant = self.Cplant.value
431-
432-
# add direct-use plant cost of co-gen system to Cplant (only of no total Cplant was provided)
433-
if not self.ccplantfixed.Valid: # 1.15 below for contingency
434-
if model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY,
435-
EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT]: # enduse_option = 3: cogen topping cycle
436-
self.CAPEX_cost_heat_plant = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
437-
model.surfaceplant.HeatProduced.value / model.surfaceplant.enduse_efficiency_factor.value) * 1000.
438-
elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT,
439-
EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY]: # enduse_option = 4: cogen bottoming cycle
440-
self.CAPEX_cost_heat_plant = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
441-
model.surfaceplant.HeatProduced.value / model.surfaceplant.enduse_efficiency_factor.value) * 1000.
442-
elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY,
443-
EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT]: # cogen parallel cycle
444-
self.CAPEX_cost_heat_plant = self._indirect_cost_factor * 1.15 * self.ccplantadjfactor.value * 250E-6 * np.max(
445-
model.surfaceplant.HeatProduced.value / model.surfaceplant.enduse_efficiency_factor.value) * 1000.
446-
447-
self.Cplant.value = self.Cplant.value + self.CAPEX_cost_heat_plant
448-
if not self.CAPEX_heat_electricity_plant_ratio.Provided:
449-
self.CAPEX_heat_electricity_plant_ratio.value = self.CAPEX_cost_electricity_plant/self.Cplant.value
226+
self.calculate_plant_costs(model)
450227

451228
if not self.totalcapcost.Valid:
452229
# exploration costs (same as in Geophires v1.2) (M$)

0 commit comments

Comments
 (0)