tespy.solver package

tespy.solver.decomposition module

Module for the structural decomposition of the equation system.

This file is part of project TESPy (github.com/oemof/tespy). It’s copyrighted by the contributors recorded in the version control history of the file, available from its original location tespy/solver/decomposition.py

SPDX-License-Identifier: MIT

class tespy.solver.decomposition.Block(id: int, kind: str, equations: list, variables: list, equation_labels: list = <factory>, variable_labels: list = <factory>, status: int = None, residual_history: list = <factory>, failure_cause: str = None, jacobian: ndarray = None, residual: ndarray = None, variable_values: list = None, connection_states: list = None)[source]

Bases: object

A block of the block lower triangular form of the equation system.

  • "scalar": a single equation in a single variable

  • "square": a group of mutually coupled equations and variables

  • "underdetermined": variables not covered by a maximum matching of the incidence together with the equations connected to them

  • "overdetermined": equations not covered by a maximum matching of the incidence together with the variables involved in them

connection_states: list = None
equation_labels: list
equations: list
failure_cause: str = None
id: int
jacobian: ndarray = None
kind: str
residual: ndarray = None
residual_history: list
status: int = None
variable_labels: list
variable_values: list = None
variables: list
class tespy.solver.decomposition.Decomposition(blocks: list, precedence: dict)[source]

Bases: object

Ordered block structure of the equation system.

The square and scalar blocks are ordered such that every block only depends on variables of preceding blocks. precedence maps a block id to the ids of the blocks it depends on.

blocks: list
property defective_blocks
precedence: dict
tespy.solver.decomposition.dulmage_mendelsohn(incidence, num_variables, coupled_variables=None)[source]

Compute the Dulmage-Mendelsohn decomposition of an incidence.

For the application of the decomposition to the analysis of equation oriented process models see [2].

Parameters:
  • incidence (dict) – Lookup of equation number to the list of variable numbers the equation depends on.

  • num_variables (int) – Total number of variables.

  • coupled_variables (list, optional) – Groups of variable numbers that must not be separated into different blocks, e.g. the mass fractions of one fluid vector, which are coupled through their normalization outside of the equation system.

Returns:

Decomposition – The over- and underdetermined parts (if any) and the square part split into its strongly connected blocks in precedence order.

tespy.solver.problem module

Module for the solver problem representation.

This file is part of project TESPy (github.com/oemof/tespy). It’s copyrighted by the contributors recorded in the version control history of the file, available from its original location tespy/solver/problem.py

SPDX-License-Identifier: MIT

class tespy.solver.problem.Problem(network)[source]

Bases: object

Solver representation of a prepared network.

The problem holds the variable space, the equation lookups and the state of the newton algorithm (residual vector, jacobian and increment). It is created by the network in the preprocessing stage of every solve call and remains accessible through Network.problem afterwards for inspection.

build()[source]

Construct the problem from the prepared network.

  • Assemble the structure matrix and the structure graph and reduce the variable space by the affine linear dependencies.

  • Presolve fluid vectors and fluid properties iteratively.

  • Assign the solver variable space and collect the equations and their incidence.

check_determination()[source]

Check, if the number of supplied parameters is sufficient.

decompose()[source]

Get the Dulmage-Mendelsohn decomposition of the solver incidence.

The result is cached for the lifetime of the problem instance.

Returns:

tespy.solver.decomposition.Decomposition – Ordered block structure of the equation system.

static format_eq_name(eq_name)[source]
format_var_label(v_idx)[source]
get_block_jacobian(block) dict[source]

Get the linear system of a failed block at its state of failure.

The jacobian and residual restricted to the block’s equations and variables are recorded as evaluated in the failing iteration of the last solution attempt (surrogate placeholders for all-zero rows appear as their fill-in value of 1). They are only available for blocks whose solution failed. The result also holds the expected entries declared by the incidence matrix, so evaluated entries can be compared against the declared dependencies, e.g. to find derivatives that are zero although the equation declares the dependency.

get_block_states(block, at='current') list[source]

Get the states of the connections a block touches.

The properties of every connection involved in the block’s equations and variables. What is reported comes from the connection classes, e.g. mass flow, pressure, enthalpy, temperature and phase for fluid connections. With at="current" the states are evaluated from the current variable values - while the solution process is paused at the block this is its entry state, including any modification made in between. at="failure" returns the states as recorded in the failing iteration of the block’s last solution attempt, only available for blocks whose solution failed.

get_equations() dict[source]

Get the lookup of solver equation numbers to labels.

get_equations_with_dependents() dict[source]

Get the equations with the variables they depend on.

get_incidence() dict[source]

Get the lookup of solver equation numbers to the variable numbers each equation depends on.

get_linear_dependent_variables() list[source]

Get the sets of linearly dependent variables by label.

get_linear_dependents_by_object(obj, prop) list[source]

Get the linearly dependent variables of a variable by label.

Raises a KeyError in case the object does not hold a variable of the given name.

get_presolved_equations() list[source]

Get the equations consumed by presolving by label.

get_presolved_variables() list[source]

Get the variables solved by presolving by label.

get_sorted_residual_index() list[int][source]

Get the equation indices sorted by scaled residual.

Returns:

list[int] – List of equation numbers, the index values.

get_structural_analysis()[source]

Get the over- and under-determined parts of the problem.

Returns:

list – One dictionary per defective part of the maximum matching of the incidence with its kind ("overdetermined" or "underdetermined"), the equations as tuples of object label and equation name and the short variable labels. An empty list means the problem is structurally sound.

get_variable_values(block=None) dict[source]

Get the variables with the current values of the original variables they represent, optionally restricted to the variables of the block with the given id.

get_variables() dict[source]

Get the variables with the original variables they represent.

get_variables_before_presolve() list[source]

Get the original variables by label.

no_progress_message()[source]
property paused

Whether the solution process is paused at a failed block.

presolve_flow_variables(seeded)[source]

Solve the flow variables on the completed property field.

With pressures and enthalpies frozen at their starting values, the equations determining the flows - mass balances, energy balances, heat and power specifications, energy connector and bus balances - are linear in the mass and energy flow variables. A single newton step restricted to those variables therefore solves them exactly with respect to the guessed property field, replacing the random mass flow starting values by consistent levels and branch ratios. Seeded values stay untouched. Returns the number of updated variables.

propagate_starting_values(seeded, props)[source]

Propagate starting values through approximate affine relations.

The components provide rough affine guesses between their inlet and outlet properties, mapped into the space of the reference variables through the exact affine relations of the variable groups. The known values - specified, presolved or one of the passed source containers - anchor a least squares problem over every connected component of the guess graph, minimizing the sum of the squared edge residuals. Along a chain this reproduces the composed guesses, between several known values it interpolates, and around a cycle the closure residual of the guesses distributes over the edges instead of accumulating at an arbitrary meeting point. Returns the set of reference containers that received a value; unreached variables are left to the local component anchors and generic values.

scaled_residual(rows=None)[source]

Residuals divided by their per equation scales.

set_variable_value(obj, prop, value)[source]

Set the SI value of a variable through any of the linearly dependent variables it represents.

Raises a KeyError in case the object does not hold a variable of the given name and a TESPyNetworkError in case the property is not part of the variable space.

solve_loop(max_iter, min_iter, use_cuda, robust_relax, oscillation_damping, iterinfo, print_results=True, block_solve=False, pause_on_block_failure=None)[source]

Loop of the newton algorithm.

starting_temperature_field()[source]

Reconcile a temperature per connection for the starting values.

The components provide approximate temperature relations between their ports, including the terminal temperature differences of heat exchangers - so known temperature levels reach coupled circuits the enthalpy relations cannot connect. The known temperatures - specifications, values derived from saturation specifications and converted fixed states - anchor a least squares problem per connected component of that graph; the temperature hints of the component state expectations act as soft priors. Returns a dict mapping connections to reconciled temperatures, including the known ones.

structure_equations() list[source]

Get the serializable description of the structural equations.

structure_variables() list[source]

Get the serializable description of the structural variables.

unload_variables()[source]

Detach all containers from their reference containers.

Detaching writes the final value (through factor and offset) back into every member container, so the results remain after the shared references are released.

tespy.solver.strategies module

Module for the block solve strategies.

This file is part of project TESPy (github.com/oemof/tespy). It’s copyrighted by the contributors recorded in the version control history of the file, available from its original location tespy/solver/strategies.py

SPDX-License-Identifier: MIT

class tespy.solver.strategies.BlockDriver(problem, pause_on_block_failure=False)[source]

Bases: object

Orchestrate the block wise solution of a problem.

The blocks of the decomposition are solved in precedence order and the variables of every solved block are frozen for the subsequent ones. Failures escalate in stages: a failed block restores its variables and the remaining blocks are solved as one coupled system; if that fails as well, the full system is solved simultaneously from its initial state, reproducing the plain simultaneous solution exactly. After a successful block phase the full residual vector is verified and a simultaneous polish runs in case couplings outside of the declared incidence left a remaining residual.

With pause_on_block_failure a failed block pauses the solution process instead of escalating: the solved blocks stay frozen, the failed block’s variables can be inspected and modified and resume retries the block and continues from there.

property paused_block
resume(iterinfo, print_results=True)[source]

Retry the paused block and continue the block-wise solution.

solve(iterinfo, print_results=True)[source]
class tespy.solver.strategies.NewtonStrategy[source]

Bases: object

Solve a single block with the newton algorithm restricted to the block.

The residuals and derivatives of all objects owning the block’s equations are evaluated, the linear system is restricted to the block’s equation rows and variable columns and only the block’s variables are updated. Variables of preceding blocks act as constants.

If the block does not converge or an equation evaluation raises an error, the block’s variables are restored to their values at entry, so a failed attempt does not degrade the starting point of any subsequent solution attempt.

solve(problem, block)[source]

Solve the block and return its status (0, 2 or 3).

class tespy.solver.strategies.ScalarBracketingStrategy[source]

Bases: NewtonStrategy

Solve a scalar block with newton steps and bracketing as fallback.

When the block’s residual changes sign between two iterations, the newton step overshot the root - but the two iterates then enclose it. The increment is replaced by a refinement of the root within that known bracket (Brent’s method), which restores monotone convergence for non-smooth residuals. Only if the refinement fails, e.g. because heuristics modified the state between the iterations, a bracketing search on the equation is performed instead.

tespy.solver.strategies.bracketed_step(problem, row, col, bracket_value)[source]

Refine the root of a scalar equation within a known bracket.

The bracket value is the variable value of a preceding newton iteration whose residual had the opposite sign of the current one, so the root is enclosed between the two values and can be refined directly without searching for a bracket first.

Returns the step to add to the variable, or None in case the refinement fails, e.g. because the residual function changed between the iterations through other variables or heuristics.

tespy.solver.strategies.scalar_residual_closure(problem, row, col)[source]

Build an evaluator of equation row over variable col.

The evaluator computes the equation’s residual at a given value of the variable and restores the current value afterwards. Works for both scalar variables (m, h, p, E) and vector variables (fluid mass fractions), where the largest other variable fluid is adjusted in the opposite direction to maintain the sum of 1.

Returns the evaluator and the current variable value, or None in case the equation cannot be evaluated standalone.

tespy.solver.strategies.search_reducing_step(problem, row, col)[source]

Find the increment for variable col that reduces equation row’s residual.

Searches both +/- directions with geometrically growing step sizes (x2 per iteration, up to 20 iterations each). Prefers the side that produces a sign change in the residual, which guarantees a root in the bracket [x0, x0±d] by the IVT, and refines its location with Brent’s method. If both sides bracket a root, the tighter one (smaller abs(residual) at the probe point) is used. Falls back to a secant step if brentq raises, and to the lower-magnitude heuristic when neither side yields a sign change.

Returns the step to add to the variable, or None if neither direction improves the residual.

tespy.solver.structure module

Module for the structure graph of the equation system.

This file is part of project TESPy (github.com/oemof/tespy). It’s copyrighted by the contributors recorded in the version control history of the file, available from its original location tespy/solver/structure.py

SPDX-License-Identifier: MIT

class tespy.solver.structure.StructureGraph(structure_matrix, rhs, variable_lookup, equation_set_lookup, equation_set_origin)[source]

Bases: object

Persistent graph representation of the equation system structure.

Built from the structure matrix assembled during preprocessing, the graph holds three classes of structural information:

  • affine_adjacency: variable pairs linked by a structure matrix row with exactly two entries, forming the affine elimination graph used by the presolver

  • linear_rows: structure matrix rows with more or fewer than two entries (e.g. mass balances of merges and splitters), which cannot be used for pairwise elimination

  • nonlinear_incidence: the incidence of the iterated solver equations, attached after the solver preparation via attach_solver_incidence

attach_solver_incidence(incidence_matrix, variables_dict)[source]

Attach the incidence of the iterated solver equations.

The solver incidence maps equation numbers to solver variable columns. It is translated back to the structural variable space here, so all three edge classes of the graph refer to the same variable numbering.

find_cycle()[source]

Find a cycle in the affine elimination graph.

The edges are added to a growing forest one by one. The first edge closing a cycle connects two variables that are already linked through the forest, the cycle is that path plus the closing edge.

Returns:

set | None – Set of the variable numbers forming a cycle or None in case the graph is acyclic.

find_linear_dependent_variables()[source]

Find the sets of affinely linked variables.

Returns:

list – List of dictionaries per set of linked variables with the variables, the reference variable, the factors and offsets relative to the reference and the structural equations consumed by the elimination.

raise_error_if_cycle(cycle)[source]
structural_key()[source]

Get a hashable summary of the problem structure.

The key is identical for two solves with unchanged topology and specification locations and changes when a specification moves, appears or vanishes. Specified values do not enter the key, so it can be used to cache structure-derived results (e.g. a decomposition) across parameter sweeps.