# -*- coding: utf-8 -*-
"""
Calculating costs for equipment
SI units input is only implemented for the Towler method and the limits are
checked now for Towler! (BA 2025-08-14/15)
Created on Wed Jul 31 13:59:25 2024
@author: Mina Anton, Majid Zarif
"""
import numpy as np
import pandas as pd
import datetime
import sys
import warnings
import carbatpy as cb
from pathlib import Path
# Pfad zur Excel-Datei
[docs]
DIR = Path(cb.CB_DEFAULTS["General"]['CB_DATA'])
_EXCEL_FILE = str(DIR / "Capital_Investment_Methods_ba.xlsx")
# Speicherstrukturen: Dict mit {sheetname: {"columns": [...], "values": np.array([...])}}
_CAP_DATA = {}
try:
[docs]
xl_data = pd.ExcelFile(_EXCEL_FILE, engine="openpyxl")
for sheet in ["Couper Method", "Turton Method", "Towler Method", "CEPCI data"]:
df = xl_data.parse(sheet)
_CAP_DATA[sheet] = {
"columns": list(df.columns),
"values": df.values,
"df": df,
}
cols = _CAP_DATA["Towler Method"]["columns"]
_Towler_unit_col_indices = [
i for i, col in enumerate(cols)
if str(col).lower().startswith("unit")]
except Exception as e:
print(f"Error loading Excel file: {e}")
[docs]
class CAP_methods:
def __init__(self):
# Direktes Zuweisen der vorbereiteten Daten
[docs]
self.Couper_columns = _CAP_DATA["Couper Method"]["columns"]
[docs]
self.Couper_xl_data = _CAP_DATA["Couper Method"]["values"]
[docs]
self.Turton_columns = _CAP_DATA["Turton Method"]["columns"]
[docs]
self.Turton_xl_data = _CAP_DATA["Turton Method"]["values"]
[docs]
self.Towler_columns = _CAP_DATA["Towler Method"]["columns"]
[docs]
self.Towler_xl_data = _CAP_DATA["Towler Method"]["values"]
[docs]
self.Towler_df = _CAP_DATA["Towler Method"]["df"]
[docs]
self.Towler_unit_col_index = _Towler_unit_col_indices[0]
[docs]
self.CEPCI_columns = _CAP_DATA["CEPCI data"]["columns"]
[docs]
self.CEPCI_xl_data = _CAP_DATA["CEPCI data"]["values"]
[docs]
self.warn = {'value': 0,
'message': 'All o.k.'}
def _Find_Present_Cost(self, BaseCost, BaseYear, plot=False, Current_year=True, Desired_year=None):
"""
Function used to adjust the cost of a component to the present day, accounting for inflation. It uses the
CEPCI (Chemical Engineering cost index data).
Parameters
----------
BaseCost : TYPE, Float.
DESCRIPTION: Cost of the compoenent based on the year the correlation is published.
BaseYear : TYPE, Float.
DESCRIPTION: Year the correlation for the cost estimate is published.
plot : TYPE, optional.
DESCRIPTION. The default is True. Plots the CEPCI vs year.
Current_year : TYPE, Boolean, optional.
DESCRIPTION : The default is True. Should the CEPCI cost index be taken relative to the current year.
Desired_year : TYPE, Float, optional.
DESCRIPTION : The default is None. If you choose False for Current_year, what year do you want
the cost index to be relative to.
Returns
-------
costPresent : TYPE, Float.
DESCRIPTION: Present day cost of the component, accounting for inflation.
"""
# Finds the year for todays date
if Current_year == True:
year = datetime.datetime.now().year
else:
if Desired_year is not None:
year = Desired_year
else:
raise ValueError(
"Desired year is not provided although Current year was set to False")
# Find the current and past cost index for the component
if year in self.CEPCI_xl_data[:, 0]:
index_present = self.CEPCI_xl_data[np.where(
self.CEPCI_xl_data[:, 0] == year), 1]
index_data = self.CEPCI_xl_data[np.where(
self.CEPCI_xl_data[:, 0] == BaseYear), 1]
# Check if present date has a cost index in CECPI
else:
print("\nerror: no cost index data for ", year)
sys.exit()
if plot:
print("\ncost index ratio: ", index_present[0][0], "/", index_data[0]
[0], " = ", np.round((index_present/index_data)[0][0], 2), "\n")
costPresent = float(BaseCost*(index_present[0][0]/index_data[0][0]))
return costPresent
def _Couper_Method(self, Comp_dict, verbose=False, Desired_year=None):
"""
Estimate component costs based on Couper et al. (2012).
Calculates the installed cost of individual components using techniques
from Chapter 21 in 'Chemical Process Equipment, Third Edition'. The
estimate accounts for operational pressure, inflation (via cost indices),
and materials of construction.
Parameters
----------
Comp_dict : dict
Variables required for the cost estimate. Required keys depend on
the component category.
Example::
{
"Category": "pumps",
"Component Name": "centrifugal",
"Power": 10.5, # in kW
"Area": 50.0, # in m2
"Pressure": 10.0, # in barg (gauge)
"Volume": 5.0, # in m3
"Volume Flow Rate": 0.1,
"Head": 100.0
}
verbose : bool, optional
If True, prints detailed calculation steps and explanations.
The default is False.
Desired_year : int or float, optional
The target year for the cost index adjustment. If None, the
most recent available index is used.
Raises
------
ValueError
If the 'Component Name' is not found in the reference database
(Excel sheet).
Returns
-------
float
The installed cost of the component adjusted for inflation and
technical factors.
Notes
-----
* SI-unit input is not fully implemented yet.
* Operating limits for the equipment are not checked.
* Pressure values for certain methods must be in gauge (100 kPa ≈ 1 atm).
"""
self.Component_category = Comp_dict.get("Category")
self.Component_name = Comp_dict.get("Component Name")
self.Power = Comp_dict.get("Power")
self.Area = Comp_dict.get("Area")
self.Pressure = Comp_dict.get("Pressure")
self.Volume = Comp_dict.get("Volume")
self.Q = Comp_dict.get("Volume Flow Rate")
self.h = Comp_dict.get("Head")
# Finds row corresponding to component and checks if component is available in this method
index = np.where(self.Couper_xl_data[:, 1] == self.Component_name)[0]
if index.size == 0:
raise ValueError(
"Component name is not found in the Couper method")
# Array index contains the row for the component
# Finds values needed for the cost estimation for the component
Component_row = self.Couper_xl_data[index[0]]
a = float(Component_row[2])
b1 = float(Component_row[3])
b2 = float(Component_row[4])
b3 = float(Component_row[5])
n = float(Component_row[6])
iF = float(Component_row[7])
fm = float(Component_row[8])
ccF = float(Component_row[9])
cF = float(Component_row[13])
cF2 = float(Component_row[17])
yr = float(Component_row[18])
fd = None
fp = None
# Calculate cost of compressor
if self.Component_category == "Compressor":
HP = self.Power * cF
CI = a * (HP**n) * iF * ccF * 1000
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Power} KW. The price of the component using Couper Method : {CI} euro")
return float(CI)
# Calculate cost of turbines
elif self.Component_category == "Turbine":
HP = self.Power * cF
CI = a * (HP**n) * iF * ccF * 1000
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Power} KW. The price of the component using Couper Method : {CI} euro ")
return float(CI)
# Calculate cost of shell and tube heat exchangers
elif self.Component_category == "Heat Exchanger S/T":
Area_sqft = self.Area * cF
if "Shell and Tube, Fixed Head" in self.Component_name:
fd = np.exp(-1.1156 + 0.0906 * np.log(Area_sqft))
elif "Shell and Tube, Kettle Reboiler" in self.Component_name:
fd = 1.35
elif "Shell and Tube, U Tube" in self.Component_name:
fd = np.exp(-0.9816 + 0.0830 * np.log(Area_sqft))
if 689.476 <= self.Pressure <= 2068.43:
fp = 0.7771 + 0.04981 * np.log(Area_sqft)
elif 2068.43 < self.Pressure <= 4136.85:
fp = 1.0305 + 0.07140 * np.log(Area_sqft)
elif 4136.85 < self.Pressure <= 6205.28:
fp = 1.1400 + 0.12088 * np.log(Area_sqft)
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Couper method")
Fm = b1 + b2 * np.log(Area_sqft)
Cb = np.exp(8.821 - 0.30863 * np.log(Area_sqft) +
0.0681 * (np.log(Area_sqft) ** n))
CI = a * fd * Fm * fp * Cb * ccF * iF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Pressure} KPa and {self.Area} m^2. The price of the component using Couper Method : {CI} euro ")
return float(CI)
# Calculate cost of double pipe heat exchnagers
elif self.Component_category == "Heat Exchanger D/P":
Area_sqft = self.Area * cF
if self.Pressure <= 400:
fp = 1
elif 400 < self.Pressure <= 600:
fp = 1.10
elif 600 < self.Pressure <= 700:
fp = 1.25
else:
print(
"The operational pressure for the double pipe heat exchanger is out of range for the Couper method")
CI = a * fm * fp * Area_sqft**n
CI = CI * iF * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Pressure} KPa and {self.Area} m^2. The price of the component using Couper Method : {CI} euro ")
return float(CI)
# Calculate cost of storage tanks
elif self.Component_category == "Shop Fabricated Storage Tank":
Volume_gal = self.Volume * cF
CI = a * fm * \
np.exp(2.631 + 1.3673 * np.log(Volume_gal) -
0.06309 * (np.log(Volume_gal))**n)
CI = CI * iF * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Volume} m^3. The price of the component using Couper Method : {CI} euro")
return float(CI)
# Calculate cost of centrifugal pumps
elif self.Component_category == "VSC Centrifugal Pump" or self.Component_category == "HSC Centrifugal Pump":
Q_gpm = self.Q * cF
h_ft = self.h * cF2
Cb = 3.00 * np.exp(8.833 - 0.6019 * np.log(Q_gpm * np.sqrt(h_ft)
) + 0.0519 * (np.log(Q_gpm * np.sqrt(h_ft)))**n)
ft = np.exp(b1 + b2 * np.log(Q_gpm * np.sqrt(h_ft)) +
b3 * np.log(Q_gpm * np.sqrt(h_ft))**n)
CI = fm * ft * Cb * ccF * iF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Q} m^3/s and {self.h} m. The price of the component using Couper Method : {CI} euro ")
return float(CI)
# Calculate cost of recipocating pumps
elif self.Component_category == "Pump":
print(
"The costs produced for Reciprocating pumps using Couper Methods are unexpectedly high")
Q_gpm = self.Q * cF
CI = a * fm * (Q_gpm**n)
CI = CI * iF * ccF * 1000
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.Q} m^3/s. The price of the component using Couper Method : {CI} euro ")
return float(CI)
[docs]
def Towler_Method(self, Comp_dict, verbose=False, Desired_year=None):
"""
Cost estimation according to Towler and Gavin (2012).
Calculates costs based on "Chemical engineering design: principles,
practice and economics of plant and process design".
The estimation follows the power-law relation:
.. math::
C_e = a + b \cdot S^n
Parameters
----------
Comp_dict : dict
Dictionary containing variables for the cost estimate.
Example::
{
"Category": "Compressor",
"Component Name": "hydrogen compressor",
"Component Attribute": 1000
}
CI : float
Capital investment of the investigated component.
S : float
Capacity of the investigated component.
n : float
Cost exponent (typically :math:`n < 1` to account for economies of scale).
a : float
Constant base value for known device costs.
b : float
Proportionality constant for device costs.
verbose : bool, optional
If True, prints values and explanations. The default is False.
Desired_year : float, optional
Target year for the cost index relative to the current year.
If None, the current year index is used.
Raises
------
ValueError
If the component name is not found in the Towler method database.
Returns
-------
float
The installed cost of the component, adjusted for inflation,
operational pressure, and material of construction.
Notes
-----
SI-unit input is implemented and limits are checked. (Updated: 2025-08-15)
"""
self.Component_category = Comp_dict.get("Category")
self.Component_name = Comp_dict.get("Component Name")
self.S = Comp_dict.get("Component Attribute")
# Finds row corresponding to component and checks if component is available in this method
index = np.where(self.Towler_xl_data[:, 1] == self.Component_name)[0]
if index.size == 0:
raise ValueError(
"Component name is not found in the Towler method")
# Array index contains the row for the component
# Finds values needed for the cost estimation for the component
Component_row = self.Towler_xl_data[index[0]]
if Component_row[self.Towler_unit_col_index] in ("kW", "KW", "kPa", "KPa"):
self.S = self.S/1000 # SI units, BA
elif Component_row[self.Towler_unit_col_index] in ("l/s", "L/s"):
self.S = self.S * 1000 # SI units, BA
#limits = self.get_values_by_name(self.Component_name)
self.check_value_within_limits(self.Component_name, self.S, verbose)
a = float(Component_row[2])
b = float(Component_row[3])
n = float(Component_row[4])
yr = float(Component_row[6])
iF = float(Component_row[7])
fm = float(Component_row[8])
fl = float(Component_row[9])
cF = float(Component_row[10])
# Calculates cost of compoennt
CI = a + b * (np.abs(self.S)**n)
CI = self._Find_Present_Cost(CI, yr, plot=verbose, Current_year=(
Desired_year is None), Desired_year=Desired_year) * iF * fm * fl * cF
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units). The price of the component using Towler Method : {CI} euro ")
return float(CI)
[docs]
def get_values_by_name(self, name_value, columns=None, df=None):
"""
Retrieve the values of specific columns for the row matching a given 'name' value.
Parameters
----------
name_value : str
The value to search for in the 'name' column.
columns : list of str, optional
List of column names whose values should be returned.
Defaults to ["S_lower", "S_upper"] if not provided.
df : pandas.DataFrame, optional
DataFrame in which to search. Defaults to self.Towler_df if not provided.
Returns
-------
dict or None
A dictionary mapping each requested column name to its value for the matching row,
or None if no matching row is found.
Notes
-----
- If multiple rows have the same 'name', only the first match is returned.
- This method is flexible and can be used with any DataFrame and column list.
"""
if df is None:
df = self.Towler_df
if columns is None:
columns = ["S_lower", "S_upper"]
row = df.loc[df["name"] == name_value]
if row.empty:
return None
return {col: row.iloc[0][col] for col in columns}
import warnings
[docs]
def check_value_within_limits(self, name_value, value, verbose,
lower_col="S_lower", upper_col="S_upper",
df=None, error=False):
"""
Check if a given value lies within predefined limits from a DataFrame entry.
Parameters
----------
name_value : str
The value to search for in the 'name' column of the DataFrame.
value : float
The numeric value to be checked.
lower_col : str, optional
Column name for the lower limit. Default is "S_lower".
upper_col : str, optional
Column name for the upper limit. Default is "S_upper".
df : pandas.DataFrame, optional
DataFrame to search in. Defaults to self.Towler_df.
error : bool, optional
If True, raises a ValueError when the value is out of range.
If False, issues a UserWarning instead.
Returns
-------
bool
True if the value is within limits or if no limits are defined.
False if the value is out of range.
Notes
-----
- If the limits are missing or NaN, the check passes automatically.
- If multiple rows match `name_value`, only the first is used.
"""
self.warn = {'value': 0,
'message': 'All o.k.'}
if df is None:
df = self.Towler_df
limits = self.get_values_by_name(
name_value, columns=[lower_col, upper_col], df=df)
if limits is None:
return True # No matching row → OK
lower = limits.get(lower_col, None)
upper = limits.get(upper_col, None)
# If limits are missing or NaN → treat as OK
if lower is None or upper is None or np.isnan(lower) or np.isnan(upper):
return True
if not (lower <= value <= upper):
if verbose:
msg = (f"Value {value} is outside allowed range [{lower}, {upper}] "
f"for component '{name_value}'. The returned value is an extrapolation")
self.warn = {'value': value/(lower + 1),
'message': msg}
if error:
raise ValueError(msg)
else:
with warnings.catch_warnings():
warnings.simplefilter("always") # Oder "default"
warnings.warn(msg, UserWarning)
return False
return True
def _Turton_Method(self, Comp_dict, verbose=False, Desired_year=None):
"""
Cost estimation according to:
Turton, R. (2003). Analysis, synthesis, and design of Chemical Processes. Prentice Hall.
SI-unit input not implemented yet! Limits are not checked! BA 2025-08-15
Parameters
----------
Comp_dict : dict # <-- TYPE, Dictionary entfernt
Contains input parameters for the Turton method. # <-- DESCRIPTION entfernt
Example:: # <-- Code-Block hinzugefügt
{
"Category": "Pump",
"Component Name": "Centrifugal Pump, Cast iron",
"Component Attribute": 200,
"Pressure": 1000
}
verbose : bool, default=False # <-- Boolean ersetzt
Print values with explanation if True. # <-- Beschreibung verbessert
Desired_year : float, optional # <-- Float okay, Punkt entfernt
Target year for cost index (current year if None). # <-- Gekürzt
Returns
-------
float # <-- String ersetzt
Equipment cost adjusted for inflation, pressure, and materials.
"""
self.Component_category = Comp_dict.get("Component Catgeory")
self.Component_name = Comp_dict.get("Component Name")
self.S = Comp_dict.get("Component Attribute")
self.Pressure = Comp_dict.get("Pressure")
# Finds row corresponding to component and checks if component is available in this method
index = np.where(self.Turton_xl_data[:, 1] == self.Component_name)[0]
if index.size == 0:
raise ValueError(
"Component name is not found in the Turton method")
# Array index contains the row for the component
# Finds values needed for the cost estimation for the component
Component_row = self.Turton_xl_data[index[0]]
K1 = float(Component_row[2])
K2 = float(Component_row[3])
K3 = float(Component_row[4])
B1 = float(Component_row[5])
B2 = float(Component_row[6])
n = float(Component_row[7])
fm = float(Component_row[8])
Fbm = float(Component_row[9])
ccF = float(Component_row[10])
cF2 = float(Component_row[18])
yr = float(Component_row[19])
fp = None
c1 = None
c2 = None
c3 = None
# Calculates the base cost of components, assuming ambient pressure and cs construction
Cp_0 = K1 + K2 * np.log10(self.S) + K3 * (np.log10(self.S))**n
Cp_0 = 10**Cp_0
if any(x in self.Component_name for x in ["Compressor", "Turbine", "Liquid Expanders"]):
CI = Cp_0 * Fbm * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif any(x in self.Component_name for x in ["Fixed Tube", "Floating Head", "U Tube"]):
if self.Pressure <= 500:
fp = 1
elif 500 < self.Pressure <= 14000:
c1 = -0.00164
c2 = -0.00627
c3 = -0.0123
fp = c1 + c2 * np.log10(self.Pressure*cF2) + \
c3 * (np.log10(self.Pressure*cF2))**n
fp = 10**fp
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif "Double Pipe" in self.Component_name:
if self.Pressure <= 4000:
fp = 1
elif 4000 < self.Pressure <= 10000:
c1 = 0.6072
c2 = -0.9120
c3 = 0.3327
fp = c1 + c2 * np.log10(self.Pressure*cF2) + \
c3 * (np.log10(self.Pressure*cF2))**n
fp = 10**fp
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif "Flat Plate" in self.Component_name:
if self.Pressure < 1900:
fp = 1
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif "Centrifugal Pump" in self.Component_name:
if self.Pressure <= 1000:
fp = 1
elif 1000 < self.Pressure <= 10000:
c1 = -0.3935
c2 = -0.3957
c3 = -0.00226
fp = c1 + c2 * np.log10(self.Pressure*cF2) + \
c3 * (np.log10(self.Pressure*cF2))**n
fp = 10**fp
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif any(x in self.Component_name for x in ["Positive Displacement Pump", "Reciprocating Pump"]):
if self.Pressure <= 1000:
fp = 1
elif 1000 < self.Pressure <= 10000:
c1 = -0.245382
c2 = 0.259016
c3 = -0.01363
fp = c1 + c2 * np.log10(self.Pressure*cF2) + \
c3 * (np.log10(self.Pressure*cF2))**n
fp = 10**fp
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
elif any(x in self.Component_name for x in ["Floating Roof", "Fixed Roof"]):
if self.Pressure <= 7:
fp = 1
else:
print(
"The operational pressure for the shell and tube heat exchanger is out of range for the Turton method")
CI = Cp_0 * (B1 + (B2*fm*fp))
CI = CI * ccF
CI = self._Find_Present_Cost(CI, yr, plot=False, Current_year=(
Desired_year is None), Desired_year=Desired_year)
if verbose == True:
print(
f"The name of this component is {self.Component_name}. The component attriute is {self.S} (units) and {self.Pressure} KPa. The price of the component using Turton Method : {CI} euro ")
return float(CI)
_cost_instance: CAP_methods | None = None
[docs]
def get_cost_inst() -> CAP_methods:
"""Return module-level CAP_methods singleton (lazy init)."""
global _cost_instance
if _cost_instance is None:
_cost_instance = CAP_methods()
return _cost_instance
"========================================== TEST RUN. =============================================="
if __name__ == "__main__":
Comp_dict = {
"Category": "Compressor",
"Component Name": "centrifugal compressor cs",
"Component Attribute": 76000, # SI units, Watt!
}
Cost_comp_couper_method = Eco.Towler_Method(
Comp_dict, verbose=False, Desired_year=2024)
print(f'Costs: {Cost_comp_couper_method:.3e}', Comp_dict, Eco.warn)