Debug your models efficiently

This tutorial gives insights on how you can debug tespy models. The user interface of the current implementation might still need some refinement, so you are invited to raise issues in the github repository. We will change it based on the feedback. The outputs shown here are based on the following version of tespy:

from tespy import __version__
__version__
"0.11.3 - Rankine's Renaissance"

Simple model debugging

This tutorial will show a couple of things

  1. How to extract the variables of the problem

    • before presolving step

    • after presolving step and identify the presolved variables

  2. How to extract the applied equations of the problem

    • before presolving step

    • after presolving step and identify the presolved equations

  3. How to read and fix the errors that are raised during presolving

  4. How to debug structural errors and non-convergence with the structural analysis, the incidence matrix and the residuals

Model overview

The model we implement is a very simple heat pump model, just as implemented in the introductory Heat Pump tutorial.

../_images/heat_pump1.svg ../_images/heat_pump_darkmode1.svg

Model code

from tespy.components import CycleCloser, SimpleHeatExchanger, Compressor, Valve, Motor, PowerSource
from tespy.connections import Connection, PowerConnection
from tespy.networks import Network
nw = Network()
nw.units.set_defaults(
    temperature="°C",
    pressure="bar",
    pressure_difference="bar",
    power="kW",
    heat="kW",
    enthalpy="kJ/kg"
)
grid = PowerSource("grid")
motor = Motor("motor")

cc = CycleCloser("cycle closer")
valve = Valve("valve")
evaporator = SimpleHeatExchanger("evaporator")
compressor = Compressor("compressor")
condenser = SimpleHeatExchanger("condenser")

c1 = Connection(cc, "out1", evaporator, "in1", label="c1")
c2 = Connection(evaporator, "out1", compressor, "in1", label="c2")
c3 = Connection(compressor, "out1", condenser, "in1", label="c3")
c4 = Connection(condenser, "out1", valve, "in1", label="c4")
c0 = Connection(valve, "out1", cc, "in1", label="c0")


nw.add_conns(c1, c2, c3, c4, c0)

e1 = PowerConnection(grid, "power", motor, "power_in", label="e1")
e2 = PowerConnection(motor, "power_out", compressor, "power", label="e2")

nw.add_conns(e1, e2)

Debug the model

Variable and equation identification

With nothing specified and trying to solve we will get an information, that the network is lacking fluid information.

nw.solve("design", init_only=True)
---------------------------------------------------------------------------
TESPyNetworkError                         Traceback (most recent call last)
Cell In[5], line 1
----> 1 nw.solve("design", init_only=True)

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2596, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, robust_relax, skip_postprocess, oscillation_damping, block_solve, pause_on_block_failure, line_search)
   2491 def solve(self, mode, init_path=None, design_path=None,
   2492           max_iter=50, min_iter=2, init_only=False, init_previous=True,
   2493           use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False,
   2494           oscillation_damping=False, block_solve=True,
   2495           pause_on_block_failure=False, line_search="stagnation"):
   2496     r"""
   2497     Solve the network.
   2498 
   (...)   2594     documentation at tespy.readthedocs.io in the section "TESPy modules".
   2595     """
-> 2596     self.presolve(
   2597         mode, init_path=init_path, design_path=design_path,
   2598         init_previous=init_previous, check=not init_only
   2599     )
   2601     if init_only:
   2602         return

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2690, in Network.presolve(self, mode, init_path, design_path, init_previous, check)
   2683 msg = (
   2684     "Network information:\n"
   2685     f" - Number of components: {len(self.comps)}\n"
   2686     f" - Number of connections: {len(self.conns)}\n"
   2687 )
   2688 logger.debug(msg)
-> 2690 self._prepare_problem()
   2691 self._presolve_pending = True
   2693 if not check:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1039, in Network._prepare_problem(self)
   1036         self._create_fluid_wrapper_branches()
   1037         break
-> 1039 self._propagate_fluid_wrappers()
   1040 # the fluid composition may have changed, the frames are rebuilt
   1041 # lazily on access of the results
   1042 for conn_type in self.conns["conn_type"].unique():

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1126, in Network._propagate_fluid_wrappers(self)
   1120 if num_potential_fluids == 0:
   1121     msg = (
   1122         "The following connections of your network are missing any "
   1123         "kind of fluid composition information:"
   1124         f"{', '.join([c.label for c in all_connections])}."
   1125     )
-> 1126     raise hlp.TESPyNetworkError(msg)
   1128 for c in all_connections:
   1129     c.mixing_rule = mixing_rule

TESPyNetworkError: The following connections of your network are missing any kind of fluid composition information:c1, c2, c3, c4, c0.

Then let’s specify the fluid and preprocess the network again. The check, whether the number of specified parameters matches the number of variables of the problem, runs automatically at the start of every solve. When running with init_only=True the check is skipped and no error is raised, so we can use that starting point in an interactive python environment to get started with debugging.

c1.set_attr(fluid={"R290": 1})
nw.solve("design", init_only=True)

Now we can check the following information:

  • Which are the original variables of our model

  • Which of those variables have already been determined by the presolving

  • Which ones are the actual variables, that the model has to solve and which original variables of the model these variables represent

The original variables:

nw.print_variables_before_presolve()
Variables before presolving (22 total):
Object    Property
--------  ----------
c0        m
c0        p
c0        h
c0        fluid
c1        m
c1        p
c1        h
c1        fluid
c2        m
c2        p
c2        h
c2        fluid
c3        m
c3        p
c3        h
c3        fluid
c4        m
c4        p
c4        h
c4        fluid
e1        E
e2        E

The variables solved already by the presolving step:

nw.print_presolved_variables()
Presolved variables (5 total):
Object    Property
--------  ----------
c0        fluid
c1        fluid
c2        fluid
c3        fluid
c4        fluid

The actual variables of the problem: each has a number and a property type (mass flow, pressure, enthalpy, fluid, …) and represents one or more of the original variables. The represents column lists those with the label of the connection they originate from.

nw.print_variables()
Variables after presolving (10 total):
  #  Property    Represents
---  ----------  --------------------------------------
  0  p           c2 (p)
  1  h           c2 (h)
  2  p           c3 (p)
  3  h           c3 (h)
  4  p           c4 (p)
  5  E           e1 (E)
  6  E           e2 (E)
  7  m           c2 (m), c3 (m), c1 (m), c4 (m), c0 (m)
  8  p           c0 (p), c1 (p)
  9  h           c0 (h), c1 (h), c4 (h)

We can also check which equations of the model have been presolved in order to retrieve the dependencies between the variables. E.g. the mass flow variable just before represents all the mass flows in this model. We can see, that the mass_flow_constraints have been solved for all components. The equations indicated here can be inspected in the tables of the documentation on the components and connections.

nw.print_presolved_equations()
Presolved equations (11 total):
Object        Equation
------------  ----------------------------
compressor    mass_flow_constraints
compressor    fluid_constraints
condenser     mass_flow_constraints
condenser     fluid_constraints
cycle closer  pressure_equality_constraint
cycle closer  enthalpy_equality_constraint
evaporator    mass_flow_constraints
evaporator    fluid_constraints
valve         mass_flow_constraints
valve         fluid_constraints
valve         enthalpy_constraints

There is not yet an easy way to identify which variable was presolved by which. Next to the presolved equations we can also inspect, which equations are present in the actual model that needs to be solved iteratively.

nw.print_equations()
Equations after presolving (1 total):
  Eq#  Object      Equation
-----  ----------  ------------------------
    0  compressor  energy_connector_balance

With the equations we can also extract the variables these depend on.

nw.print_equations_with_dependents()
Equations with dependent variables (1 total):
  Eq#  Object      Equation                  Dependent variables
-----  ----------  ------------------------  ---------------------
    0  compressor  energy_connector_balance  h1, h3, E6, m7

Impose parameters and check again

Now let’s impose a couple of boundary conditions:

  • No pressure drop in heat exchanges

  • Compressor efficiency

  • Motor efficiency

condenser.set_attr(dp=0)
evaporator.set_attr(dp=0)
compressor.set_attr(eta_s=0.8)
motor.set_attr(eta=0.97)
nw.solve("design", init_only=True)

Again, we can inspect, which variables have been presolved now. It does not change, because we did not impose any boundary conditions, where any of the variables can be directly determined from.

nw.print_presolved_variables()
Presolved variables (5 total):
Object    Property
--------  ----------
c0        fluid
c1        fluid
c2        fluid
c3        fluid
c4        fluid

But if we check the actual variables of the system, we see that the number has been reduced. The two energy flows are now mapped to a single variable, and the pressure values before and after the heat exchangers have been also mapped to a single variable respectively.

nw.print_variables()
Variables after presolving (7 total):
  #  Property    Represents
---  ----------  --------------------------------------
  0  h           c2 (h)
  1  h           c3 (h)
  2  m           c2 (m), c3 (m), c1 (m), c4 (m), c0 (m)
  3  p           c3 (p), c4 (p)
  4  p           c0 (p), c1 (p), c2 (p)
  5  h           c0 (h), c1 (h), c4 (h)
  6  E           e1 (E), e2 (E)

The reason for that can be seen in the presolved equations, where now we have three additional entries.

nw.print_presolved_equations()
Presolved equations (14 total):
Object        Equation
------------  ----------------------------
compressor    mass_flow_constraints
compressor    fluid_constraints
condenser     mass_flow_constraints
condenser     fluid_constraints
condenser     dp
cycle closer  pressure_equality_constraint
cycle closer  enthalpy_equality_constraint
evaporator    mass_flow_constraints
evaporator    fluid_constraints
evaporator    dp
motor         eta
valve         mass_flow_constraints
valve         fluid_constraints
valve         enthalpy_constraints

And we also get one more equation in our model equations, that needs to be solved numerically: the compressor efficiency.

nw.print_equations_with_dependents()
Equations with dependent variables (2 total):
  Eq#  Object      Equation                  Dependent variables
-----  ----------  ------------------------  ---------------------
    0  compressor  energy_connector_balance  h0, h1, m2, E6
    1  compressor  eta_s                     h0, h1, p3, p4

Or in a matrix view:

nw.print_incidence_matrix()
Incidence matrix:
                                     h0    h1    m2    p3    p4    E6
-----------------------------------  ----  ----  ----  ----  ----  ----
compressor.energy_connector_balance  x     x     x     -     -     x
compressor.eta_s                     x     x     -     x     x     -

Let’s add more boundary conditions, because we are still missing a couple:

  • evaporation temperature level and superheating

c2.set_attr(T_dew=10, td_dew=10)
nw.solve("design", init_only=True)

Now we can see that the number of variables has been reduced by two. The reason for this is, that the presolver was able to identify pressure and enthalpy at the compressor inlet with the given boundary conditions.

nw.print_variables()
Variables after presolving (5 total):
  #  Property    Represents
---  ----------  --------------------------------------
  0  h           c3 (h)
  1  m           c2 (m), c3 (m), c1 (m), c4 (m), c0 (m)
  2  p           c3 (p), c4 (p)
  3  h           c0 (h), c1 (h), c4 (h)
  4  E           e1 (E), e2 (E)

Since these two variables have now been presolved, the equation of the compressor has less dependents, as it is not necessary to solve for the respective variables anymore.

nw.print_equations_with_dependents()
Equations with dependent variables (2 total):
  Eq#  Object      Equation                  Dependent variables
-----  ----------  ------------------------  ---------------------
    0  compressor  energy_connector_balance  h0, m1, E4
    1  compressor  eta_s                     h0, p2

We are still missing 3 equations as we have 5 variables in the problem and only 2 equations at the moment, so let’s add the missing specifications:

  • electrical power input

  • condensing temperature level and subcooling

c4.set_attr(T_bubble=60, td_bubble=0)
e1.set_attr(E=100)  # 100 kW
nw.solve("design")
 block   0 | scalar          | iterations:   2 | residual: 0.00e+00 | compressor.eta_s
 block   1 | scalar          | iterations:   2 | residual: 2.15e-15 | compressor.energy_connector_balance

The solver output shows that the two remaining equations were solved as individual blocks in sequence. The block decomposition can be inspected directly, see the decomposition section for the background:

nw.print_blocks()
Block lower triangular decomposition (2 blocks):
  #  Kind      Needs  Equations                            Variables
---  ------  -------  -----------------------------------  -----------
  0  scalar           compressor.eta_s                     h0
  1  scalar        0  compressor.energy_connector_balance  m1
nw.print_incidence_matrix(block_order=True)
Incidence matrix:
  Block                                       h0    m1
-------  -----------------------------------  ----  ----
      0  compressor.eta_s                     X     -
      1  compressor.energy_connector_balance  x     X

Handle errors during presolving

Some errors can occur during presolving, for example:

You specify a linear change of specific variable while specifying both values simultaneously. In this case, the error message directly tells you which variables are linear dependent and that you specified more than a single value in that set (points to the labels of the connections/components).

e2.set_attr(E=97)
nw.solve("design")
---------------------------------------------------------------------------
TESPyNetworkError                         Traceback (most recent call last)
Cell In[26], line 2
      1 e2.set_attr(E=97)
----> 2 nw.solve("design")

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2596, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, robust_relax, skip_postprocess, oscillation_damping, block_solve, pause_on_block_failure, line_search)
   2491 def solve(self, mode, init_path=None, design_path=None,
   2492           max_iter=50, min_iter=2, init_only=False, init_previous=True,
   2493           use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False,
   2494           oscillation_damping=False, block_solve=True,
   2495           pause_on_block_failure=False, line_search="stagnation"):
   2496     r"""
   2497     Solve the network.
   2498 
   (...)   2594     documentation at tespy.readthedocs.io in the section "TESPy modules".
   2595     """
-> 2596     self.presolve(
   2597         mode, init_path=init_path, design_path=design_path,
   2598         init_previous=init_previous, check=not init_only
   2599     )
   2601     if init_only:
   2602         return

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2690, in Network.presolve(self, mode, init_path, design_path, init_previous, check)
   2683 msg = (
   2684     "Network information:\n"
   2685     f" - Number of components: {len(self.comps)}\n"
   2686     f" - Number of connections: {len(self.conns)}\n"
   2687 )
   2688 logger.debug(msg)
-> 2690 self._prepare_problem()
   2691 self._presolve_pending = True
   2693 if not check:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1050, in Network._prepare_problem(self)
   1046 # this method will distribute units and set SI values from given values
   1047 # and units
   1048 self._transform_user_input_to_SI()
-> 1050 self._problem.build()
   1052 # generic fluid property initialisation
   1053 self._set_starting_values()

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:199, in Problem.build(self)
    192 msg = (
    193     f"Original problem: {self.num_original_variables} variables and "
    194     f"{self.num_original_equations} equations, of which {num_affine} "
    195     "equations were consumed by the affine variable elimination."
    196 )
    197 logger.debug(msg)
--> 199 self._presolve()
    201 # counted only now: during the structure matrix assembly the
    202 # specification and variable flags of the containers are transient,
    203 # e.g. propagated fluid compositions read as set while their
    204 # variable fractions are only marked during the presolving
    205 self.num_specified_variables = 0

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:509, in Problem._presolve(self)
    505 self._presolve_fluid_vectors()
    507 # impose the user specifications on the affine groups first, so the
    508 # first round of connection presolving already sees them as known
--> 509 self._presolve_linear_dependents()
    511 # only scalar references are tracked: the fluid vectors were
    512 # fully resolved above and their is_var holds a set of fraction
    513 # names, not a boolean
    514 known_references = set()

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:739, in Problem._presolve_linear_dependents(self)
    733     var_str = ", ".join(variables_properties)
    734     msg = (
    735         "You specified more than one variable within a set of "
    736         "linearly dependent variables.\n"
    737         f"  Variables:  {var_str}"
    738     )
--> 739     raise hlp.TESPyNetworkError(msg)
    740 elif number_specifications == 1:
    741     reference_data = self._variable_lookup[reference]

TESPyNetworkError: You specified more than one variable within a set of linearly dependent variables.
  Variables:  e1 (E), e2 (E)

We can see the same problem if we were to specify compressor pressure ratio: The compressor inlet pressure is determined from the compressor inlet state, the condenser outlet pressure is determined from the condenser outlet state and the condenser pressure drop is specified. By that also the compressor outlet pressure is known and you cannot specify the outlet pressure.

e2.set_attr(E=None)
compressor.set_attr(pr=4)
nw.solve("design", init_only=True)
---------------------------------------------------------------------------
TESPyNetworkError                         Traceback (most recent call last)
Cell In[27], line 3
      1 e2.set_attr(E=None)
      2 compressor.set_attr(pr=4)
----> 3 nw.solve("design", init_only=True)

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2596, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, robust_relax, skip_postprocess, oscillation_damping, block_solve, pause_on_block_failure, line_search)
   2491 def solve(self, mode, init_path=None, design_path=None,
   2492           max_iter=50, min_iter=2, init_only=False, init_previous=True,
   2493           use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False,
   2494           oscillation_damping=False, block_solve=True,
   2495           pause_on_block_failure=False, line_search="stagnation"):
   2496     r"""
   2497     Solve the network.
   2498 
   (...)   2594     documentation at tespy.readthedocs.io in the section "TESPy modules".
   2595     """
-> 2596     self.presolve(
   2597         mode, init_path=init_path, design_path=design_path,
   2598         init_previous=init_previous, check=not init_only
   2599     )
   2601     if init_only:
   2602         return

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2690, in Network.presolve(self, mode, init_path, design_path, init_previous, check)
   2683 msg = (
   2684     "Network information:\n"
   2685     f" - Number of components: {len(self.comps)}\n"
   2686     f" - Number of connections: {len(self.conns)}\n"
   2687 )
   2688 logger.debug(msg)
-> 2690 self._prepare_problem()
   2691 self._presolve_pending = True
   2693 if not check:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1050, in Network._prepare_problem(self)
   1046 # this method will distribute units and set SI values from given values
   1047 # and units
   1048 self._transform_user_input_to_SI()
-> 1050 self._problem.build()
   1052 # generic fluid property initialisation
   1053 self._set_starting_values()

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:199, in Problem.build(self)
    192 msg = (
    193     f"Original problem: {self.num_original_variables} variables and "
    194     f"{self.num_original_equations} equations, of which {num_affine} "
    195     "equations were consumed by the affine variable elimination."
    196 )
    197 logger.debug(msg)
--> 199 self._presolve()
    201 # counted only now: during the structure matrix assembly the
    202 # specification and variable flags of the containers are transient,
    203 # e.g. propagated fluid compositions read as set while their
    204 # variable fractions are only marked during the presolving
    205 self.num_specified_variables = 0

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:546, in Problem._presolve(self)
    537     for determination in c._presolve_determinations:
    538         self._presolve_log.append({
    539             "round": rounds,
    540             "kind": "combination",
   (...)    544             "requires": determination["requires"],
    545         })
--> 546 self._presolve_linear_dependents()
    548 newly_known = []
    549 for linear_dependents in self._variable_dependencies:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:739, in Problem._presolve_linear_dependents(self)
    733     var_str = ", ".join(variables_properties)
    734     msg = (
    735         "You specified more than one variable within a set of "
    736         "linearly dependent variables.\n"
    737         f"  Variables:  {var_str}"
    738     )
--> 739     raise hlp.TESPyNetworkError(msg)
    740 elif number_specifications == 1:
    741     reference_data = self._variable_lookup[reference]

TESPyNetworkError: You specified more than one variable within a set of linearly dependent variables.
  Variables:  c2 (p), c3 (p), c1 (p), c0 (p), c4 (p)

You can also think of creating a circular dependency. For example, if you specify a relationship of mass flow in front and behind the cycle closer (or if you were to remove the cycle closer). Then the mass flow would form a circular dependency. As output of the error message you get the variables which are part of the circular dependency and the equations responsible for that.

compressor.set_attr(pr=None)


from tespy.connections import Ref

c1.set_attr(m=Ref(c0, 1, 0))
nw.solve("design", init_only=True)
---------------------------------------------------------------------------
TESPyNetworkError                         Traceback (most recent call last)
Cell In[28], line 7
      3 
      4 from tespy.connections import Ref
      5 
      6 c1.set_attr(m=Ref(c0, 1, 0))
----> 7 nw.solve("design", init_only=True)

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2596, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, robust_relax, skip_postprocess, oscillation_damping, block_solve, pause_on_block_failure, line_search)
   2491 def solve(self, mode, init_path=None, design_path=None,
   2492           max_iter=50, min_iter=2, init_only=False, init_previous=True,
   2493           use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False,
   2494           oscillation_damping=False, block_solve=True,
   2495           pause_on_block_failure=False, line_search="stagnation"):
   2496     r"""
   2497     Solve the network.
   2498 
   (...)   2594     documentation at tespy.readthedocs.io in the section "TESPy modules".
   2595     """
-> 2596     self.presolve(
   2597         mode, init_path=init_path, design_path=design_path,
   2598         init_previous=init_previous, check=not init_only
   2599     )
   2601     if init_only:
   2602         return

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2690, in Network.presolve(self, mode, init_path, design_path, init_previous, check)
   2683 msg = (
   2684     "Network information:\n"
   2685     f" - Number of components: {len(self.comps)}\n"
   2686     f" - Number of connections: {len(self.conns)}\n"
   2687 )
   2688 logger.debug(msg)
-> 2690 self._prepare_problem()
   2691 self._presolve_pending = True
   2693 if not check:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1050, in Network._prepare_problem(self)
   1046 # this method will distribute units and set SI values from given values
   1047 # and units
   1048 self._transform_user_input_to_SI()
-> 1050 self._problem.build()
   1052 # generic fluid property initialisation
   1053 self._set_starting_values()

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:187, in Problem.build(self)
    178 def build(self):
    179     """Construct the problem from the prepared network.
    180 
    181     - Assemble the structure matrix and the structure graph and reduce the
   (...)    185       incidence.
    186     """
--> 187     self._create_structure_matrix()
    189     self.num_original_variables = len(self._variable_lookup)
    190     self.num_original_equations = len(self._equation_set_lookup)

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:274, in Problem._create_structure_matrix(self)
    266 sum_eq = self._preprocess_network_parts(self.network.user_defined_eq.values(), sum_eq)
    268 self.structure_graph = StructureGraph(
    269     self._structure_matrix, self._rhs,
    270     self._variable_lookup, self._equation_set_lookup,
    271     self._equation_set_origin
    272 )
    273 _linear_dependencies = (
--> 274     self.structure_graph.find_linear_dependent_variables()
    275 )
    276 _linear_dependent_variables = [
    277     var for linear_dependents in _linear_dependencies
    278     for var in linear_dependents["variables"]
    279 ]
    280 # variables without any affine partner become singleton groups
    281 # referencing themselves: every variable owns a reference
    282 # container this way and no consumer has to distinguish grouped
    283 # from ungrouped variables

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/structure.py:198, in StructureGraph.find_linear_dependent_variables(self)
    196 cycle = self.find_cycle()
    197 if cycle is not None:
--> 198     self.raise_error_if_cycle(cycle)
    200 adjacency_list = self.affine_adjacency
    201 eq_idx = self.edge_eq_idx

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/structure.py:180, in StructureGraph.raise_error_if_cycle(self, cycle)
    174 eq_str = ", ".join(f"{lbl}.{eq}" for lbl, eq in equations)
    175 msg = (
    176     "A circular dependency has been detected. This overdetermines the problem.\n"
    177     f"  Variables:  {var_str}\n"
    178     f"  Equations:  {eq_str}"
    179 )
--> 180 raise hlp.TESPyNetworkError(msg)

TESPyNetworkError: A circular dependency has been detected. This overdetermines the problem.
  Variables:  c0 (m), c1 (m), c2 (m), c3 (m), c4 (m)
  Equations:  c1.m_ref, compressor.mass_flow_constraints, condenser.mass_flow_constraints, evaporator.mass_flow_constraints, valve.mass_flow_constraints

A last error that might occur is specification of properties that determine the same variable, e.g. the c2 pressure as the evaporation pressure is already determined from the saturation temperature and superheating.

c1.set_attr(m=None)
c2.set_attr(p=10)  # p has already been set!
nw.solve("design")
---------------------------------------------------------------------------
TESPyNetworkError                         Traceback (most recent call last)
Cell In[29], line 3
      1 c1.set_attr(m=None)
      2 c2.set_attr(p=10)  # p has already been set!
----> 3 nw.solve("design")

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2596, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, robust_relax, skip_postprocess, oscillation_damping, block_solve, pause_on_block_failure, line_search)
   2491 def solve(self, mode, init_path=None, design_path=None,
   2492           max_iter=50, min_iter=2, init_only=False, init_previous=True,
   2493           use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False,
   2494           oscillation_damping=False, block_solve=True,
   2495           pause_on_block_failure=False, line_search="stagnation"):
   2496     r"""
   2497     Solve the network.
   2498 
   (...)   2594     documentation at tespy.readthedocs.io in the section "TESPy modules".
   2595     """
-> 2596     self.presolve(
   2597         mode, init_path=init_path, design_path=design_path,
   2598         init_previous=init_previous, check=not init_only
   2599     )
   2601     if init_only:
   2602         return

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:2690, in Network.presolve(self, mode, init_path, design_path, init_previous, check)
   2683 msg = (
   2684     "Network information:\n"
   2685     f" - Number of components: {len(self.comps)}\n"
   2686     f" - Number of connections: {len(self.conns)}\n"
   2687 )
   2688 logger.debug(msg)
-> 2690 self._prepare_problem()
   2691 self._presolve_pending = True
   2693 if not check:

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/networks/network.py:1050, in Network._prepare_problem(self)
   1046 # this method will distribute units and set SI values from given values
   1047 # and units
   1048 self._transform_user_input_to_SI()
-> 1050 self._problem.build()
   1052 # generic fluid property initialisation
   1053 self._set_starting_values()

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:199, in Problem.build(self)
    192 msg = (
    193     f"Original problem: {self.num_original_variables} variables and "
    194     f"{self.num_original_equations} equations, of which {num_affine} "
    195     "equations were consumed by the affine variable elimination."
    196 )
    197 logger.debug(msg)
--> 199 self._presolve()
    201 # counted only now: during the structure matrix assembly the
    202 # specification and variable flags of the containers are transient,
    203 # e.g. propagated fluid compositions read as set while their
    204 # variable fractions are only marked during the presolving
    205 self.num_specified_variables = 0

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/solver/problem.py:536, in Problem._presolve(self)
    532 for c in to_check:
    533     # cleared here, not in _presolve: custom connection classes are
    534     # not required to know about the log
    535     c._presolve_determinations = []
--> 536     self._presolved_equations += c._presolve()
    537     for determination in c._presolve_determinations:
    538         self._presolve_log.append({
    539             "round": rounds,
    540             "kind": "combination",
   (...)    544             "requires": determination["requires"],
    545         })

File ~/checkouts/readthedocs.org/user_builds/tespy/checkouts/stable/src/tespy/connections/connection.py:1700, in Connection._presolve(self)
   1693 if num_specs > 2:
   1694     msg = (
   1695         "You have specified more than 2 parameters for the connection "
   1696         f"{self.label} with a known fluid composition: "
   1697         f"{', '.join(specifications)}. This overdetermines the state "
   1698         "of the fluid."
   1699     )
-> 1700     raise TESPyNetworkError(msg)
   1702 presolved_equations = []
   1704 if self.p.is_set:

TESPyNetworkError: You have specified more than 2 parameters for the connection c2 with a known fluid composition: p, T_dew, td_dew. This overdetermines the state of the fluid.
c2.set_attr(p=None)

Inspect reasons for linear dependency

You can also inspect the network after solve crashing. For this, we will construct a case where, we get this exact issue:

  • We fix heat output of condenser (having fixed motor electrical power already)

  • no specification of evaporator delta p

The block decomposition is able determine, that the problem is structurally singular.

condenser.set_attr(Q=-350)
evaporator.set_attr(dp=None)
nw.solve("design")
The problem is structurally singular, block-wise solving is not possible.
Structural analysis - the problem contains an under-determined part (1 variable constrained by 0 equations) and an over-determined part (3 equations competing for 2 variables).
Use nw.print_structural_analysis() for the affected equations and variables. If the structural defect stems from an incomplete dependency declaration of a custom equation, the simultaneous solution can still be attempted with nw.solve(mode, block_solve=False).

The solver reports that the problem is structurally singular although the parameter count matches. One part of the model is over-determined while another part is under-determined at the same time. The structural analysis prints both:

nw.print_structural_analysis()
Under-determined part - the following variables cannot be determined by the involved equations:
  Variables: p2
  Involved equations: 
Over-determined part - the following equations compete for the involved variables:
  Equations: compressor.energy_connector_balance, compressor.eta_s, condenser.Q
  Involved variables: h0, m1

We can see the same looking at the actual variables and the equations associated with them separately:

nw.print_variables()
Variables after presolving (3 total):
  #  Property    Represents
---  ----------  --------------------------------------
  0  h           c3 (h)
  1  m           c2 (m), c3 (m), c1 (m), c4 (m), c0 (m)
  2  p           c0 (p), c1 (p)

The under-determined variable p2 represents the pressures around the evaporator: with its pressure drop specification removed, no equation determines that pressure level anymore, while the condenser heat transfer competes with the compressor equations for enthalpy and mass flow.

nw.print_equations_with_dependents()
Equations with dependent variables (3 total):
  Eq#  Object      Equation                  Dependent variables
-----  ----------  ------------------------  ---------------------
    0  compressor  energy_connector_balance  h0, m1
    1  compressor  eta_s                     h0
    2  condenser   Q                         h0, m1
nw.print_incidence_matrix(block_order=True)
Incidence matrix:
  Block                                       p2    h0    m1
-------  -----------------------------------  ----  ----  ----
      1  compressor.energy_connector_balance  -     X     X
         compressor.eta_s                     -     X     -
         condenser.Q                          -     X     X
nw.print_blocks()
Block lower triangular decomposition (2 blocks):
  #  Kind             Needs    Equations                                                           Variables
---  ---------------  -------  ------------------------------------------------------------------  -----------
  0  underdetermined                                                                               p2
  1  overdetermined            compressor.energy_connector_balance, compressor.eta_s, condenser.Q  h0, m1

A specification can also be numerically impossible while being structurally perfectly sound. In that case the structural analysis cannot detect the issue. Just a normal HeatExchanger is sufficient to show this:

from tespy.components import Source, Sink, HeatExchanger


nw = Network()
nw.units.set_defaults(
    temperature="°C",
    pressure="bar",
    pressure_difference="bar"
)

so1 = Source("source 1")
so2 = Source("source 2")

si1 = Sink("sink 1")
si2 = Sink("sink 2")

heatex = HeatExchanger("heatexchanger")

c1 = Connection(so1, "out1", heatex, "in1", label="c1")
c2 = Connection(heatex, "out1", si1, "in1", label="c2")
d1 = Connection(so2, "out1", heatex, "in2", label="d1")
d2 = Connection(heatex, "out2", si2, "in1", label="d2")

nw.add_conns(c1, c2, d1, d2)

Now we could make a specification that is impossible but hard to catch as being a setup problem: We set a minimum terminal temperature difference of 25 K but at the same time fix the temperature at hot side outlet and cold side inlet (leading to a temperature difference of 20 K).

c1.set_attr(fluid={"air": 1}, T=200, p=1, m=5)
c2.set_attr(T=110)
d1.set_attr(fluid={"water": 1}, T=90, p=1)
heatex.set_attr(dp1=0, dp2=0, ttd_min=25)
nw.solve("design")
Block 0 did not converge, solving remaining 2 blocks simultaneously.
  Cause: no acceptance within the iteration budget of 50 iterations, the last scaled residual is 5.00e+00
  Equations: heatexchanger.ttd_min
  Variables: h0
 block   0 | scalar          | iterations:  92 | residual: 5.00e+00 | heatexchanger.ttd_min

 iter  | residual   | progress   | massflow   | pressure   | enthalpy   | fluid      | energy     | component  
-------+------------+------------+------------+------------+------------+------------+------------+------------
 1     | 8.37e-02   | 15 %       | 1.10e-01   | 0.00e+00   | 1.97e+04   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 2     | 5.00e+00   | 0 %        | 8.91e-04   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 3     | 5.00e+00   | 0 %        | 3.83e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 4     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 5     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 6     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 7     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 8     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 9     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 10    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 11    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 12    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 13    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 14    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 15    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 16    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 17    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 18    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 19    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 20    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 21    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 22    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 23    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 24    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 25    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 26    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 27    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 28    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 29    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 30    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 31    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 32    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 33    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 34    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 35    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 36    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 37    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 38    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 39    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 40    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 41    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 42    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 43    | 8.37e-02   | 15 %       | 1.10e-01   | 0.00e+00   | 1.97e+04   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 44    | 5.00e+00   | 0 %        | 8.91e-04   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 45    | 5.00e+00   | 0 %        | 3.83e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 46    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 47    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 48    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 49    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 50    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 51    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 52    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 53    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 54    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 55    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 56    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 57    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 58    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 59    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 60    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 61    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 62    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 63    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 64    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 65    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 66    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 67    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 68    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 69    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 70    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 71    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 72    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 73    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 74    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 75    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 76    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 77    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 78    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 79    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 80    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 81    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 82    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 83    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 84    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 85    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 86    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 87    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 88    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 89    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 90    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 91    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 92    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 block   0 | remainder       | iterations:  92 | residual: 5.00e+00 | 2 equations
The remaining system did not converge either, restarting with the simultaneous solution of the full system from its initial state.
 iter  | residual   | progress   | massflow   | pressure   | enthalpy   | fluid      | energy     | component  
-------+------------+------------+------------+------------+------------+------------+------------+------------
 1     | 8.37e-02   | 15 %       | 1.10e-01   | 0.00e+00   | 1.97e+04   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 2     | 5.00e+00   | 0 %        | 8.91e-04   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 3     | 5.00e+00   | 0 %        | 3.83e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 4     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 5     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 6     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 7     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 8     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 9     | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 10    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 11    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 12    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 13    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 14    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 15    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 16    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 17    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 18    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 19    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 20    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 21    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 22    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 23    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 24    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 25    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 26    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 27    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 28    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 29    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 30    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 31    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 32    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 33    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 34    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 35    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 36    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 37    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 38    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 39    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 40    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 41    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 42    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 43    | 8.37e-02   | 15 %       | 1.10e-01   | 0.00e+00   | 1.97e+04   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 44    | 5.00e+00   | 0 %        | 8.91e-04   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 45    | 5.00e+00   | 0 %        | 3.83e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 46    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 47    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 48    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 49    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 50    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 51    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 52    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 53    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 54    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 55    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 56    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 57    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 58    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 59    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 60    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 61    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 62    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 63    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 64    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 65    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 66    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
The calculation did not converge, the last scaled residual is 5.00e+00 (heatexchanger: ttd_min).
Possible reasons include:
 - fluid properties moving outside the valid range of the property database (consider adjusting p_range or h_range),
 - an impossible constraint that can never be satisfied 
 - bad starting values causing the Newton solver to diverge.
Use nw.print_residuals() to identify which equations have the largest residuals.
 67    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 68    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 69    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 70    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 71    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 72    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 73    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 74    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 75    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 76    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 77    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 78    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 79    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 80    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 81    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 82    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 83    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 84    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 85    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 86    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 87    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 88    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 89    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 90    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 91    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 92    | 5.00e+00   | 0 %        | 3.85e-07   | 0.00e+00   | 5.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
Total iterations: 92, Calculation time: 2.34 s, Iterations per second: 39.28

Such an impossible specification leads to non-convergence. The block-wise solution process localizes the problem: the first failing block names the ttd_min equation, and the final message quotes the equation with the largest scaled residual. The residuals show that the energy balance is satisfied while ttd_min cannot fall below a residual of 5, which is exactly the 5 K by which the specification is infeasible:

nw.print_residuals()
Residuals per equation (2 total, sorted by scaled magnitude):
  Eq#  Object         Equation                       Scaled    Residual
-----  -------------  --------------------------  ---------  ----------
    1  heatexchanger  ttd_min                     5.000e+00   5.000e+00
    0  heatexchanger  energy_balance_constraints  6.488e-13  -1.925e-06

Next steps

The solver section documents the full solution process and all inspection methods shown here. For debugging the solution process itself in the block decomposition, pausing at a failed block and correcting starting values interactively, see the advanced debugging tutorial.