Condition

Tag: General

This block creates a conditional node in the workflow, which can be used, for example:

  • As a gate that discards incoming data or allows it to pass.
  • As a switch that redirects input data to one of the two alternative output branches.

Introduction

Block behavior is based on a user-defined condition 1 which can contain any of the block variables 2. When the block receives values of variables, it starts up and checks the condition. If it is met, the data is passed further. If the condition is not met, then, based on the output setting 3, the block either:

  • discards the input data, or
  • sends the data to alternative outputs.
../_images/page_blocks_Condition_configure.png

Variables

Configuring a Condition block requires adding variables (no variables are defined by default). These variables are then used in the condition.

Adding a variable automatically creates ports — one input and one or two outputs. For example, when you add a variable named “myvar”, the following ports are created:

  • myvar input,
  • myvar output, and
  • else_myvar output (optional; see section Output for details).

All ports always have the same type. By default all data types are allowed. You can change the type when adding a variable, if you want to limit the allowed types.

The block does not start until it receives values of all variables, so all input ports you create by adding variables are required ports.

Conditions

Any block variable can be used in the condition. When the block starts, it substitutes the received values of variables to the conditional expression and checks if the condition is met.

Conditions may include various comparisons, logical and arithmetic operators. Common ones are:

  • Basic arithmetic operators (+, -, *, /).
  • Modulus (%), exponent (**), floor division (//).
  • Equality (==), inequality (!=), comparisons (<, >, <=, >=). Note that = is an assignment, not equality testing!
  • Logical and, or and not.

Example conditions:

  • Check if variable equals some value: ans == 42.
  • Check the value of a string variable: status == "Success".
  • Check the value of a vector or matrix component: vec[0] <= 0; m[1][2] != 1.
  • Check the number of matrix rows: m.shape[0] >= 10.
  • Same for columns: m.shape[1] == 3.
  • Complex condition: status == "Success" or (res[1] > 0 and res[0] + res[2] < 5).

Note

For advanced users: Python syntax is allowed in conditions.

Output

There are two alternative output settings for the block: discard data if the condition is not met (default), or output it to alternative ports (the “else” branch).

For example, consider the following configuration:

../_images/page_blocks_Condition_output_default.png
  • Two integer variables have been added.
  • Two input ports have been automatically created: x and y (you can see them in block properties).
  • Two output ports: x and y.

The block compares values it receives to x and y. If the condition is met, the same values are output to the x and y ports. If the condition is not met, there is no output — values are discarded.

Compare with the following configuration:

../_images/page_blocks_Condition_output_else.png
  • Two integer variables.
  • Two input ports: x and y.
  • Since alternative output option is selected, this configuration creates four output ports: x, y, else_x, and else_y.

If the condition is met, block behavior is the same as in previous configuration: received values are output to the x and y ports. However if the condition is not met, the values are now not discarded; instead, they are output to the else_x and else_y ports. This is an example of a simple switch configuration.

Note that you can add some other variable to use it exclusively as a condition. For example:

../_images/page_blocks_Condition_output_switch.png

If the status received is "Success", active outputs are status, x and y. In any other case, active outputs are else_status, else_x and else_y. The idea is to use the status input port as a switch condition only: related outputs, status and else_status would not be connected to anything.

Note

Since names of “else” ports are generated automatically, it is possible to create a naming conflict — for example, by adding variables “x” and “else_x”. This results in a validation error, and a workflow with a Condition block configured like this does not run (pSeven will inform you about this).

Warning

If you select the redirect option, connect “else” ports to other block, and then change the output option to default, all “else” ports are automatically removed, so the links you have created are deleted (however this does not happen until you click b_ok or b_apply).

Examples

This section provides a few examples of how the Condition block can be used in real workflows.

Status Checker

The Optimizer block (Optimize) is an example of a block that has a status output port. The Condition block (CheckStatus) is used to send optimization results to some post-processing block (ProcessResult) if optimization succeeded, or make the workflow output a predefined constant if optimization failed.

../_images/page_blocks_Condition_status.png

In this workflow, CheckStatus has “status” variable (StringScalar) and a number of variables for optimization results. In case of success, the Optimize block outputs string "Success" to Optimize.status. This port is connected to CheckStatus.success. Condition is: status == "Success".

The success branch is default, CheckStatus simply sends all results to ProcessResult. In case of failure, the optimization result is empty, so it does not need to be passed further: “else” ports are not connected, except CheckStatus.else_status which is linked to ReturnConstant.do. Thus the failure status, processed by CheckStatus, becomes a signal for the ReturnConstant block to start up and output the constant defined by its configuration.

Configuration Switch

This is an example of a workflow with a simple switch added to its run configuration.

../_images/page_blocks_Condition_fork.png

The Switch block defines a BoolScalar variable named “use_accurate”. The “else” branch is on, and condition is: use_accurate (meaning that it is met if the value specified in run configuration is True). The use_accurate input port is uplinked and appears on the Inputs pane in Run. The outputs use_accurate and else_use_accurate are used to send signals to workflow branches:

  • Switch.accurate is connected to AccurateSolver. This branch is active if “use_accurate” is True and starts a heavy solver block.
  • Switch.else_accurate is connected to Generate, the first block in the alternative branch. This branch is active if “use_accurate” is False. Presumably it starts another less accurate solver for quick tests.

Fallback

Fallback concept is simple: if some block fails, there may be another similar block that tries to accomplish the task. The difficult part is making the fallback block to start only if the first one fails. If you simply send input data to both blocks, they start at once, but there is no point in that.

../_images/page_blocks_Condition_mesh.png

The Condition block (CheckStatus) resolves the situation by checking the first solver status. As you can see, CheckStatus receives a copy of input data from the GetData block, but this data is not output until Solver reports its status. In case of success, CheckStatus discards the data, so AlternativeSolver receives no input and does not start.

In this example the CheckStatus block works as a simple conditional gate.

Notes

  • Python modules os, sys and numpy are available in the conditional expression.

  • If the conditional expression evaluates to a non-Boolean, then the evaluation result is converted to Boolean using the Python’s standard truth testing procedure. For example, if you set a condition like x + y where both variables are integers, it is always met unless the sum is zero (all non-zero integers are converted to True in Python).

  • Since pSeven vector and matrix types are converted to numpy.ndarray (see pSeven to Python Types Conversion), if you try to set condition like vec == [1,2,3] where vec is a RealVector, block execution will fail with a message:

    The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
    

    The solution is to use tolist(): vec.tolist() == [1,2,3].