exerpy.analyses

class exerpy.analyses.EconomicAnalysis(PEC, i_eff, n, tau, f_tci, omc_share, reference_year=None, base_year=None, cost_index=None, fuel_costs=None, omc_basis='PEC', r_n=0.05, currency='EUR', exergy_analysis=None)[source]

Bases: object

Turn the purchased equipment costs of a plant into the cost rates of its components.

The method is the total revenue requirement (TRR) method of Bejan et al. [2]. Every cost factor may be given once for the whole plant or separately per component, so a heat exchanger can carry a different installation effort from a motor:

\[\mathrm{PEC}_{\mathrm{base},j} = \mathrm{PEC}_j \cdot \frac{I_{y_\mathrm{base}}}{I_{y_{\mathrm{ref},j}}} \qquad \mathrm{TCI}_j = f_{\mathrm{TCI},j} \cdot \mathrm{PEC}_{\mathrm{base},j}\]
\[\dot{Z}^\mathrm{CC}_j = \frac{\mathrm{TCI}_j \cdot \mathrm{CRF}}{\tau} \qquad \dot{Z}^\mathrm{OM}_j = \frac{\mathrm{omc}_j \cdot \mathrm{PEC}_{\mathrm{base},j} \cdot \mathrm{CELF}}{\tau} \qquad \dot{Z}_j = \dot{Z}^\mathrm{CC}_j + \dot{Z}^\mathrm{OM}_j\]

A cost from an earlier year is carried to the base year with a plant cost index, \(I\), whose values are an input to the analysis.

The cost of the streams entering the plant is levelized the same way. A stream bought at \(c_0\) and escalating at its own nominal rate enters the exergoeconomic analysis at

\[c_\mathrm{L} = c_0 \cdot \mathrm{CELF}(r_{\mathrm{n},\mathrm{fuel}})\]

so the cost of the fuel and the cost of the equipment are levelized over the same lifetime and the specific cost of the product is a levelized cost too.

A purchased equipment cost may also be scaled from the cost of a reference component of the same type but a different size, taken from the literature or from a manufacturer, with the six-tenths rule of cost estimation:

\[\mathrm{PEC}_j = \mathrm{PEC}_{\mathrm{ref},j} \left(\frac{X_j}{X_{\mathrm{ref},j}}\right)^{\alpha_j}\]

The cost of the reference component is given at the price level of the reference_year of the component and carried to the base year with the plant cost index like any other.

Parameters:
  • PEC (dict) – Purchased equipment cost of every component, as {"<component>": cost}, in the currency of the analysis and at the price level of its reference_year. Instead of a cost, an entry may be {"PEC_ref": cost of the reference, "size_ref": size of the reference, "size": size, "exponent": alpha} to scale the cost of a reference component of the same type. size and size_ref are in the same units. Instead of size, size_by names the size the reference is given in, one of exerpy.costing.quantities(), for example "power" in W or "area" in m², and exergy_analysis provides the model it is read from with exerpy.costing.size(); an area takes exchanger_type (shell-and-tube by default) and U. exponent is 0.6 by default.

  • i_eff (float) – Effective rate of return \(i_\mathrm{eff}\), per year.

  • n (int) – Lifetime of the plant \(n\), in years.

  • tau (float) – Operating hours of the plant \(\tau\), per year. It scales every cost rate.

  • f_tci (float or dict) – Ratio of the total capital investment to the purchased equipment cost, for the whole plant or per component. It covers installation, piping, instrumentation, engineering, contingency, start-up and working capital.

  • omc_share (float or dict) – First-year operating and maintenance cost as a fraction of the purchased equipment cost or of the total capital investment, see omc_basis, for the whole plant or per component.

  • omc_basis (str, optional) – Whether omc_share is a fraction of the purchased equipment cost, "PEC", or of the total capital investment, "TCI". The two differ by the installation factor, so a share meant for one basis is badly wrong on the other. Default is "PEC".

  • reference_year (int or dict, optional) – Year whose price level a purchased equipment cost is given in, for the whole plant or per component. Default is the base year, so nothing is escalated and no cost index is needed.

  • base_year (int, optional) – Year every cost is carried to. Required as soon as any cost comes from a different year.

  • cost_index (dict, optional) – Plant cost index per year, as {year: index}. Only the ratio of two entries is used, so any consistent normalization works. Required as soon as costs come from more than one year. Where it does not reach the base year, the remaining years are bridged with r_n.

  • fuel_costs (dict, optional) – Specific cost of every stream entering the plant, as {"<connection>": {"c": value, "r_n": rate, "basis": "exergy" | "energy"}}. c is in currency per GJ at the price level of the base year, or in the unit c_unit in the same currency, e.g. "EUR / MWh"; r_n is the nominal escalation rate of that cost per year and defaults to that of the operating and maintenance cost, and basis says whether c is per unit of exergy (the default) or per unit of energy. A cost on the energy basis is converted with the flows of the stream, which are read from the exergy analysis unless the entry gives energy_flow and exergy_flow itself. An entry may be a plain number instead of a dictionary, which is read as its specific cost with everything else left at its default, so a stream entering free of charge is 0.0.

  • r_n (float, optional) – Nominal escalation rate of the operating and maintenance cost \(r_\mathrm{n}\), per year. Default is 0.05.

  • currency (str, optional) – Currency of the costs, used in the results tables. Default is “EUR”.

  • exergy_analysis (ExergyAnalysis, optional) – The analysed plant, to read the sizes a scaled purchased equipment cost leaves out.

Raises:

ValueError – If a required parameter is missing or not positive, if a per-component factor names a component without a purchased equipment cost, if the cost index does not cover a year that is used, or if a scaled cost lacks a value of its reference or its size.

See also

EconomicAnalysis.from_json

Read the same assumptions from a file instead.

EconomicAnalysis.compute_costs

The cost rates and the stream costs in one dictionary, ready

for

meth:ExergoeconomicAnalysis.run.

Examples

>>> from exerpy import EconomicAnalysis
>>> eco = EconomicAnalysis(
...     PEC={"COMP": 300000.0, "COND": 120000.0},
...     i_eff=0.12, n=20, tau=8000, f_tci=6.32, omc_share=0.015,
... )
>>> round(eco.compute_crf(), 5)
0.13388
>>> {name: round(value, 3) for name, value in eco.compute_z().items()}
{'COMP_Z': 32.548, 'COND_Z': 13.019}

A cost from an earlier year is carried to the base year:

>>> eco = EconomicAnalysis(
...     PEC={"COMP": 300000.0}, i_eff=0.12, n=20, tau=8000, f_tci=6.32, omc_share=0.015,
...     reference_year=2021, base_year=2024, cost_index={2021: 100.0, 2024: 125.0},
... )
>>> round(eco.base_PEC["COMP"], 1)
375000.0

A heat exchanger of 120 m² scaled from a reference of 80 m² that cost 100 000 in 2021:

>>> eco = EconomicAnalysis(
...     PEC={"COND": {"PEC_ref": 100000.0, "size_ref": 80.0, "size": 120.0}},
...     i_eff=0.12, n=20, tau=8000, f_tci=6.32, omc_share=0.015,
...     reference_year=2021, base_year=2024, cost_index={2021: 100.0, 2024: 125.0},
... )
>>> round(eco.PEC["COND"], 1), round(eco.base_PEC["COND"], 1)
(127542.5, 159428.1)
property TCI

Total capital investment, \(\sum_j f_{\mathrm{TCI},j}\,\mathrm{PEC}_{\mathrm{base},j}\).

property base_PEC

Purchased equipment cost of every component at the price level of the base year.

Every cost is carried from its year to the base year with escalation_factor(): with the plant cost index where it covers the years, with the nominal escalation rate beyond it, since an index is published for the past and not for the future.

\[\mathrm{PEC}_{\mathrm{base},j} = \mathrm{PEC}_j \cdot f\left(y_{\mathrm{ref},j}\right)\]
base_year_om_costs()[source]

Compute the operating and maintenance cost per component in money of the base year.

This is the cost at the start of the first year of operation, \(P_0\) in [2] (eq. 7.34); the payment for the first year is \((1 + r_n)\) times it, which the levelization accounts for. The share is taken of the purchased equipment cost or of the total capital investment, whichever omc_basis names. The two differ by the installation factor, so a share meant for one basis understates or overstates the cost badly when applied to the other:

\[\mathrm{OMC}_{0,j} = \mathrm{omc}_j \cdot \mathrm{PEC}_{\mathrm{base},j} \qquad \text{or} \qquad \mathrm{OMC}_{0,j} = \mathrm{omc}_j \cdot f_{\mathrm{TCI},j} \cdot \mathrm{PEC}_{\mathrm{base},j}\]
Returns:

dict – The operating and maintenance cost of every component in the base year, in currency per year.

compute_c(exergy_analysis=None)[source]

Return the levelized specific cost of every stream entering the plant.

The cost of a stream bought over the lifetime of the plant escalates, so the cost the exergoeconomic analysis works with is the levelized one:

\[c_\mathrm{L} = c_0 \cdot \mathrm{CELF}(r_{\mathrm{n},\mathrm{fuel}})\]

A cost given per unit of energy is converted to a cost per unit of exergy with the ratio of the two flows of that stream, since the exergoeconomic analysis costs exergy.

Parameters:

exergy_analysis (ExergyAnalysis, optional) – The analysis the costs are meant for. When it is given, every stream entering the plant has to have a cost, and a cost given for a stream that does not enter the plant is an error. The energy basis needs it as well, to read the flows of the stream.

Returns:

dict – {"<connection>_c": specific cost} in currency per GJ.

Raises:

ValueError – If the streams of the analysis and the given costs do not match, or if a cost on the energy basis belongs to a stream whose energy flow is unknown.

compute_celf(r_n=None)[source]

Compute the constant escalation levelization factor for a repeating expenditure.

An expenditure that repeats every year and escalates at the constant nominal rate \(r_\mathrm{n}\) is an uneven series of payments. The factor relates its value at the beginning of the first year, \(P_0\), to the equal yearly payment that replaces it [2]:

\[\mathrm{CELF} = \frac{A}{P_0} = \frac{k\,\left(1 - k^{n}\right)}{1 - k} \cdot \mathrm{CRF} \qquad k = \frac{1 + r_\mathrm{n}}{1 + i_\mathrm{eff}}\]

The cost the analysis is given is that \(P_0\), at the price level of the base year; the expenditure of the first year of operation is \(P_0 \cdot (1 + r_\mathrm{n})\). An escalation rate equal to the rate of return makes \(k = 1\), and the factor is then \(n \cdot \mathrm{CRF}\).

Parameters:

r_n (float, optional) – Nominal escalation rate to use. Default is that of the operating and maintenance cost.

Returns:

float – The constant escalation levelization factor.

compute_component_costs()[source]

Compute the cost rate of every component, split into its investment and its O&M share.

Each component carries its own investment and its own operating cost, so a component whose installation effort or maintenance differs from the plant average gets its own cost rate:

\[\dot{Z}^\mathrm{CC}_{j} = \frac{f_{\mathrm{TCI},j} \cdot \mathrm{PEC}_{\mathrm{base},j} \cdot \mathrm{CRF}}{\tau} \qquad \dot{Z}^\mathrm{OM}_{j} = \frac{\mathrm{OMC}_{0,j} \cdot \mathrm{CELF}}{\tau}\]
Returns:

dict – {"<component>": (Z_CC, Z_OM, Z_total)}, each in currency per hour.

compute_costs(exergy_analysis)[source]

Return the cost rates of the components and the costs of the entering streams together.

Parameters:

exergy_analysis (ExergyAnalysis) – The analysis the costs are meant for; both sides are checked against it.

Returns:

dict – The dictionary to pass to ExergoeconomicAnalysis.run().

compute_crf()[source]

Compute the capital recovery factor using the effective rate of return.

The factor turns a single investment at the start of the plant’s life into the equal yearly payment that repays it over the plant’s lifetime:

\[\mathrm{CRF} = \frac{i_\mathrm{eff}\,(1 + i_\mathrm{eff})^{n}} {(1 + i_\mathrm{eff})^{n} - 1}\]
Returns:

float – The capital recovery factor.

compute_z(exergy_analysis=None)[source]

Return the cost rates of the components, ready for the exergoeconomic analysis.

Parameters:

exergy_analysis (ExergyAnalysis, optional) – The analysis the costs are meant for. When it is given, every component of the plant that needs a cost rate has to have a purchased equipment cost, and a purchased equipment cost given for a component that is not in the plant, or that carries no cost balance, is an error.

Returns:

dict – {"<component>_Z": cost rate} in currency per hour.

Raises:

ValueError – If the components of the analysis and the purchased equipment costs do not match.

economic_results(exergy_analysis=None, print_results=True)[source]

Return the cost rates of the components and the levelized costs of the plant.

Parameters:
  • exergy_analysis (ExergyAnalysis, optional) – Needed for the levelized cost of the entering streams.

  • print_results (bool, optional) – If True, print both tables. Default is True.

Returns:

tuple of pandas.DataFrame – The costs per component and the levelized costs of the plant.

escalation_factor(year)[source]

Return the factor that carries a cost from the price level of a year to that of the base year.

Within the years the plant cost index covers, the factor is the ratio of the two index values. Outside of them, before the first or after the last entry, every year is bridged with the nominal escalation rate, forward or backward:

\[f = \frac{I_{\bar{y}_\mathrm{base}}}{I_{\bar{y}}} \cdot \left(1 + r_\mathrm{n}\right)^{(\bar{y} - y) + (y_\mathrm{base} - \bar{y}_\mathrm{base})}\]

where \(\bar{y}\) is a year clamped to the range of the index. Without an index, the rate bridges the whole span.

Parameters:

year (int or None) – The year the cost is given in. None means the base year.

Returns:

float

Raises:

ValueError – If a year inside the range of the index has no value, which no rate can bridge.

first_year_om_costs()[source]

Deprecated name of base_year_om_costs().

classmethod from_dict(data, exergy_analysis=None)[source]

Read the cost assumptions of a plant from a dictionary.

The dictionary has the structure of the file from_json() reads, so the same document can be kept in memory, written to a file or read back from one.

Parameters:
  • data (dict) – The cost assumptions, structured as in from_json().

  • exergy_analysis (ExergyAnalysis, optional) – The analysed plant, to read the sizes a scaled cost leaves out.

Returns:

EconomicAnalysis – The analysis described by the dictionary.

Raises:

ValueError – If the dictionary has no components, if a component has no purchased equipment cost, or if a key is not one the class knows.

classmethod from_json(path, exergy_analysis=None)[source]

Read the cost assumptions of a plant from a JSON file.

The file keeps everything about one component in one entry, so the purchased equipment cost, its reference year and the factors that belong to it cannot drift apart:

{
    "i_eff": 0.12,
    "n": 20,
    "tau": 6000,
    "base_year": 2025,
    "currency": "EUR",
    "f_tci": 6.32,
    "omc_share": 0.015,
    "cost_index": {"2021": 112.0, "2025": 143.0},
    "components": {
        "COMP": {"PEC": 300000.0, "reference_year": 2021, "f_tci": 4.2, "omc_share": 0.03},
        "COND": {"PEC_ref": 100000.0, "size_ref": 80.0, "size": 120.0, "reference_year": 2021},
        "VAL": 5000.0
    },
    "fuel_costs": {"e1": {"c": 30.0, "r_n": 0.04}, "11": 0.0}
}

A value given at the top level applies to the whole plant, and a component that names the same key overrides it, so only what differs has to be written out. A component entry may be a plain number instead of an object, and so may an entry of fuel_costs; both are read as the cost with everything else left at its default. A component scaled from a reference gives PEC_ref, size_ref and size or size_by, and optionally exponent, exchanger_type and U, instead of PEC, see EconomicAnalysis.

Parameters:
  • path (str) – Path to the JSON file.

  • exergy_analysis (ExergyAnalysis, optional) – The analysed plant, to read the sizes a scaled cost leaves out.

Returns:

EconomicAnalysis – The analysis described by the file.

Raises:

ValueError – If the file has no components, if a component has no purchased equipment cost, or if a key is not one the class knows.

See also

EconomicAnalysis.from_dict

The same from a dictionary already in memory.

levelized_carrying_charges()[source]

Compute the levelized carrying charges of the plant.

\[\mathrm{CC}_\mathrm{L} = \mathrm{TCI} \cdot \mathrm{CRF}\]
Returns:

float – Levelized carrying charges in currency per year.

levelized_fuel_costs(exergy_analysis=None)[source]

Compute the levelized cost of the streams entering the plant.

\[\mathrm{FC}_\mathrm{L} = \tau \cdot \sum_i c_{\mathrm{L},i} \cdot \dot{E}_i\]
Returns:

float – Levelized cost of the entering streams in currency per year, or 0.0 when no stream cost is given.

levelized_om_costs()[source]

Compute the levelized operating and maintenance cost of the plant.

\[\mathrm{OMC}_\mathrm{L} = \mathrm{CELF}(r_\mathrm{n}) \cdot \sum_j \mathrm{OMC}_{0,j}\]
Returns:

float – Levelized operating and maintenance cost in currency per year.

property total_PEC

Purchased equipment cost of the whole plant at the price level of the base year.

total_revenue_requirement(exergy_analysis=None)[source]

Compute the levelized total revenue requirement of the plant.

\[\mathrm{TRR}_\mathrm{L} = \mathrm{CC}_\mathrm{L} + \mathrm{OMC}_\mathrm{L} + \mathrm{FC}_\mathrm{L}\]
Parameters:

exergy_analysis (ExergyAnalysis, optional) – Needed for the fuel cost, which follows from the exergy of the entering streams. Without it the fuel cost is left out and the sum is the capital and the operating cost alone.

Returns:

float – Levelized total revenue requirement in currency per year.

class exerpy.analyses.ExergoeconomicAnalysis(exergy_analysis_instance, currency='EUR')[source]

Bases: object

” This class performs exergoeconomic analysis on a previously completed exergy analysis. It takes the results from an ExergyAnalysis instance and builds upon them to conduct a complete exergoeconomic analysis. It constructs and solves a system of linear equations to determine the costs (both total and specific) associated with each exergy stream in the system, and calculates various exergoeconomic indicators for each component.

Variables:
  • exergy_analysis (ExergyAnalysis) – The exergy analysis instance used as the basis for calculations.

  • connections (dict) – Dictionary of all energy/material connections in the system.

  • components (dict) – Dictionary of all components in the system.

  • chemical_exergy_enabled (bool) – Flag indicating if chemical exergy is considered in calculations.

  • E_F_dict (dict) – Dictionary mapping fuel streams to components.

  • E_P_dict (dict) – Dictionary mapping product streams to components.

  • E_L_dict (dict) – Dictionary mapping loss streams to components.

  • num_variables (int) – Number of cost variables in the exergoeconomic equations.

  • variables (dict) – Dictionary mapping variable indices to variable names.

  • equations (dict) – Dictionary mapping equation indices to equation types.

  • currency (str) – Currency symbol used in cost reporting.

  • system_costs (dict) – Dictionary of system-level costs after analysis.

assign_user_costs(Exe_Eco_Costs)[source]

Assign component and connection costs from user input dictionary.

Parameters:

Exe_Eco_Costs (dict) – Dictionary containing cost assignments for components and connections. Format for components: “<component_name>_Z”: cost_value [currency/h] Format for connections: “<connection_name>_c”: cost_value [currency/GJ] A material stream may also have a cost per exergy form, “<connection_name>_c_T”, “_c_M” and “_c_CH”, or “_c_PH” for the thermal and the mechanical exergy together (without the split: “_c_PH” and “_c_CH”). A form without a cost of its own takes “_c”. Another unit in the currency of the analysis may be given next to a value, as "<connection_name>_c_unit": "EUR / MWh" or "<component_name>_Z_unit": "EUR / s".

Raises:

ValueError – If a component cost is missing or if a required input connection cost is not provided, if a cost per exergy form does not fit the split of the physical exergy, or if a unit is unknown, of the wrong kind or in another currency.

Notes

Component costs are converted from [currency/h] to [currency/s]. Connection costs are converted from [currency/GJ] to [currency/J]. Material connections receive c_T, c_M, c_CH cost breakdowns. Heat and power connections receive only c_TOT values.

check_cost_balance(tol=1e-06)[source]

Check the exergoeconomic cost balance for each component.

For each component, verify that sum of inlet C_TOT minus sum of outlet C_TOT plus component Z_costs equals zero within the given tolerance.

Parameters:

tol (float, optional) – Numerical tolerance for balance check (default is 1e-6).

Returns:

dict – Mapping from component name to tuple (balance, is_balanced), where balance is the residual and is_balanced is True if abs(balance) <= tol.

construct_matrix()[source]

Construct the exergoeconomic cost matrix and vector.

Returns:

tuple – A tuple containing: - A: numpy.ndarray - The coefficient matrix for the linear equation system - b: numpy.ndarray - The right-hand side vector for the linear equation system

Notes

This method constructs a system of linear equations that includes: 1. Cost balance equations for each productive component 2. Equations for inlet streams to fix their costs based on provided values 3. Auxiliary equations for power flows 4. Custom auxiliary equations from each component 5. Special equations for dissipative components

property cost_labels: tuple[str, ...]

Cost variables of a material stream.

With split physical exergy a stream carries a thermal and a mechanical cost, without it a single cost of its physical exergy. The chemical cost is added when chemical exergy is enabled. Every part of the analysis derives the number of cost variables of a stream from this, so that the matrix stays square: the components have to provide one auxiliary equation per cost variable of their outlets, except for the one covered by their cost balance.

detect_linear_dependencies(tol_strict: float = 1e-12, tol_near: float = 1e-08)[source]

Scan A for zero-rows, zero-cols, pairwise colinear equation pairs, and use SVD null-space analysis to identify multi-equation dependencies.

The SVD analysis finds the actual null space of A^T, revealing which equations participate in linear dependencies even when no two equations are pairwise colinear.

distribute_all_Z_diff(C_solution)[source]

Store the share of the dissipative cost differences (the C_diff variables) that the cost balance of each component is charged with.

The share is read from the coefficients of the C_diff columns in the cost balance row of the component and stored as its Z_diss, zero for a component without such a row.

Parameters:

C_solution (array_like) – Solution vector of cost variables from the solved linear system.

evaluate_results(top_n=5, sort_by='C_D+Z')[source]

Analyze and print the most important components from the exergoeconomic analysis.

This method ranks components by the selected criterion and prints a summary table highlighting where the highest cost increases occur and whether they are driven by investment (Z) or by inefficiency (C_D).

Parameters:
  • top_n (int, optional) – Number of top components to display (default is 5).

  • sort_by (str, optional) – Column to sort by. Valid options:

    • "C_D+Z" : total cost rate of exergy destruction plus investment (default)

    • "C_D" : cost rate of exergy destruction (inefficiency-driven cost)

    • "Z" : investment cost rate

    • "r" : relative cost difference [%]

    • "f" : exergoeconomic factor [%]

Returns:

pandas.DataFrame – The sorted component DataFrame (excluding the TOT row).

Notes

The exergoeconomic factor f indicates whether the cost increase in a component is dominated by investment (f close to 100 %) or by exergy destruction (f close to 0 %). A low f suggests that improving component efficiency would be more effective, while a high f suggests that reducing investment cost is the priority. The cost a component is charged for the dissipative components it serves, Z_diss, is part of its r and c_P, but not of f and C_D+Z: it is neither its investment nor its exergy destruction, and C_D+Z of the dissipative component already contains it.

exergoeconomic_results(print_results=True)[source]

Displays tables of exergoeconomic analysis results with columns for costs and economic parameters for each component, and additional cost information for material and non-material connections.

Parameters:

print_results (bool, optional) – If True, prints the results as tables in the console (default is True).

Returns:

tuple of pandas.DataFrame – (df_component_results, df_material_connection_results_part1, df_material_connection_results_part2, df_non_material_connection_results) with the exergoeconomic analysis results.

export_to_json(output_path, units=None)[source]

Export the model with its exergy and cost results to a JSON file.

Every value is written with its unit: the costs in currency/h, the specific costs in currency/GJ and the other values in SI, unless units asks for another one.

Parameters:
  • output_path (str) – Path where the JSON file will be saved.

  • units (dict, optional) – Unit to write a value other than a cost in, see ExergyAnalysis.export_to_json().

initialize_cost_variables()[source]

Initialize cost variables for the exergoeconomic analysis.

This method assigns unique indices to each cost variable in the matrix system and populates a dictionary mapping these indices to variable names.

For material streams, separate indices are assigned for thermal, mechanical, and chemical exergy components when chemical exergy is enabled (otherwise only thermal and mechanical). For non-material streams (heat, power), a single index is assigned for the total exergy cost.

Notes

The assigned indices are used for constructing the cost balance equations in the matrix system that will be solved to find all cost variables.

print_dependency_report(tol_strict: float = 1e-12, tol_near: float = 1e-08)[source]

Nicely print which equations or variables are under- or over-determined, distinguishing exact vs. near colinearities, and showing SVD null-space analysis.

print_equations()[source]

Get mapping of equation indices to equation descriptions.

Returns:

dict – Keys are equation indices (int), values are equation descriptions (str).

print_variables()[source]

Get mapping of variable indices to variable names.

Returns:

dict – Keys are variable indices (int), values are variable names (str).

run(Exe_Eco_Costs, allow_singular=False)[source]

Execute the full exergoeconomic analysis.

Parameters:
  • Exe_Eco_Costs (dict) – Dictionary containing cost assignments for components and connections. Format for components: “<component_name>_Z”: cost_value [currency/h] Format for connections: “<connection_name>_c”: cost_value [currency/GJ], or a cost per exergy form of a material stream, see assign_user_costs().

  • allow_singular (bool, optional) – If True, use least-squares solver as fallback when the matrix is singular. The solution may not be physically consistent. Default is False.

Notes

This method performs the complete exergoeconomic analysis by: 1. Initializing cost variables for all components and streams 2. Assigning user-defined costs to components and boundary streams 3. Solving the system of exergoeconomic equations

solve_exergoeconomic_analysis(allow_singular=False)[source]

Solve the exergoeconomic cost balance equations and assign the results to connections and components.

Parameters:

allow_singular (bool, optional) – If True, use least-squares solver as fallback when the matrix is singular. The solution may not be physically consistent. Default is False.

Returns:

tuple – (exergy_cost_matrix, exergy_cost_vector) - The coefficient matrix and right-hand side vector used in the linear equation system.

Raises:

ValueError – If the exergoeconomic system is singular (and allow_singular is False) or if the cost balance is not satisfied.

Notes

This method performs the following steps: 1. Constructs the exergoeconomic cost matrix 2. Solves the system of linear equations 3. Assigns cost solutions to connections 4. Calculates component exergoeconomic indicators 5. Distributes loss stream costs to product streams 6. Computes system-level cost variables

class exerpy.analyses.ExergyAnalysis(component_data, connection_data, Tamb, pamb, chemExLib=None, split_physical_exergy=True)[source]

Bases: object

This class performs exergy analysis on energy system models from various simulation tools. It parses input data, constructs component objects, calculates exergy flows, and provides a comprehensive exergy balance for the overall system and individual components. The class supports importing data from TESPy, Aspen, Ebsilon, or directly from JSON files.

Variables:
  • Tamb (float) – Ambient temperature in K for reference environment.

  • pamb (float) – Ambient pressure in Pa for reference environment.

  • _component_data (dict) – Raw component data from the input model.

  • _connection_data (dict) – Raw connection data from the input model.

  • chemExLib (object, optional) – Chemical exergy library for chemical exergy calculations.

  • chemical_exergy_enabled (bool) – Flag indicating if chemical exergy calculations are enabled.

  • split_physical_exergy (bool) – Flag indicating if physical exergy is split into thermal and mechanical components.

  • components (dict) – Dictionary of component objects constructed from input data.

  • connections (dict) – Dictionary of connection data with exergy values.

  • E_F (float) – Total fuel exergy for the overall system in W.

  • E_P (float) – Total product exergy for the overall system in W.

  • E_L (float) – Total loss exergy for the overall system in W.

  • E_D (float) – Total exergy destruction for the overall system in W.

  • E_F_dict (dict) – Dictionary specifying fuel connections.

  • E_P_dict (dict) – Dictionary specifying product connections.

  • E_L_dict (dict) – Dictionary specifying loss connections.

  • epsilon (float) – Overall exergy efficiency of the system.

analyse(E_F, E_P, E_L=None) → None[source]

Run the exergy analysis for the entire system and calculate overall exergy efficiency.

Parameters:
  • E_F (dict) – Dictionary containing input connections for fuel exergy (e.g., {“inputs”: [“1”, “2”]}).

  • E_P (dict) – Dictionary containing input and output connections for product exergy (e.g., {“inputs”: [“E1”], “outputs”: [“T1”, “T2”]}).

  • E_L (dict, optional) – Dictionary containing input and output connections for loss exergy (default is {}).

boundary_streams()[source]

Return the streams crossing the system boundary.

A stream crosses the boundary when one of its ends is no component of the analysis. That end may be missing, as in the Ebsilon exports, or name a source or sink of the simulation that is no component of the plant, such as “ambient air” or “chimney” in the TESPy and Aspen exports. Only material, heat and power streams are reported; control signals are left out.

Returns:

list of dict – One entry per stream, in the order of the connections, with its name and kind, its direction ("in" when it enters the plant, "out" when it leaves it and None when neither end is a component), the outside end it comes from or goes to, and its E, energy_flow, m, T and p where the stream has them. E is the value at the time of the call; the exergy of a heat stream may only be known after analyse().

exergy_results(print_results=True)[source]

Displays a table of exergy analysis results with columns for E_F, E_P, E_D, and epsilon for each component, and additional information for material and non-material connections.

CycleCloser components are excluded from the component results.

Parameters:

print_results (bool, optional) – If True, prints the results as tables in the console (default is True).

Returns:

tuple of pandas.DataFrame – (df_component_results, df_material_connection_results, df_non_material_connection_results) with the exergy analysis results.

export_to_json(output_path, units=None)[source]

Export the model to a JSON file.

Every value is written with its unit, in SI unless units asks for another one.

Parameters:
  • output_path (str) – Path where the JSON file will be saved.

  • units (dict, optional) – Unit to write a key in, e.g. {"T": "degC", "p": "bar", "E_D": "kW"}; the keys are those of exerpy.units.SI_UNITS. from_json() reads the file back in SI.

Returns:

None – The model is saved to the specified path.

Notes

This method serializes the model using the internal _serialize method and writes the resulting data to a JSON file with indentation. NaN values are converted to null for valid JSON output.

flows_from_roles(roles)[source]

Build the fuel, product and loss definitions of the plant from the role of its boundary streams.

analyse() sums each of the three as the streams listed under "inputs" minus the ones under "outputs". A stream feeding the plant adds to the fuel, a stream leaving it adds to the product or to the loss, and the stream on the other side of the same service is subtracted: the water entering a heat pump is an output of the product formed by the heated water, and the cooling water entering a condenser an output of the loss formed by the warm cooling water. The exergy of a heat stream exchanged with a stream that leaves below the ambient temperature flows against the heat [2], so its direction is reversed, with a warning.

Parameters:

roles (dict) – The role of a boundary stream by its name: "F", "P" or "L", or spelled out as "fuel", "product" or "loss". A stream that is left out is part of no definition.

Returns:

tuple of dict – (E_F, E_P, E_L) as analyse() takes them.

Raises:

ValueError – If a name is no stream crossing the system boundary, if a stream is attached to the plant on neither side, or if a role is not one of the three.

Examples

>>> ean = ExergyAnalysis.from_json("hp.json")
>>> E_F, E_P, E_L = ean.flows_from_roles({"e1": "F", "21": "P", "23": "P", "11": "L", "13": "L"})
>>> E_P
{'inputs': ['23'], 'outputs': ['21']}
classmethod from_aspen(path, Tamb=None, pamb=None, chemExLib=None, split_physical_exergy=True, validate=True)[source]

Create an instance of the ExergyAnalysis class from an Aspen model file.

Parameters:
  • path (str) – Path to the Aspen file (.bkp format).

  • Tamb (float, optional) – Ambient temperature in K. Defaults to the reference temperature REF_TEMP of the model. A value passed here replaces it and the model is run again, so all exergies are computed at it. The model file stays unchanged.

  • pamb (float, optional) – Ambient pressure in Pa. Defaults to the reference pressure REF_PRES of the model, and replaces it like Tamb.

  • chemExLib (str, optional) – Name of the chemical exergy library (if any).

  • split_physical_exergy (bool, optional) – If True, separates physical exergy into thermal and mechanical components.

  • validate (bool, default=True) – Check the parsed model against the input schema of exerpy.schema.

Returns:

ExergyAnalysis – An instance of the ExergyAnalysis class with parsed Aspen data.

classmethod from_ebsilon(path, Tamb=None, pamb=None, chemExLib=None, split_physical_exergy=True, profile=None, validate=True)[source]

Create an instance of the ExergyAnalysis class from an Ebsilon model file.

Parameters:
  • path (str) – Path to the Ebsilon file (.ebs format).

  • Tamb (float, optional) – Ambient temperature in K. Defaults to the reference temperature of the model, set by a measuring point. A value passed here overrides it and all exergies are computed at it; if it differs from the model, the physical exergies are computed from the fluid data of the streams instead of taken from Ebsilon. Only the reference state changes, not the simulation. If the measuring point also sets an inlet temperature of the plant, change it in Ebsilon to simulate the plant at another ambient temperature.

  • pamb (float, optional) – Ambient pressure in Pa. Defaults to the reference pressure of the model, and overrides it like Tamb.

  • chemExLib (str, optional) – Name of the chemical exergy library (if any).

  • split_physical_exergy (bool, optional) – If True, separates physical exergy into thermal and mechanical components.

  • profile (str or int, optional) – Name or id of the profile (operating point) to simulate, e.g. a part load case. Defaults to the profile the model was saved with. Use exerpy.parser.from_ebsilon.ebsilon_parser.get_ebsilon_profiles() to list them.

  • validate (bool, default=True) – Check the parsed model against the input schema of exerpy.schema.

Returns:

ExergyAnalysis – An instance of the ExergyAnalysis class with parsed Ebsilon data.

classmethod from_json(json_path: str, Tamb=None, pamb=None, chemExLib=None, split_physical_exergy=None, validate=True)[source]

Create an ExergyAnalysis instance from a JSON file.

A value given with a unit, as "T": 15.0, "T_unit": "degC", is converted to SI; a value without a unit is taken as SI, see exerpy.units.

Parameters:
  • json_path (str) – Path to JSON file containing component and connection data.

  • Tamb (float, optional) – Ambient temperature in K. If None, taken from ambient_conditions of the JSON. The exergies in the file were computed at that state, so a value passed here must agree with it; it is needed only if the file has none.

  • pamb (float, optional) – Ambient pressure in Pa, like Tamb.

  • chemExLib (str, optional) – Name of chemical exergy library to use. Default is None.

  • split_physical_exergy (bool, optional) – Split physical exergy into thermal and mechanical parts. If None, read from the JSON settings or detected from the data.

  • validate (bool, default=True) – Check the file against the input schema of exerpy.schema before the analysis is set up. All problems found are reported at once.

Returns:

ExergyAnalysis – Configured instance with data from JSON file.

Raises:
  • FileNotFoundError – If JSON file does not exist.

  • ValueError – If JSON structure is invalid or missing required data, or if Tamb or pamb differ from the ambient state of the file. For a unit that is unknown or of the wrong kind, and with validate=True for any problem, this is an exerpy.schema.InputValidationError, whose issues attribute lists each problem with its location.

  • JSONDecodeError – If JSON file is malformed.

classmethod from_tespy(model: str, Tamb=None, pamb=None, chemExLib=None, split_physical_exergy=True, validate=True)[source]

Create an instance of the ExergyAnalysis class from a tespy network or a tespy network export structure.

Parameters:
  • model (str | tespy.networks.network.Network) – Path to the tespy Network export or the actual Network instance.

  • Tamb (float, optional) – Ambient temperature in K. All exergies are computed at it.

  • pamb (float, optional) – Ambient pressure in Pa. All exergies are computed at it.

  • chemExLib (str, optional) – Name of the library for chemical exergy tables.

  • validate (bool, default=True) – Check the parsed model against the input schema of exerpy.schema.

Returns:

ExergyAnalysis – Instance of the ExergyAnalysis class.

plot_exergy_waterfall(title=None, figsize=(12, 10), exclude_components=None, colors=None, show_plot=True)[source]

Create an exergy destruction waterfall diagram.

Parameters:
  • title (str, optional) – Title for the plot.

  • figsize (tuple, optional) – Figure size as (width, height) in inches. Default is (12, 10).

  • exclude_components (list, optional) – Component names to exclude. Components with NaN E_F are always excluded.

  • colors (dict, optional) – Override bar colors. Keys: “fuel”, “destruction”, “loss”, “product”.

  • show_plot (bool, optional) – Whether to display the plot immediately. Default is True.

Returns:

  • fig (matplotlib.figure.Figure)

  • ax (matplotlib.axes.Axes)

Examples

>>> analysis = ExergyAnalysis.from_tespy(network, Tamb=288.15, pamb=101325)
>>> analysis.analyse(E_F={'inputs': ['fuel']}, E_P={'outputs': ['power']})
>>> fig, ax = analysis.plot_exergy_waterfall(title='Power Plant Exergy Waterfall')
plot_exergy_waterfall_plotly(title=None, exclude_components=None, colors=None, show_plot=True)[source]

Create an interactive exergy destruction waterfall diagram using Plotly.

Parameters:
  • title (str, optional) – Title for the plot.

  • exclude_components (list, optional) – Component names to exclude. Components with NaN E_F are always excluded.

  • colors (dict, optional) – Override bar colors. Keys: “fuel”, “destruction”, “loss”, “product”.

  • show_plot (bool, optional) – Whether to display the plot immediately. Default is True.

Returns:

fig (plotly.graph_objects.Figure)

Examples

>>> analysis = ExergyAnalysis.from_tespy(network, Tamb=288.15, pamb=101325)
>>> analysis.analyse(E_F={'inputs': ['fuel']}, E_P={'outputs': ['power']})
>>> fig = analysis.plot_exergy_waterfall_plotly(title='Power Plant Exergy Waterfall')
plot_sankey(mode: int = 1, collapse_passthroughs: bool | list[str] = True, groups: dict | None = None, node_colors: dict | None = None, title: str | None = None, output_path: str | None = None)[source]

Create an interactive Sankey diagram of the exergy flows.

Parameters:
  • mode ({1, 2, 3}) – 1 – total exergy E per link (default) 2 – split material links into E_PH + E_CH (requires chemical_exergy_enabled) 3 – split material links into E_T + E_M + E_CH (requires split_physical_exergy)

  • collapse_passthroughs (bool or list[str]) – True → collapse CycleCloser nodes into their neighbours (default) False → show every component node list → collapse only the listed component type names

  • groups (dict[str, list[str]], optional) – Visual grouping: {"Group": ["comp1", "comp2"]} hides internal connections and aggregates boundary-crossing links.

  • node_colors (dict[str, str], optional) – Per-component colour overrides keyed by component name, e.g. {"CC": "#C62828", "GT": "#388E3C"}. Components not listed use the default node colour.

  • title (str, optional) – Diagram title.

  • output_path (str, optional) – If given, export the diagram to this HTML file path.

Returns:

plotly.graph_objects.Figure

print_exergy_summary()[source]

Print a text summary of the exergy analysis results.

This method provides a concise summary of the overall system exergy performance, including fuel exergy, total destruction, losses, and efficiency.

Raises:

RuntimeError – If the exergy analysis has not been performed yet (analyse() not called).

Notes

The summary includes: - Exergetic Fuel: Normalized to 100% - Total Exergy Destruction: Sum of all component exergy destructions as % of fuel - Exergetic Loss: Exergy losses to the environment as % of fuel - Exergetic Product (epsilon): Overall system exergy efficiency as %

Examples

>>> analysis = ExergyAnalysis.from_tespy(network, Tamb=288.15, pamb=101325)
>>> analysis.analyse(E_F={'inputs': ['fuel']}, E_P={'outputs': ['power']})
>>> analysis.print_exergy_summary()
Exergy Analysis Summary:
Exergetic Fuel: 100.00%
Total Exergy Destruction: 35.42%
Exergetic Loss: 5.12%
Exergetic Product (epsilon): 59.46%

See also

exergy_results

Display detailed tabular results.

plot_exergy_waterfall

Create a visual waterfall diagram.