Exergoeconomic Analysis¶
Exergoeconomic analysis provides a systematic methodology to quantify both the thermodynamic performance and the associated economic costs of energy‐conversion systems. Building upon exergy analysis, which accounts for irreversibilities and the quality of energy, exergoeconomics introduces cost formulation rules to allocate monetary values to all exergy streams entering and leaving each component [2]. This approach enables the identification of cost‐intensive inefficiencies, guiding optimal design and operation decisions to minimize total exergy consumption and expenses. The theory described in this section follows the Specific Exergy Costing (SPECO) method as presented by Lazzaretto and Tsatsaronis (2006) [33].
Where this step fits: step 5 of the workflow
Step |
Needs |
Gives |
Examples |
|
|---|---|---|---|---|
1 |
a model from Ebsilon, Aspen Plus, TESPy or JSON; fuel, product and loss of the plant |
\(\dot{E}_\mathrm{F}\), \(\dot{E}_\mathrm{P}\), \(\dot{E}_\mathrm{D}\) and \(\varepsilon\) of every component |
||
2 |
Component sizing, only where a cost is estimated from the size |
the analysed plant; heat transfer coefficients for the heat exchangers |
the size a cost function takes, for example power, heat transfer area or heat flow |
|
3 |
known costs, costs of reference components, user-defined cost equations or the correlations of OpenPyTEA |
the purchased equipment cost of every component and its reference year |
||
4 |
the purchased equipment costs; rate of return, lifetime, operating hours, fuel prices |
the cost rate \(\dot{Z}\) of every component and the levelized costs of the fuels |
||
5 |
the results of steps 1 and 4 |
the cost of every stream; \(c_\mathrm{F}\), \(c_\mathrm{P}\), \(\dot{C}_\mathrm{D}\), \(f\) and \(r\) of every component |
Steps 1 and 5 are enough where the cost rates \(\dot{Z}\) are known; steps 2 to 4 obtain them from the equipment costs.
Fundamentals of exergoeconomic analysis¶
Exergoeconomic analysis couples the first and second laws of thermodynamics with cost accounting principles. Each exergy stream—whether associated with material, work, or heat transfer—is assigned a cost rate, and cost balances are formulated for every component.
In this framework, we define:
\(\dot{C}_{i}\) and \(\dot{C}_{e}\) as the cost rates associated with exergy streams entering and exiting a component, respectively,
\(\dot{C}_{w}\) as the cost rate associated with work flow,
\(\dot{C}_{q}\) as the cost rate associated with heat transfer.
The component cost balance is [2]:
\[\sum_i \dot{C}_{i,k} + \dot{C}_{q,k} + \dot{Z}_k = \sum_e \dot{C}_{e,k} + \dot{C}_{w,k}\]
where \(\dot{Z}_k\) represents the total charges due to capital investment and operating and maintenance costs.
Two fundamental principles govern the auxiliary costing equations [33]:
F principle: For each exergy removal from a fuel stream, the unit cost remains equal to the average cost at which that exergy was supplied by upstream components.
P principle: All exergy added to product streams is assigned the same unit cost, denoted \(c_P\), determined from the component cost balance and the F equations.
Costs are assigned to exergy, \(\dot{C} = c \cdot \dot{E}\) [33], so a stream without exergy of a share \(x\) (thermal, mechanical, physical or chemical) carries no cost of that share. Where an auxiliary equation equates specific costs and one of the two streams has no exergy of the share, ExerPy writes \(\dot{C}^{x}_\mathrm{out} = 0\) instead, for the outlet without exergy, or for the outlet of the equation if the inlet has none. An inlet is never fixed, since its cost is set upstream. In the mixing rule of a mixer or deaerator, an inlet without exergy of the share adds nothing, and an outlet without it gets \(\dot{C}^{x}_\mathrm{out} = 0\).
Terminology¶
The definitions and symbols used in exergoeconomic analysis are summarized below:
Variable |
Name |
Symbol |
Description |
|---|---|---|---|
|
(specific) inlet cost |
\(c_i\), \(\dot{C}_i\) |
(specific) cost flow rate of an entering exergy stream |
|
(specific) outlet cost |
\(c_e\), \(\dot{C}_e\) |
(specific) cost flow rate of an exiting exergy stream |
|
(specific) work cost |
\(c_w\), \(\dot{C}_w\) |
(specific) cost rate associated with work flow |
|
(specific) heat cost |
\(c_q\), \(\dot{C}_q\) |
(specific) cost rate associated with heat transfer |
|
(specific) product cost |
\(c_P\), \(\dot{C}_P\) |
(specific) cost rate of the product exergy stream |
|
(specific) fuel cost |
\(c_F\), \(\dot{C}_F\) |
(specific) cost rate of the fuel exergy stream |
|
cost of exergy destruction |
\(\dot{C}_D\) |
cost rate associated with exergy destruction |
|
cost of exergy loss |
\(\dot{C}_L\) |
cost rate associated with exergy loss |
|
exergoeconomic factor |
\(f_k\) |
ratio of non-thermodynamic costs to total component cost |
|
relative cost difference |
\(r_k\) |
normalized increase of product over fuel unit cost |
|
charges |
\(\dot{Z}\) |
sum of capital and O&M cost rates |
|
charged dissipative cost |
\(\dot{Z}_\mathrm{diss}\) |
share of the cost of the dissipative components charged to the component |
Note
The auxiliary costing equations derived from the F and P principles, together with the component cost balance, form a solvable linear system that yields the cost rates for all exergy streams in the system, see How the equation system is built and solved.
Exergoeconomic metrics and indicators¶
After solving the SPECO equations for all cost rates, several exergoeconomic indicators are computed to assess the economic impact of irreversibilities in each component. Three key metrics are:
Cost rate of exergy destruction
The cost associated with thermodynamic inefficiencies in component k is
\[\dot{C}_{\mathrm{D},k} = c_{\mathrm{F},k}\,\dot{E}_{\mathrm{D},k}\]
where \(c_{\mathrm{F},k}\) is the specific cost of the fuel exergy of component k and \(\dot{E}_{\mathrm{D},k}\) its exergy destruction rate [2].
Exergoeconomic factor
The fraction of a component’s total cost arising from investment and O&M (non-thermodynamic) charges is
\[f_k = \frac{\dot{Z}_k}{\dot{Z}_k + \dot{C}_{\mathrm{D},k}}\]
with the investment and O&M cost rate \(\dot{Z}_k\) of the component only [2]. The share \(\dot{Z}_{\mathrm{diss},k}\) of the cost of the dissipative components that is charged to component k, in proportion to its exergy destruction, enters its cost balance and thus its \(c_{\mathrm{P},k}\) and \(r_k\) [33]. It is not part of \(f_k\), since it is neither the investment of the component nor the cost of its exergy destruction.
A high \(f_k\) indicates that capital and O&M dominate the cost, suggesting a focus on reducing \(\dot{Z}_k\). A low \(f_k\) signals that inefficiencies (exergy destruction) are the primary cost drivers [2].
Relative cost difference
The relative increase in specific cost from fuel to product exergy for component k is
\[r_k = \frac{c_{\mathrm{P},k} - c_{\mathrm{F},k}}{c_{\mathrm{F},k}}\]
where \(c_{\mathrm{P},k}\) and \(c_{\mathrm{F},k}\) are the specific product and fuel costs. Lowering \(r_k\) through efficiency improvements is recommended for cost optimization [2].
How the equation system is built and solved¶
The cost rates of all streams follow from one linear equation system \(A\,\dot{C} = b\), with one unknown per cost variable and one row per equation. ExerPy builds it from the analysed plant and the cost dictionary, solves it and then derives the indicators of every component.
The cost variables¶
Every stream that touches a component of the plant carries cost variables:
a material stream one per share of its exergy: \(\dot{C}^\mathrm{T}\) and \(\dot{C}^\mathrm{M}\) with split physical exergy, \(\dot{C}^\mathrm{PH}\) without it, and \(\dot{C}^\mathrm{CH}\) in addition when chemical exergy is enabled;
a heat or power stream one, \(\dot{C}^\mathrm{TOT}\);
a dissipative component one more, the cost \(\dot{C}_\mathrm{diff}\) of the exergy it destroys without a product, and a storage one for the exergy it puts into or takes out of its store.
The equations¶
Kind |
Rows |
What the row states |
|---|---|---|
|
one per component with a cost balance |
\(\sum \dot{C}_\mathrm{in} - \sum \dot{C}_\mathrm{out} = -\dot{Z}\); the splitter, the power bus, the cycle closer, the storage and dissipative components have none |
|
one per cost variable of every material or heat stream entering the plant, and of every power stream entering it with a given cost |
the cost given in the cost dictionary, \(\dot{C} = c\,\dot{E}\); a material stream gets the same specific cost for each of its shares |
|
one less than the number of power streams entering the plant |
all purchased power has the same specific cost |
|
written by the components |
F principle: exergy removed from a stream leaves at the specific cost it entered with |
|
written by the components |
P principle: every exergy added to the products of a component has the same specific cost |
|
written by the components |
a share that only passes through keeps its specific cost, for example the chemical exergy through a component without a reaction |
|
written by mixer, deaerator and combustion chamber |
the rules of a component that mixes streams, for the shares its cost balance does not cover |
|
written by dissipative components |
the main working fluid keeps its specific cost, the auxiliary fluid, such as cooling water, leaves without cost, and the cost of the destroyed exergy and of the auxiliary fluid, \(\dot{C}_\mathrm{diff}\), is charged to the productive components in proportion to their exergy destruction [33] |
The system is square by construction. A component with a cost balance writes one auxiliary row per cost variable of its outlets, less one, since its cost balance determines the last one; a dissipative component writes one row more and has no cost balance. Every stream inside the plant is the outlet of exactly one component, and every stream entering the plant gets its boundary rows, so the number of rows equals the number of cost variables. For the CGAM process with chemical exergy, for example:
split physical exergy |
without the split |
|
|---|---|---|
material streams × cost variables |
12 × 3 (T, M, CH) |
12 × 2 (PH, CH) |
heat and power streams |
3 |
3 |
dissipative component |
0 |
0 |
cost variables and rows |
39 |
27 |
of which cost balances, boundary rows, auxiliary rows |
7, 9, 23 |
7, 6, 14 |
The variables and the rows of a run can be listed by name:
eco.run(costs)
eco.print_variables() # {0: "C_1_PH", 1: "C_1_CH", 2: "C_10_PH", ...}
eco.print_equations() # {0: {"kind": "cost_balance", "object": ["CC"], ...}, ...}
Solving¶
run() solves the system with numpy.linalg.solve
and then
charges the cost of the exergy destroyed in dissipative components to the productive ones;
assigns every stream its cost rates and specific costs, \(c = \dot{C}/\dot{E}\) per share, and with the split \(\dot{C}^\mathrm{PH} = \dot{C}^\mathrm{T} + \dot{C}^\mathrm{M}\);
computes \(\dot{C}_\mathrm{F}\), \(\dot{C}_\mathrm{P}\), \(\dot{C}_\mathrm{D}\), \(r\) and \(f\) of every component;
checks the cost balance of every component and warns where one is not closed;
charges the cost of the loss streams to the product streams, in proportion to their net exergy (Bejan et al., Example 8.1) [2]. A stream subtracted in
E_P, such as the feedwater of a boiler, is paired with the product stream it turns into downstream, such as the steam. If it reaches no product stream or more than one, the gross exergy of the products is used and a warning names the stream;checks the cost balance of the whole plant, \(\dot{C}_\mathrm{P,tot} = \dot{C}_\mathrm{F,tot} + \sum \dot{Z}\), and raises an error where it is not closed.
What changes with the split of the physical exergy¶
With split_physical_exergy=True, the thermal and the mechanical exergy of a stream are costed
separately; without it, the physical exergy is costed as a whole.
Variables: a material stream has \(\dot{C}^\mathrm{T}\) and \(\dot{C}^\mathrm{M}\) instead of \(\dot{C}^\mathrm{PH}\), so the system has one variable more per stream, 39 instead of 27 for the CGAM process.
Rules: with the split, a component writes a rule for each share. A heat exchanger, for example, follows the F principle for the thermal exergy its hot stream gives off, while the mechanical exergy passes at its own specific cost. Without the split, the rules for the mechanical exergy fall away and the thermal rules apply to the physical exergy instead.
Results: the split lets the two shares of a stream carry different specific costs. A pump, for example, adds mechanical exergy at the cost of its product, while the thermal exergy of the stream keeps the cost it had. Without the split, both are averaged into one specific cost. The cost balances are met either way, but the specific costs of streams and components differ, see Split Physical Exergy in Exergoeconomics.
Below the ambient temperature only the split credits the cold exergy of a stream to the product of the component that produces it. Models whose streams lack the thermal and mechanical shares, such as a JSON input with the physical exergy only, are analysed without it.
Getting started with exergoeconomic analysis¶
Prerequisites¶
Before performing an exergoeconomic analysis, you need:
A completed exergy analysis
Component investment cost rates and specific costs of the input streams, given directly or obtained from the purchased equipment costs with the economic analysis, whose
compute_costs()returns them in the format below
Every component of ExerPy takes part in the exergoeconomic analysis. Two of them need an input that the thermodynamic model does not carry:
a combustion chamber needs the chemical exergy, so the exergy analysis has to run with a
chemExLib;a steam generator needs the temperature of its heat source in its
T_hotattribute, since that source is usually outside the model.
A simple heat exchanger may be given the temperature of its heat source or its heat consumer as well, see Heat from or to outside the model.
Note
With split_physical_exergy=True, the cost of a material stream is allocated to its
thermal and its mechanical exergy separately; with False, it is allocated to its physical
exergy as a whole. Both are supported, so models whose streams lack the thermal and mechanical
shares can be analysed as well. The two conventions do not give the same specific
costs; see What changes with the split and
Split Physical Exergy in Exergoeconomics.
Workflow overview¶
The exergoeconomic analysis in ExerPy follows four steps:
Perform the exergy analysis, here with the physical exergy split:
from exerpy import ExergyAnalysis, ExergoeconomicAnalysis
ean = ExergyAnalysis.from_json(model_path, chemExLib="Ahrendts", split_physical_exergy=True)
fuel = {"inputs": ["1", "10"], "outputs": []}
product = {"inputs": ["E1", "9"], "outputs": ["8"]}
loss = {"inputs": ["7"], "outputs": []}
ean.analyse(E_F=fuel, E_P=product, E_L=loss)
Create the exergoeconomic analysis instance:
eco = ExergoeconomicAnalysis(ean)
Define costs and run the analysis:
costs = {
# Component investment cost rates [EUR/h]
"AC_Z": 80,
"CC_Z": 30,
"EXP_Z": 100,
"GEN_Z": 40,
# Input stream specific costs [EUR/GJ]
"1_c": 0.0, # Ambient air (free)
"10_c": 10.0, # Natural gas fuel
"8_c": 0.5, # Feedwater
}
eco.run(costs)
The cost rates \(\dot{Z}\) and the specific costs of the entering streams can be typed in, as
above, or derived with the economic analysis: the purchased
equipment costs come from one of the four sources (known
costs, scaled costs of reference components, user-defined cost equations or the correlations of
OpenPyTEA), the total revenue requirement method turns them into \(\dot{Z}\), and
compute_costs() returns both in the format of the cost
dictionary:
from exerpy import EconomicAnalysis
economic = EconomicAnalysis(
PEC={
"AC": 1.2e6,
"CC": 4.0e5,
# ... the other components
},
fuel_costs={"1": 0.0, "10": 10.0, "8": 0.5}, # EUR/GJ, the streams entering the plant
# ... reference_year, base_year, cost_index and the parameters, see Economic Analysis
)
eco.run(economic.compute_costs(ean)) # the "_Z" and "_c" entries of the cost dictionary
From Equipment Costs to the Cost of the Product shows the whole way on a heat pump.
View results:
eco.exergoeconomic_results()
eco.evaluate_results()
Cost input format¶
The cost dictionary passed to run() requires two types of entries:
Key format |
Type |
Unit |
Description |
|---|---|---|---|
|
Component cost |
currency/h |
Investment and O&M cost rate for each component |
|
Stream cost |
currency/GJ |
Specific cost for each input stream crossing the system boundary |
A value can also be given in another unit, as long as it is in the currency of the analysis, e.g.
"10_c": 90.0, "10_c_unit": "EUR / MWh" or "COMP_Z": 0.0222, "COMP_Z_unit": "EUR / s".
A cost per day or per year is not accepted: turning it into a cost per hour of operation needs the
operating hours, which EconomicAnalysis takes into account.
A material stream entering the plant can also have a cost for each form of its exergy. In the SPECO
method, the cost rate of each exergy form (thermal, mechanical and chemical) of a material stream
supplied to the plant from outside is a known value of its own [33]. The keys
are "<connection_name>_c_T", "<connection_name>_c_M" and
"<connection_name>_c_CH", and "<connection_name>_c_PH" stands for the thermal and the
mechanical exergy together. Without the split of the physical exergy only "_c_PH" and
"_c_CH" apply. "_c_CH" is used only when the chemical exergy is part of the analysis.
A form without a cost of its own takes the "_c" of the stream, and each key can have its own
unit, e.g. "10_c_CH_unit".
Mandatory costs:
All components must have a
_Zcost, except theCycleCloser, thePowerBusand theSplitter. These pass their streams on without a cost balance of their own, so a cost given for one of them could not be charged to any stream and is rejected.All material and power/heat streams entering the system boundary must have a
_ccost. A material stream can have a cost for each of its exergy forms instead. For heat, what counts is the direction of its exergy, which below the ambient temperature is against the heat: heat that cools a stream below it (a chiller) needs a cost, heat taken in by such a stream (an evaporator) is priced by the component and needs none.
Examples:
"COMP_Z": 80.0— compressor investment cost of 80 EUR/h"1_c": 0.0— ambient air enters the system at zero cost"10_c": 25.0— natural gas enters the system at 25 EUR/GJ"10_c": 2.0, "10_c_CH": 10.0— the chemical exergy of stream 10 costs 10 EUR/GJ, its thermal and mechanical exergy 2 EUR/GJ
Interpreting results¶
After running the analysis, use exergoeconomic_results() to display the full results,
and evaluate_results() to identify the components with the highest cost improvement potential.
# Display all results (4 DataFrames)
df_comp, df_mat_props, df_mat_costs, df_non_mat = eco.exergoeconomic_results()
# Identify top components for optimization
eco.evaluate_results(sort_by="C_D+Z", top_n=5)
The component results table lists the cost rates and the indicators defined in
Exergoeconomic metrics and indicators. The components with the
largest total cost rate \(\dot{C}_\mathrm{D} + \dot{Z}\) are the most promising targets for an
improvement. The column Z holds the given cost rate of a component and Z_diss the share
of the cost of the dissipative components charged to it. C_D+Z and f leave
Z_diss out, since C_D+Z of the dissipative component already contains it. In the row
TOT, Z is the sum of the given cost rates only, since the charged shares stay inside the
plant, and C_D is \(c_\mathrm{F,tot}\,\dot{E}_\mathrm{D,tot}\), not the sum of the column,
since the cost of the exergy destruction of the plant cannot be found by adding the costs of the
components [2].
The evaluate_results() method accepts the following sort_by options:
"C_D+Z" (default), "C_D", "Z", "r", "f".
To verify the integrity of the solution, use check_cost_balance():
balances = eco.check_cost_balance(tol=1e-3)
for name, (residual, is_balanced) in balances.items():
print(f"{name}: residual={residual:.6f}, balanced={is_balanced}")
Note
Results depend on the auxiliary equations, and those are a modelling choice. Check the cost
balance of every component with
check_cost_balance() and validate the results
independently before basing a decision on them.
Troubleshooting¶
The messages below point to what is missing or wrong in the specification.
“Cost for component ‘…’” or “Cost for input connection ‘…’ is mandatory but not provided”
A "<name>_Z" or "<name>_c" entry is missing; Cost input format lists which components and streams need one. A stream entering
free of charge is given 0.0.
“Exergoeconomic system is singular (rank r/n)”
The rows do not determine all cost variables. ExerPy prints a dependency report, which can also be
called directly with print_dependency_report(). Read it
as follows:
Equations with no variables are rows that stayed empty: the system has fewer equations than cost variables. Look for warnings of the components at the start of the run, such as “not implemented” for a case a component does not cover or “No auxiliary equations provided”. A power stream entering the plant without a cost, in a plant that exports no power, leaves a row empty as well; give it a
"<name>_c".Variables never used are cost variables no row contains: a stream between components that have no cost balance, for example.
Exactly collinear pairs are two rows that state the same thing, for example two conditions on the same stream.
SVD dependencies list a group of rows that together are dependent. The components and streams named in these rows are where a rule is missing or doubled.
run(costs, allow_singular=True) returns a least-squares solution instead of an error. It is not
unique and may not be physically consistent; use it to inspect the system, not as a result.
“Exergoeconomic cost balance of the entire system is not satisfied”
Fuel, product and loss of the plant do not cover every stream that crosses the system boundary. The
exergy analysis warns about such streams (“The following system boundary connections are not included
in E_F, E_P, or E_L”); add each of them to E_F, E_P or E_L.
“Balance for component … not fulfilled”
The cost balance of a component is not closed after the solution, which points to a rule of that
component that contradicts its balance. Check it with
check_cost_balance().
“The solution of the cost matrix contains NaN values”
A stream carries no valid exergy value, for example a NaN in the export of the model. Check the
exergy of the streams in exergy_results().